/*!
* alphaTab v1.8.4 (, build 34)
*
* Copyright © 2026, 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
*/
(function(global, factory) {
	typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.alphaTab = {}));
})(this, function(exports) {
	Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
	//#region \0rolldown/runtime.js
	var __defProp = Object.defineProperty;
	var __exportAll = (all, no_symbols) => {
		let target = {};
		for (var name in all) __defProp(target, name, {
			get: all[name],
			enumerable: true
		});
		if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
		return target;
	};
	//#endregion
	//#region src/platform/javascript/ResizeObserverPolyfill.ts
	/**
	* A very basic polyfill of the ResizeObserver which triggers
	* a the callback on window resize for all registered targets.
	* @target web
	* @internal
	*/
	var ResizeObserverPolyfill = class {
		_callback;
		_targets = /* @__PURE__ */ new Set();
		constructor(callback) {
			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,
				contentRect: void 0,
				borderBoxSize: void 0,
				contentBoxSize: [],
				devicePixelContentBoxSize: []
			});
			this._callback(entries, this);
		}
	};
	//#endregion
	//#region src/platform/javascript/IntersectionObserverPolyfill.ts
	/**
	* A polyfill of the InsersectionObserver
	* @target web
	* @internal
	*/
	var IntersectionObserverPolyfill = class {
		_callback;
		_elements = [];
		_timer = null;
		constructor(callback) {
			this._callback = callback;
			window.addEventListener("resize", () => this._check, true);
			document.addEventListener("scroll", () => this._check, true);
		}
		_check() {
			if (!this._timer) this._timer = setTimeout(() => {
				this._doCheck();
				this._timer = null;
			}, 100);
		}
		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;
			});
		}
		_doCheck() {
			const entries = [];
			for (const element of this._elements) {
				const rect = element.getBoundingClientRect();
				if (rect.top + rect.height >= 0 && rect.top <= window.innerHeight && rect.left + rect.width >= 0 && rect.left <= window.innerWidth) entries.push({
					target: element,
					isIntersecting: true
				});
			}
			if (entries.length) this._callback(entries, this);
		}
	};
	//#endregion
	//#region src/alphaTab.polyfills.ts
	(() => {
		if (typeof Symbol.dispose === "undefined") Symbol.dispose = Symbol("Symbol.dispose");
		if (typeof window !== "undefined") {
			if (!("ResizeObserver" in globalThis)) globalThis.ResizeObserver = ResizeObserverPolyfill;
			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);
		};
	})();
	//#endregion
	//#region src/AlphaTabError.ts
	/**
	* @public
	*/
	var AlphaTabErrorType = /* @__PURE__ */ function(AlphaTabErrorType) {
		AlphaTabErrorType[AlphaTabErrorType["General"] = 0] = "General";
		AlphaTabErrorType[AlphaTabErrorType["Format"] = 1] = "Format";
		AlphaTabErrorType[AlphaTabErrorType["AlphaTex"] = 2] = "AlphaTex";
		return AlphaTabErrorType;
	}({});
	/**
	* @public
	*/
	var AlphaTabError = class extends Error {
		type;
		constructor(type, message = "", inner) {
			super(message ?? "", { cause: inner });
			this.type = type;
		}
	};
	//#endregion
	//#region src/generated/VersionInfo.ts
	/**
	* @internal
	*/
	var VersionInfo = class VersionInfo {
		static version = "1.8.4";
		static date = "2026-07-05T14:46:18.224Z";
		static commit = "022a45c8e42370f9e12e68949d11eada370da83d";
		static print(print) {
			print(`alphaTab ${VersionInfo.version}`);
			print(`commit: ${VersionInfo.commit}`);
			print(`build date: ${VersionInfo.date}`);
		}
	};
	//#endregion
	//#region src/model/DynamicValue.ts
	/**
	* Lists all dynamics.
	* @public
	*/
	var DynamicValue = /* @__PURE__ */ function(DynamicValue) {
		/**
		* 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";
		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";
		return DynamicValue;
	}({});
	//#endregion
	//#region src/midi/MidiUtils.ts
	/**
	* @internal
	*/
	var MidiUtils = class MidiUtils {
		static QuarterTime = 960;
		static _minVelocity = 15;
		static VelocityIncrement = 16;
		/**
		* 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 * (6e4 / (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 / (6e4 / (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 / 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;
				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;
				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;
				case DynamicValue.FP:
					velocity = MidiUtils._minVelocity + 5 * MidiUtils.VelocityIncrement;
					break;
				case DynamicValue.RF:
				case DynamicValue.RFZ:
				case DynamicValue.SFFZ:
					velocity = MidiUtils._minVelocity + 5 * MidiUtils.VelocityIncrement;
					break;
				case DynamicValue.N:
					velocity = 1;
					break;
				case DynamicValue.PF:
					velocity = MidiUtils._minVelocity + (4.5 * MidiUtils.VelocityIncrement | 0);
					break;
			}
			velocity += adjustment * MidiUtils.VelocityIncrement;
			return Math.min(Math.max(velocity, 1), 127);
		}
	};
	//#endregion
	//#region src/model/Automation.ts
	/**
	* This public enumeration lists all types of automations.
	* @public
	*/
	var AutomationType = /* @__PURE__ */ 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";
		/**
		* Midi Bank change.
		*/
		AutomationType[AutomationType["Bank"] = 4] = "Bank";
		return AutomationType;
	}({});
	/**
	* Represents the data of a sync point for synchronizing the internal time axis with
	* an external audio file.
	* @cloneable
	* @json
	* @json_strict
	* @public
	*/
	var SyncPointData = class {
		/**
		* Indicates for which repeat occurence this sync point is valid (e.g. 0 on the first time played, 1 on the second time played)
		*/
		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.
		*/
		millisecondOffset = 0;
	};
	/**
	* Automations are used to change the behaviour of a song.
	* @cloneable
	* @json
	* @json_strict
	* @public
	*/
	var Automation = class Automation {
		/**
		* Gets or sets whether the automation is applied linear.
		*/
		isLinear = false;
		/**
		* Gets or sets the type of the automation.
		*/
		type = 0;
		/**
		* Gets or sets the target value of the automation.
		*/
		value = 0;
		/**
		* The sync point data in case of {@link AutomationType.SyncPoint}
		*/
		syncPointValue;
		/**
		* Gets or sets the relative position of of the automation.
		*/
		ratioPosition = 0;
		/**
		* Gets or sets the additional text of the automation.
		*/
		text = "";
		/**
		* Whether this automation should be visible. (not all automation types are shown, 
		* e.g. tempo changes shown in the score while volume changes are not).
		*/
		isVisible = true;
		static buildTempoAutomation(isLinear, ratioPosition, value, reference, isVisible = true) {
			if (reference < 1 || reference > 5) reference = 2;
			const references = new Float32Array([
				1,
				.5,
				1,
				1.5,
				2,
				3
			]);
			const automation = new Automation();
			automation.type = 0;
			automation.isLinear = isLinear;
			automation.ratioPosition = ratioPosition;
			automation.value = value * references[reference];
			automation.isVisible = isVisible;
			return automation;
		}
		static buildInstrumentAutomation(isLinear, ratioPosition, value) {
			const automation = new Automation();
			automation.type = 2;
			automation.isLinear = isLinear;
			automation.ratioPosition = ratioPosition;
			automation.value = value;
			return automation;
		}
	};
	//#endregion
	//#region src/model/BendPoint.ts
	/**
	* A single point of a bending graph. Used to
	* describe WhammyBar and String Bending effects.
	* @cloneable
	* @json
	* @json_strict
	* @public
	*/
	var BendPoint = class {
		static MaxPosition = 60;
		static MaxValue = 12;
		/**
		* Gets or sets offset of the point relative to the note duration (0-60)
		*/
		offset;
		/**
		* Gets or sets the 1/4 note value offsets for the bend.
		*/
		value;
		/**
		* 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;
		}
	};
	//#endregion
	//#region src/model/BendStyle.ts
	/**
	* Lists the different bend styles
	* @public
	*/
	var BendStyle = /* @__PURE__ */ 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";
		return BendStyle;
	}({});
	//#endregion
	//#region src/model/BendType.ts
	/**
	* Lists all types of bends
	* @public
	*/
	var BendType = /* @__PURE__ */ 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 played and
		* then releases the bend to a lower note where it is held until the end.
		*/
		BendType[BendType["PrebendRelease"] = 8] = "PrebendRelease";
		return BendType;
	}({});
	//#endregion
	//#region src/model/BrushType.ts
	/**
	* Lists all types of how to brush multiple notes on a beat.
	* @public
	*/
	var BrushType = /* @__PURE__ */ function(BrushType) {
		/**
		* No brush.
		*/
		BrushType[BrushType["None"] = 0] = "None";
		/**
		* Normal brush up.
		*/
		BrushType[BrushType["BrushUp"] = 1] = "BrushUp";
		/**
		* Normal brush down.
		*/
		BrushType[BrushType["BrushDown"] = 2] = "BrushDown";
		/**
		* Arpeggio up.
		*/
		BrushType[BrushType["ArpeggioUp"] = 3] = "ArpeggioUp";
		/**
		* Arpeggio down.
		*/
		BrushType[BrushType["ArpeggioDown"] = 4] = "ArpeggioDown";
		return BrushType;
	}({});
	//#endregion
	//#region src/model/CrescendoType.ts
	/**
	* Lists all Crescendo and Decrescendo types.
	* @public
	*/
	var CrescendoType = /* @__PURE__ */ function(CrescendoType) {
		/**
		* No crescendo applied.
		*/
		CrescendoType[CrescendoType["None"] = 0] = "None";
		/**
		* Normal crescendo applied.
		*/
		CrescendoType[CrescendoType["Crescendo"] = 1] = "Crescendo";
		/**
		* Normal decrescendo applied.
		*/
		CrescendoType[CrescendoType["Decrescendo"] = 2] = "Decrescendo";
		return CrescendoType;
	}({});
	//#endregion
	//#region src/model/Duration.ts
	/**
	* Lists all durations of a beat.
	* @public
	*/
	var Duration = /* @__PURE__ */ function(Duration) {
		/**
		* A quadruple whole note duration
		*/
		Duration[Duration["QuadrupleWhole"] = -4] = "QuadrupleWhole";
		/**
		* A double whole note duration
		*/
		Duration[Duration["DoubleWhole"] = -2] = "DoubleWhole";
		/**
		* A whole note duration
		*/
		Duration[Duration["Whole"] = 1] = "Whole";
		/**
		* A 1/2 note duration
		*/
		Duration[Duration["Half"] = 2] = "Half";
		/**
		* A 1/4 note duration
		*/
		Duration[Duration["Quarter"] = 4] = "Quarter";
		/**
		* A 1/8 note duration
		*/
		Duration[Duration["Eighth"] = 8] = "Eighth";
		/**
		* A 1/16 note duration
		*/
		Duration[Duration["Sixteenth"] = 16] = "Sixteenth";
		/**
		* A 1/32 note duration
		*/
		Duration[Duration["ThirtySecond"] = 32] = "ThirtySecond";
		/**
		* A 1/64 note duration
		*/
		Duration[Duration["SixtyFourth"] = 64] = "SixtyFourth";
		/**
		* A 1/128 note duration
		*/
		Duration[Duration["OneHundredTwentyEighth"] = 128] = "OneHundredTwentyEighth";
		/**
		* A 1/256 note duration
		*/
		Duration[Duration["TwoHundredFiftySixth"] = 256] = "TwoHundredFiftySixth";
		return Duration;
	}({});
	//#endregion
	//#region src/model/GraceType.ts
	/**
	* Lists all types of grace notes
	* @public
	*/
	var GraceType = /* @__PURE__ */ function(GraceType) {
		/**
		* No grace, normal beat.
		*/
		GraceType[GraceType["None"] = 0] = "None";
		/**
		* The beat contains on-beat grace notes.
		*/
		GraceType[GraceType["OnBeat"] = 1] = "OnBeat";
		/**
		* The beat contains before-beat grace notes.
		*/
		GraceType[GraceType["BeforeBeat"] = 2] = "BeforeBeat";
		/**
		* The beat contains very special bend-grace notes used in SongBook style displays.
		*/
		GraceType[GraceType["BendGrace"] = 3] = "BendGrace";
		return GraceType;
	}({});
	//#endregion
	//#region src/model/AccentuationType.ts
	/**
	* Lists all types of note acceuntations
	* @public
	*/
	var AccentuationType = /* @__PURE__ */ function(AccentuationType) {
		/**
		* No accentuation
		*/
		AccentuationType[AccentuationType["None"] = 0] = "None";
		/**
		* Normal accentuation
		*/
		AccentuationType[AccentuationType["Normal"] = 1] = "Normal";
		/**
		* Heavy accentuation
		*/
		AccentuationType[AccentuationType["Heavy"] = 2] = "Heavy";
		/**
		* Tenuto accentuation
		*/
		AccentuationType[AccentuationType["Tenuto"] = 3] = "Tenuto";
		return AccentuationType;
	}({});
	//#endregion
	//#region src/model/Fingers.ts
	/**
	* Lists all fingers.
	* @public
	*/
	var Fingers = /* @__PURE__ */ function(Fingers) {
		/**
		* Unknown type (not documented)
		*/
		Fingers[Fingers["Unknown"] = -2] = "Unknown";
		/**
		* No finger, dead note
		*/
		Fingers[Fingers["NoOrDead"] = -1] = "NoOrDead";
		/**
		* The thumb
		*/
		Fingers[Fingers["Thumb"] = 0] = "Thumb";
		/**
		* The index finger
		*/
		Fingers[Fingers["IndexFinger"] = 1] = "IndexFinger";
		/**
		* The middle finger
		*/
		Fingers[Fingers["MiddleFinger"] = 2] = "MiddleFinger";
		/**
		* The annular finger
		*/
		Fingers[Fingers["AnnularFinger"] = 3] = "AnnularFinger";
		/**
		* The little finger
		*/
		Fingers[Fingers["LittleFinger"] = 4] = "LittleFinger";
		return Fingers;
	}({});
	//#endregion
	//#region src/model/HarmonicType.ts
	/**
	* Lists all harmonic types.
	* @public
	*/
	var HarmonicType = /* @__PURE__ */ function(HarmonicType) {
		/**
		* No harmonics.
		*/
		HarmonicType[HarmonicType["None"] = 0] = "None";
		/**
		* Natural harmonic
		*/
		HarmonicType[HarmonicType["Natural"] = 1] = "Natural";
		/**
		* Artificial harmonic
		*/
		HarmonicType[HarmonicType["Artificial"] = 2] = "Artificial";
		/**
		* Pinch harmonics
		*/
		HarmonicType[HarmonicType["Pinch"] = 3] = "Pinch";
		/**
		* Tap harmonics
		*/
		HarmonicType[HarmonicType["Tap"] = 4] = "Tap";
		/**
		* Semi harmonics
		*/
		HarmonicType[HarmonicType["Semi"] = 5] = "Semi";
		/**
		* Feedback harmonics
		*/
		HarmonicType[HarmonicType["Feedback"] = 6] = "Feedback";
		return HarmonicType;
	}({});
	//#endregion
	//#region src/model/NoteAccidentalMode.ts
	/**
	* Lists the modes how accidentals are handled for notes
	* @public
	*/
	var NoteAccidentalMode = /* @__PURE__ */ function(NoteAccidentalMode) {
		/**
		* Accidentals are calculated automatically.
		*/
		NoteAccidentalMode[NoteAccidentalMode["Default"] = 0] = "Default";
		/**
		* This will try to ensure that no accidental is shown.
		*/
		NoteAccidentalMode[NoteAccidentalMode["ForceNone"] = 1] = "ForceNone";
		/**
		* This will move the note one line down and applies a Naturalize.
		*/
		NoteAccidentalMode[NoteAccidentalMode["ForceNatural"] = 2] = "ForceNatural";
		/**
		* This will move the note one line down and applies a Sharp.
		*/
		NoteAccidentalMode[NoteAccidentalMode["ForceSharp"] = 3] = "ForceSharp";
		/**
		* This will move the note to be shown 2 half-notes deeper with a double sharp symbol
		*/
		NoteAccidentalMode[NoteAccidentalMode["ForceDoubleSharp"] = 4] = "ForceDoubleSharp";
		/**
		* This will move the note one line up and applies a Flat.
		*/
		NoteAccidentalMode[NoteAccidentalMode["ForceFlat"] = 5] = "ForceFlat";
		/**
		* This will move the note two half notes up with a double flag symbol.
		*/
		NoteAccidentalMode[NoteAccidentalMode["ForceDoubleFlat"] = 6] = "ForceDoubleFlat";
		return NoteAccidentalMode;
	}({});
	//#endregion
	//#region src/model/Ottavia.ts
	/**
	* Lists all ottavia.
	* @public
	*/
	var Ottavia = /* @__PURE__ */ 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";
		return Ottavia;
	}({});
	//#endregion
	//#region src/model/SlideInType.ts
	/**
	* This public enum lists all different types of finger slide-ins on a string.
	* @public
	*/
	var SlideInType = /* @__PURE__ */ function(SlideInType) {
		/**
		* No slide.
		*/
		SlideInType[SlideInType["None"] = 0] = "None";
		/**
		* Slide into the note from below on the same string.
		*/
		SlideInType[SlideInType["IntoFromBelow"] = 1] = "IntoFromBelow";
		/**
		* Slide into the note from above on the same string.
		*/
		SlideInType[SlideInType["IntoFromAbove"] = 2] = "IntoFromAbove";
		return SlideInType;
	}({});
	//#endregion
	//#region src/model/SlideOutType.ts
	/**
	* This public enum lists all different types of finger slide-outs on a string.
	* @public
	*/
	var SlideOutType = /* @__PURE__ */ function(SlideOutType) {
		/**
		* No slide.
		*/
		SlideOutType[SlideOutType["None"] = 0] = "None";
		/**
		* Shift slide to next note on same string
		*/
		SlideOutType[SlideOutType["Shift"] = 1] = "Shift";
		/**
		* Legato slide to next note on same string.
		*/
		SlideOutType[SlideOutType["Legato"] = 2] = "Legato";
		/**
		* Slide out from the note from upwards on the same string.
		*/
		SlideOutType[SlideOutType["OutUp"] = 3] = "OutUp";
		/**
		* Slide out from the note from downwards on the same string.
		*/
		SlideOutType[SlideOutType["OutDown"] = 4] = "OutDown";
		/**
		* Pickslide down on this note
		*/
		SlideOutType[SlideOutType["PickSlideDown"] = 5] = "PickSlideDown";
		/**
		* Pickslide up on this note
		*/
		SlideOutType[SlideOutType["PickSlideUp"] = 6] = "PickSlideUp";
		return SlideOutType;
	}({});
	//#endregion
	//#region src/model/Slur.ts
	/**
	* A slur arc spanning two notes, optionally with inner articulation
	* segments. Corresponds conceptually to a MusicXML `<slur>` element
	* plus the technique spans inside it.
	*
	* For this PR only effect slurs (hammer-pull + legato-slide chains)
	* are derived in `Note.finish()`. Phrase and legato slurs may join
	* this type in a future PR; a discriminator will be added at that
	* point.
	* @internal
	*/
	var Slur = class {
		originNote;
		destinationNote;
		segments = [];
	};
	//#endregion
	//#region src/model/SlurSegmentKind.ts
	/**
	* Articulation kind for an inner span of a {@link Slur}.
	*
	* Drives the renderer's font selection (which {@link NotationElement} to
	* use) and the default label text when {@link SlurSegment.text} is null.
	* `Note.finish()` classifies the kind once when building the slur; the
	* renderer never re-derives it.
	* @internal
	*/
	var SlurSegmentKind = /* @__PURE__ */ function(SlurSegmentKind) {
		SlurSegmentKind[SlurSegmentKind["HammerPull"] = 0] = "HammerPull";
		SlurSegmentKind[SlurSegmentKind["LegatoSlide"] = 1] = "LegatoSlide";
		return SlurSegmentKind;
	}({});
	//#endregion
	//#region src/model/VibratoType.ts
	/**
	* This public enum lists all vibrato types that can be performed.
	* @public
	*/
	var VibratoType = /* @__PURE__ */ function(VibratoType) {
		/**
		* No vibrato.
		*/
		VibratoType[VibratoType["None"] = 0] = "None";
		/**
		* A slight vibrato.
		*/
		VibratoType[VibratoType["Slight"] = 1] = "Slight";
		/**
		* A wide vibrato.
		*/
		VibratoType[VibratoType["Wide"] = 2] = "Wide";
		return VibratoType;
	}({});
	//#endregion
	//#region src/NotationSettings.ts
	/**
	* Lists the different modes on how rhythm notation is shown on the tab staff.
	* @public
	*/
	var TabRhythmMode = /* @__PURE__ */ function(TabRhythmMode) {
		/**
		* Rhythm notation is hidden.
		*/
		TabRhythmMode[TabRhythmMode["Hidden"] = 0] = "Hidden";
		/**
		* Rhythm notation is shown with individual beams per beat.
		*/
		TabRhythmMode[TabRhythmMode["ShowWithBeams"] = 1] = "ShowWithBeams";
		/**
		* Rhythm notation is shown and behaves like normal score notation with connected bars.
		*/
		TabRhythmMode[TabRhythmMode["ShowWithBars"] = 2] = "ShowWithBars";
		/**
		* Automatic detection whether the tabs should show rhythm based on hidden standard notation.
		* @since 1.4.0
		*/
		TabRhythmMode[TabRhythmMode["Automatic"] = 3] = "Automatic";
		return TabRhythmMode;
	}({});
	/**
	* Lists all modes on how fingerings should be displayed.
	* @public
	*/
	var FingeringMode = /* @__PURE__ */ function(FingeringMode) {
		/**
		* Fingerings will be shown in the standard notation staff.
		*/
		FingeringMode[FingeringMode["ScoreDefault"] = 0] = "ScoreDefault";
		/**
		* Fingerings will be shown in the standard notation staff. Piano finger style is enforced, where
		* fingers are rendered as 1-5 instead of p,i,m,a,c and T,1,2,3,4.
		*/
		FingeringMode[FingeringMode["ScoreForcePiano"] = 1] = "ScoreForcePiano";
		/**
		* Fingerings will be shown in a effect band above the tabs in case
		* they have only a single note on the beat.
		*/
		FingeringMode[FingeringMode["SingleNoteEffectBand"] = 2] = "SingleNoteEffectBand";
		/**
		* Fingerings will be shown in a effect band above the tabs in case
		* they have only a single note on the beat. Piano finger style is enforced, where
		* fingers are rendered as 1-5 instead of p,i,m,a,c and T,1,2,3,4.
		*/
		FingeringMode[FingeringMode["SingleNoteEffectBandForcePiano"] = 3] = "SingleNoteEffectBandForcePiano";
		return FingeringMode;
	}({});
	/**
	* Lists all modes on how alphaTab can handle the display and playback of music notation.
	* @public
	*/
	var NotationMode = /* @__PURE__ */ function(NotationMode) {
		/**
		* Music elements will be displayed and played as in Guitar Pro.
		*/
		NotationMode[NotationMode["GuitarPro"] = 0] = "GuitarPro";
		/**
		* Music elements will be displayed and played as in traditional songbooks.
		* Changes:
		* 1. Bends
		*   For bends additional grace beats are introduced.
		*   Bends are categorized into gradual and fast bends.
		*   - Gradual bends are indicated by beat text "grad" or "grad.". Bend will sound along the beat duration.
		*   - Fast bends are done right before the next note. If the next note is tied even on-beat of the next note.
		* 2. Whammy Bars
		*   Dips are shown as simple annotation over the beats
		*   Whammy Bars are categorized into gradual and fast.
		*   - Gradual whammys are indicated by beat text "grad" or "grad.". Whammys will sound along the beat duration.
		*   - Fast whammys are done right the beat.
		* 3. Let Ring
		*   Tied notes with let ring are not shown in standard notation
		*   Let ring does not cause a longer playback, duration is defined via tied notes.
		*/
		NotationMode[NotationMode["SongBook"] = 1] = "SongBook";
		return NotationMode;
	}({});
	/**
	* Lists all major music notation elements that are part
	* of the music sheet and can be dynamically controlled to be shown
	* or hidden.
	* @public
	*/
	var NotationElement = /* @__PURE__ */ function(NotationElement) {
		/**
		* The score title shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreTitle"] = 0] = "ScoreTitle";
		/**
		* The score subtitle shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreSubTitle"] = 1] = "ScoreSubTitle";
		/**
		* The score artist shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreArtist"] = 2] = "ScoreArtist";
		/**
		* The score album shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreAlbum"] = 3] = "ScoreAlbum";
		/**
		* The score words author shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreWords"] = 4] = "ScoreWords";
		/**
		* The score music author shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreMusic"] = 5] = "ScoreMusic";
		/**
		* The score words&music author shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreWordsAndMusic"] = 6] = "ScoreWordsAndMusic";
		/**
		* The score copyright owner shown at the start of the music sheet.
		*/
		NotationElement[NotationElement["ScoreCopyright"] = 7] = "ScoreCopyright";
		/**
		* The tuning information of the guitar shown
		* above the staves.
		*/
		NotationElement[NotationElement["GuitarTuning"] = 8] = "GuitarTuning";
		/**
		* The track names which are shown in the accolade.
		*/
		NotationElement[NotationElement["TrackNames"] = 9] = "TrackNames";
		/**
		* The chord diagrams for guitars. Usually shown
		* below the score info.
		*/
		NotationElement[NotationElement["ChordDiagrams"] = 10] = "ChordDiagrams";
		/**
		* Parenthesis that are shown for tied bends
		* if they are preceeded by bends.
		*/
		NotationElement[NotationElement["ParenthesisOnTiedBends"] = 11] = "ParenthesisOnTiedBends";
		/**
		* The tab number for tied notes if the
		* bend of a note is increased at that point.
		*/
		NotationElement[NotationElement["TabNotesOnTiedBends"] = 12] = "TabNotesOnTiedBends";
		/**
		* Zero tab numbers on "dive whammys".
		*/
		NotationElement[NotationElement["ZerosOnDiveWhammys"] = 13] = "ZerosOnDiveWhammys";
		/**
		* The alternate endings information on repeats shown above the staff.
		*/
		NotationElement[NotationElement["EffectAlternateEndings"] = 14] = "EffectAlternateEndings";
		/**
		* The information about the fret on which the capo is placed shown above the staff.
		*/
		NotationElement[NotationElement["EffectCapo"] = 15] = "EffectCapo";
		/**
		* The chord names shown above beats shown above the staff.
		*/
		NotationElement[NotationElement["EffectChordNames"] = 16] = "EffectChordNames";
		/**
		* The crescendo/decrescendo angle  shown above the staff.
		*/
		NotationElement[NotationElement["EffectCrescendo"] = 17] = "EffectCrescendo";
		/**
		* The beat dynamics  shown above the staff.
		*/
		NotationElement[NotationElement["EffectDynamics"] = 18] = "EffectDynamics";
		/**
		* The curved angle for fade in/out effects  shown above the staff.
		*/
		NotationElement[NotationElement["EffectFadeIn"] = 19] = "EffectFadeIn";
		/**
		* The fermata symbol shown above the staff.
		*/
		NotationElement[NotationElement["EffectFermata"] = 20] = "EffectFermata";
		/**
		* The fingering information.
		*/
		NotationElement[NotationElement["EffectFingering"] = 21] = "EffectFingering";
		/**
		* The harmonics names shown above the staff.
		* (does not represent the harmonic note heads)
		*/
		NotationElement[NotationElement["EffectHarmonics"] = 22] = "EffectHarmonics";
		/**
		* The let ring name and line above the staff.
		*/
		NotationElement[NotationElement["EffectLetRing"] = 23] = "EffectLetRing";
		/**
		* The lyrics of the track shown above the staff.
		*/
		NotationElement[NotationElement["EffectLyrics"] = 24] = "EffectLyrics";
		/**
		* The section markers shown above the staff.
		*/
		NotationElement[NotationElement["EffectMarker"] = 25] = "EffectMarker";
		/**
		* The ottava symbol and lines shown above the staff.
		*/
		NotationElement[NotationElement["EffectOttavia"] = 26] = "EffectOttavia";
		/**
		* The palm mute name and line shown above the staff.
		*/
		NotationElement[NotationElement["EffectPalmMute"] = 27] = "EffectPalmMute";
		/**
		* The pick slide information shown above the staff.
		* (does not control the pick slide lines)
		*/
		NotationElement[NotationElement["EffectPickSlide"] = 28] = "EffectPickSlide";
		/**
		* The pick stroke symbols shown above the staff.
		*/
		NotationElement[NotationElement["EffectPickStroke"] = 29] = "EffectPickStroke";
		/**
		* The slight beat vibrato waves shown above the staff.
		*/
		NotationElement[NotationElement["EffectSlightBeatVibrato"] = 30] = "EffectSlightBeatVibrato";
		/**
		* The slight note vibrato waves shown above the staff.
		*/
		NotationElement[NotationElement["EffectSlightNoteVibrato"] = 31] = "EffectSlightNoteVibrato";
		/**
		* The tap/slap/pop effect names shown above the staff.
		*/
		NotationElement[NotationElement["EffectTap"] = 32] = "EffectTap";
		/**
		* The tempo information shown above the staff.
		*/
		NotationElement[NotationElement["EffectTempo"] = 33] = "EffectTempo";
		/**
		* The additional beat text shown above the staff.
		*/
		NotationElement[NotationElement["EffectText"] = 34] = "EffectText";
		/**
		* The trill name and waves shown above the staff.
		*/
		NotationElement[NotationElement["EffectTrill"] = 35] = "EffectTrill";
		/**
		* The triplet feel symbol shown above the staff.
		*/
		NotationElement[NotationElement["EffectTripletFeel"] = 36] = "EffectTripletFeel";
		/**
		* The whammy bar information shown above the staff.
		* (does not control the whammy lines shown within the staff)
		*/
		NotationElement[NotationElement["EffectWhammyBar"] = 37] = "EffectWhammyBar";
		/**
		* The wide beat vibrato waves shown above the staff.
		*/
		NotationElement[NotationElement["EffectWideBeatVibrato"] = 38] = "EffectWideBeatVibrato";
		/**
		* The wide note vibrato waves shown above the staff.
		*/
		NotationElement[NotationElement["EffectWideNoteVibrato"] = 39] = "EffectWideNoteVibrato";
		/**
		* The left hand tap symbol shown above the staff.
		*/
		NotationElement[NotationElement["EffectLeftHandTap"] = 40] = "EffectLeftHandTap";
		/**
		* The "Free time" text shown above the staff.
		*/
		NotationElement[NotationElement["EffectFreeTime"] = 41] = "EffectFreeTime";
		/**
		* The Sustain pedal effect shown above the staff "Ped.____*"
		*/
		NotationElement[NotationElement["EffectSustainPedal"] = 42] = "EffectSustainPedal";
		/**
		* The Golpe effect signs above and below the staff.
		*/
		NotationElement[NotationElement["EffectGolpe"] = 43] = "EffectGolpe";
		/**
		* The Wah effect signs above and below the staff.
		*/
		NotationElement[NotationElement["EffectWahPedal"] = 44] = "EffectWahPedal";
		/**
		* The Beat barre effect signs above and below the staff "1/2B IV ─────┐"
		*/
		NotationElement[NotationElement["EffectBeatBarre"] = 45] = "EffectBeatBarre";
		/**
		* The note ornaments like turns and mordents.
		*/
		NotationElement[NotationElement["EffectNoteOrnament"] = 46] = "EffectNoteOrnament";
		/**
		* The Rasgueado indicator above the staff Rasg. ----|"
		*/
		NotationElement[NotationElement["EffectRasgueado"] = 47] = "EffectRasgueado";
		/**
		* The directions indicators like coda and segno.
		*/
		NotationElement[NotationElement["EffectDirections"] = 48] = "EffectDirections";
		/**
		* The absolute playback time of beats.
		*/
		NotationElement[NotationElement["EffectBeatTimer"] = 49] = "EffectBeatTimer";
		/**
		* The whammy bar line effect shown above the tab staff
		*/
		NotationElement[NotationElement["EffectWhammyBarLine"] = 50] = "EffectWhammyBarLine";
		/**
		* The key signature for numbered notation staff.
		*/
		NotationElement[NotationElement["EffectNumberedNotationKeySignature"] = 51] = "EffectNumberedNotationKeySignature";
		/**
		* The fretboard numbers shown in chord diagrams.
		*/
		NotationElement[NotationElement["ChordDiagramFretboardNumbers"] = 52] = "ChordDiagramFretboardNumbers";
		/**
		* The bar numbers.
		*/
		NotationElement[NotationElement["BarNumber"] = 53] = "BarNumber";
		/**
		* The repeat count indicator shown above the thick bar line to describe
		* how many repeats should be played.
		*/
		NotationElement[NotationElement["RepeatCount"] = 54] = "RepeatCount";
		/**
		* The slurs shown on bend effects within the score staff.
		*/
		NotationElement[NotationElement["ScoreBendSlur"] = 55] = "ScoreBendSlur";
		/**
		* The hammer-on pull-off text shown on slurs.
		*/
		NotationElement[NotationElement["EffectHammerOnPullOffText"] = 56] = "EffectHammerOnPullOffText";
		/**
		* The slide text shown on slurs.
		*/
		NotationElement[NotationElement["EffectSlideText"] = 57] = "EffectSlideText";
		return NotationElement;
	}({});
	/**
	* The notation settings control how various music notation elements are shown and behaving
	* @json
	* @json_declaration
	* @public
	*/
	var NotationSettings = class NotationSettings {
		/**
		* The mode to use for display and play music notation elements.
		* @since 0.9.6
		* @category Notation
		* @defaultValue `NotationMode.GuitarPro`
		* @remarks
		* AlphaTab provides 2 main music notation display modes `GuitarPro` and `SongBook`.
		* As the names indicate they adjust the overall music notation rendering either to be more in line how [Arobas Guitar Pro](https://www.guitar-pro.com) displays it,
		* or more like the common practice in paper song books practices the display.
		*
		* The main differences in the Songbook display mode are:
		*
		* 1. **Bends**
		* For bends additional grace beats are introduced. Bends are categorized into gradual and fast bends.
		*     * Gradual bends are indicated by beat text "grad" or "grad.". Bend will sound along the beat duration.
		*     * Fast bends are done right before the next note. If the next note is tied even on-beat of the next note.
		* 2.  **Whammy Bars**
		* Dips are shown as simple annotation over the beats. Whammy Bars are categorized into gradual and fast.
		*     * Gradual whammys are indicated by beat text "grad" or "grad.". Whammys will sound along the beat duration.
		*     * Fast whammys are done right the beat.
		*
		* 3. **Let Ring**
		* Tied notes with let ring are not shown in standard notation. Let ring does not cause a longer playback, duration is defined via tied notes.
		*
		* 4. **Settings**
		* Following default setting values are applied:
		* ```js
		* {
		*     notation: {
		*         smallGraceTabNotes: false,
		*         fingeringMode: alphaTab.FingeringMode.SingleNoteEffectBandm
		*         extendBendArrowsOnTiedNotes: false
		*     },
		*     elements: {
		*         parenthesisOnTiedBends: false,
		*         tabNotesOnTiedBends: false,
		*         zerosOnDiveWhammys: true
		*     }
		* }
		* ```
		*/
		notationMode = 0;
		/**
		* The fingering mode to use.
		* @since 0.9.6
		* @category Notation
		* @defaultValue `FingeringMode.ScoreDefault`
		* @remarks
		* AlphaTab supports multiple modes on how to display fingering information in the music sheet. This setting controls how they should be displayed. The default behavior is to show the finger information
		* directly in the score along the notes. For some use cases of training courses and for beginners this notation might be hard to read. The effect band mode allows to show a single finger information above the staff.
		*
		* | Score                                                       | Effect Band                                                       |
		* |-------------------------------------------------------------|-------------------------------------------------------------------|
		* | ![Enabled](https://alphatab.net/img/reference/property/fingeringmode-score.png) | ![Disabled](https://alphatab.net/img/reference/property/fingeringmode-effectband.png) |
		*/
		fingeringMode = 0;
		/**
		* Whether music notation elements are visible or not.
		* @since 0.9.8
		* @category Notation
		* @defaultValue `[[NotationElement.ZerosOnDiveWhammys, false]]`
		* @remarks
		* AlphaTab has quite a set of notation elements that are usually shown by default or only shown when using
		* the `SongBook` notation mode. This setting allows showing/hiding individual notation elements like the
		* song information or the track names.
		*
		* For each element you can configure whether it is visible or not. The setting is a Map/Dictionary where
		* the key is the element to configure and the value is a boolean value whether it should be visible or not.
		* @example
		* JavaScript
		* Internally the setting is a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) where the key must be a {@link NotationElement} enumeration value.
		* For JSON input the usual enumeration serialization applies where also the names can be used. The names
		* are case insensitive.
		*
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'), {
		*     notation: {
		*         elements: {
		*             scoreTitle: false,
		*             trackNames: false
		*         }
		*     }
		* });
		* api.settings.notation.elements.set(alphaTab.NotationElement.EffectWhammyBar, false);
		* ```
		* @example
		* C#
		* ```cs
		* var settings = new AlphaTab.Settings();
		* settings.Notation.Elements[AlphaTab.NotationElement.ScoreTitle] = false;
		* settings.Notation.Elements[AlphaTab.NotationElement.TrackNames] = false;
		* ```
		* @example
		* Android
		* ```kotlin
		* val settings = AlphaTab.Settings();
		* settings.notation.elements[alphaTab.NotationElement.ScoreTitle] = false;
		* settings.notation.elements[alphaTab.NotationElement.TrackNames] = false;
		* ```
		*/
		elements = /* @__PURE__ */ new Map();
		/**
		* Gets the default configuration of the {@see notationElements} setting. Do not modify
		* this map as it might not result in the expected side effects.
		* If items are not listed explicitly in this list, they are considered visible.
		*/
		static defaultElements = new Map([[13, false]]);
		/**
		* Controls how the rhythm notation is rendered for tab staves.
		* @since 0.9.6
		* @category Notation
		* @defaultValue `TabRhythmMode.Automatic`
		* @remarks
		* This setting enables the display of rhythm notation on tab staffs. [Demo](https://alphatab.net/docs/showcase/guitar-tabs)
		* {@since 1.4.0} its automatically detected whether rhythm notation should be shown on tabs (based on the visibility of other staves).
		*/
		rhythmMode = 3;
		/**
		* Controls how high the ryhthm notation is rendered below the tab staff
		* @since 0.9.6
		* @category Notation
		* @defaultValue `25`
		* @remarks
		* This setting can be used in combination with the {@link rhythmMode} setting to control how high the rhythm notation should be rendered below the tab staff.
		*/
		rhythmHeight = 25;
		/**
		* The transposition pitch offsets for the individual tracks used for rendering and playback.
		* @since 0.9.6
		* @category Notation
		* @defaultValue `[]`
		* @remarks
		* This setting allows transposing of tracks for display and playback.
		* The `transpositionPitches` setting allows defining an additional pitch offset per track, that is then considered when displaying the music sheet.
		*/
		transpositionPitches = [];
		/**
		* The transposition pitch offsets for the individual tracks used for rendering only.
		* @since 0.9.6
		* @category Notation
		* @defaultValue `[]`
		* @remarks
		* For some instruments the pitch shown on the standard notation has an additional transposition. One example is the Guitar.
		* Notes are shown 1 octave higher than they are on the piano. The following image shows a C4 for a piano and a guitar, and a C5 for the piano as comparison:
		*
		* ![Display Transposition Pitches example](https://alphatab.net/img/reference/property/displaytranspositionpitches.png)
		*
		* The `DisplayTranspositionPitch` setting allows defining an additional pitch offset per track, that is then considered when displaying the music sheet.
		* This setting does not affect the playback of the instrument in any way. Despite the 2 different standard notations in the above example, they both play the same note height.
		* The transposition is defined as number of semitones and one value per track of the song can be defined.
		*/
		displayTranspositionPitches = [];
		/**
		* If set to true the guitar tabs on grace beats are rendered smaller.
		* @since 0.9.6
		* @category Notation
		* @defaultValue `true`
		* @remarks
		* By default, grace notes are drawn smaller on the guitar tabs than the other numbers. With this setting alphaTab can be configured to show grace tab notes with normal text size.
		* | Enabled                                                            | Disabled                                                             |
		* |--------------------------------------------------------------------|----------------------------------------------------------------------|
		* | ![Enabled](https://alphatab.net/img/reference/property/smallgracetabnotes-enabled.png) | ![Disabled](https://alphatab.net/img/reference/property/smallgracetabnotes-disabled.png) |
		*/
		smallGraceTabNotes = true;
		/**
		* If set to true bend arrows expand to the end of the last tied note of the string. Otherwise they end on the next beat.
		* @since 0.9.6
		* @category Notation
		* @defaultValue `true`
		* @remarks
		* By default the arrows and lines on bend effects are extended to the space of tied notes. This behavior is the Guitar Pro default but some applications and songbooks practice it different.
		* There the bend only is drawn to the next beat.
		* | Enabled                                                                     | Disabled                                                                      |
		* |-----------------------------------------------------------------------------|-------------------------------------------------------------------------------|
		* | ![Enabled](https://alphatab.net/img/reference/property/extendbendarrowsontiednotes-enabled.png) | ![Disabled](https://alphatab.net/img/reference/property/extendbendarrowsontiednotes-disabled.png) |
		*/
		extendBendArrowsOnTiedNotes = true;
		/**
		* If set to true, line effects like w/bar and let-ring are drawn until the end of the beat instead of the start
		* @since 0.9.6
		* @category Notation
		* @defaultValue `false`
		* @remarks
		* By default effect annotations that render a line above the staff, stop on the beat. This is the typical display of Guitar Pro. In songbooks and some other tools
		* these effects are drawn to the end of this beat.
		* | Enabled                                                                     | Disabled                                                                      |
		* |-----------------------------------------------------------------------------|-------------------------------------------------------------------------------|
		* | ![Enabled](https://alphatab.net/img/reference/property/extendlineeffectstobeatend-enabled.png) | ![Disabled](https://alphatab.net/img/reference/property/extendlineeffectstobeatend-disabled.png) |
		*/
		extendLineEffectsToBeatEnd = false;
		/**
		* The height scale factor for slurs
		* @since 0.9.6
		* @category Notation
		* @defaultValue `5`
		* @remarks
		* Slurs and ties currently calculate their height based on the distance they have from start to end note. Most music notation software do some complex collision detection to avoid a slur to overlap with other elements, alphaTab
		* only has a simplified version of the slur positioning as of today. This setting allows adjusting the slur height to avoid collisions. The factor defined by this setting, is multiplied with the logarithmic distance between start and end.
		* | Slur Height Default                                                    | Slur Height 14                                               |
		* |------------------------------------------------------------------------|--------------------------------------------------------------|
		* | ![Slur Height Default](https://alphatab.net/img/reference/property/slurheight-default.png) | ![Slur Height 14](https://alphatab.net/img/reference/property/slurheight-14.png)  |
		*/
		slurHeight = 5;
		/**
		* Gets whether the given music notation element should be shown
		* @param element the element to check
		* @returns true if the element should be shown, otherwise false.
		*/
		isNotationElementVisible(element) {
			if (this.elements.has(element)) return this.elements.get(element);
			if (NotationSettings.defaultElements.has(element)) return NotationSettings.defaultElements.get(element);
			return true;
		}
	};
	//#endregion
	//#region src/util/Lazy.ts
	/**
	* @target web
	* @internal
	*/
	var Lazy = class {
		_factory;
		_value = void 0;
		get hasValue() {
			return this._value !== void 0;
		}
		constructor(factory) {
			this._factory = factory;
		}
		get value() {
			if (this._value === void 0) this._value = this._factory();
			return this._value;
		}
		reset() {
			this._value = void 0;
		}
	};
	//#endregion
	//#region src/LogLevel.ts
	/**
	* Defines all loglevels.
	* @json
	* @public
	*/
	var LogLevel = /* @__PURE__ */ function(LogLevel) {
		/**
		* No logging
		*/
		LogLevel[LogLevel["None"] = 0] = "None";
		/**
		* Debug level (internal details are displayed).
		*/
		LogLevel[LogLevel["Debug"] = 1] = "Debug";
		/**
		* Info level (only important details are shown)
		*/
		LogLevel[LogLevel["Info"] = 2] = "Info";
		/**
		* Warning level
		*/
		LogLevel[LogLevel["Warning"] = 3] = "Warning";
		/**
		* Error level.
		*/
		LogLevel[LogLevel["Error"] = 4] = "Error";
		return LogLevel;
	}({});
	//#endregion
	//#region src/Logger.ts
	/**
	* @public
	*/
	var ConsoleLogger = class ConsoleLogger {
		static logLevel = LogLevel.Info;
		static _format(category, msg) {
			return `[AlphaTab][${category}] ${msg}`;
		}
		debug(category, msg, ...details) {
			console.debug(ConsoleLogger._format(category, msg), ...details);
		}
		warning(category, msg, ...details) {
			console.warn(ConsoleLogger._format(category, msg), ...details);
		}
		info(category, msg, ...details) {
			console.info(ConsoleLogger._format(category, msg), ...details);
		}
		error(category, msg, ...details) {
			console.error(ConsoleLogger._format(category, msg), ...details);
		}
	};
	/**
	* @public
	*/
	var Logger = class Logger {
		static logLevel = LogLevel.Info;
		static log = new ConsoleLogger();
		static _shouldLog(level) {
			return Logger.logLevel !== LogLevel.None && level >= Logger.logLevel;
		}
		static debug(category, msg, ...details) {
			if (Logger._shouldLog(LogLevel.Debug)) Logger.log.debug(category, msg, ...details);
		}
		static warning(category, msg, ...details) {
			if (Logger._shouldLog(LogLevel.Warning)) Logger.log.warning(category, msg, ...details);
		}
		static info(category, msg, ...details) {
			if (Logger._shouldLog(LogLevel.Info)) Logger.log.info(category, msg, ...details);
		}
		static error(category, msg, ...details) {
			if (Logger._shouldLog(LogLevel.Error)) Logger.log.error(category, msg, ...details);
		}
	};
	//#endregion
	//#region src/model/AccidentalType.ts
	/**
	* Defines all possible accidentals for notes.
	* @public
	*/
	var AccidentalType = /* @__PURE__ */ function(AccidentalType) {
		/**
		* No accidental
		*/
		AccidentalType[AccidentalType["None"] = 0] = "None";
		/**
		* Naturalize
		*/
		AccidentalType[AccidentalType["Natural"] = 1] = "Natural";
		/**
		* Sharp
		*/
		AccidentalType[AccidentalType["Sharp"] = 2] = "Sharp";
		/**
		* Flat
		*/
		AccidentalType[AccidentalType["Flat"] = 3] = "Flat";
		/**
		* Natural for smear bends
		*/
		AccidentalType[AccidentalType["NaturalQuarterNoteUp"] = 4] = "NaturalQuarterNoteUp";
		/**
		* Sharp for smear bends
		*/
		AccidentalType[AccidentalType["SharpQuarterNoteUp"] = 5] = "SharpQuarterNoteUp";
		/**
		* Flat for smear bends
		*/
		AccidentalType[AccidentalType["FlatQuarterNoteUp"] = 6] = "FlatQuarterNoteUp";
		/**
		* Double Sharp, indicated by an 'x'
		*/
		AccidentalType[AccidentalType["DoubleSharp"] = 7] = "DoubleSharp";
		/**
		* Double Flat, indicated by 'bb'
		*/
		AccidentalType[AccidentalType["DoubleFlat"] = 8] = "DoubleFlat";
		return AccidentalType;
	}({});
	//#endregion
	//#region src/model/Clef.ts
	/**
	* This public enumeration lists all supported Clefs.
	* @public
	*/
	var Clef = /* @__PURE__ */ 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";
		return Clef;
	}({});
	//#endregion
	//#region src/model/SimileMark.ts
	/**
	* Lists all simile mark types as they are assigned to bars.
	* @public
	*/
	var SimileMark = /* @__PURE__ */ 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";
		return SimileMark;
	}({});
	//#endregion
	//#region src/model/ElementStyle.ts
	/**
	* Defines the custom styles for an element in the music sheet (like bars, voices, notes etc).
	* @public
	*/
	var ElementStyle = class {
		/**
		* 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.
		*/
		colors = /* @__PURE__ */ new Map();
	};
	//#endregion
	//#region src/model/KeySignature.ts
	/**
	* This public enumeration lists all available key signatures
	* @public
	*/
	var KeySignature = /* @__PURE__ */ 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";
		return KeySignature;
	}({});
	//#endregion
	//#region src/model/KeySignatureType.ts
	/**
	* This public enumeration lists all available types of KeySignatures
	* @public
	*/
	var KeySignatureType = /* @__PURE__ */ function(KeySignatureType) {
		/**
		* Major
		*/
		KeySignatureType[KeySignatureType["Major"] = 0] = "Major";
		/**
		* Minor
		*/
		KeySignatureType[KeySignatureType["Minor"] = 1] = "Minor";
		return KeySignatureType;
	}({});
	//#endregion
	//#region src/model/Bar.ts
	/**
	* The different pedal marker types.
	* @public
	*/
	var SustainPedalMarkerType = /* @__PURE__ */ 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";
		return SustainPedalMarkerType;
	}({});
	/**
	* A marker on whether a sustain pedal starts or ends.
	* @json
	* @json_strict
	* @public
	*/
	var SustainPedalMarker = class {
		/**
		* The relative position of pedal markers within the bar.
		*/
		ratioPosition = 0;
		/**
		* Whether what should be done with the pedal at this point
		*/
		pedalType = 0;
		/**
		* THe bar to which this marker belongs to.
		* @json_ignore
		*/
		bar;
		/**
		* 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
		*/
		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
		*/
		previousPedalMarker = null;
	};
	/**
	* Lists all graphical sub elements within a {@link Bar} which can be styled via {@link Bar.style}
	* @public
	*/
	var BarSubElement = /* @__PURE__ */ 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";
		return BarSubElement;
	}({});
	/**
	* Defines the custom styles for bars.
	* @json
	* @json_strict
	* @public
	*/
	var BarStyle = class extends ElementStyle {};
	/**
	* Lists all bar line styles.
	* @public
	*/
	var BarLineStyle = /* @__PURE__ */ 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";
		return BarLineStyle;
	}({});
	/**
	* A bar is a single block within a track, also known as Measure.
	* @json
	* @json_strict
	* @public
	*/
	var Bar = class Bar {
		static _globalBarId = 0;
		/**
		* @internal
		*/
		static resetIds() {
			Bar._globalBarId = 0;
		}
		/**
		* Gets or sets the unique id of this bar.
		*/
		id = Bar._globalBarId++;
		/**
		* Gets or sets the zero-based index of this bar within the staff.
		* @json_ignore
		*/
		index = 0;
		/**
		* Gets or sets the next bar that comes after this bar.
		* @json_ignore
		*/
		nextBar = null;
		/**
		* Gets or sets the previous bar that comes before this bar.
		* @json_ignore
		*/
		previousBar = null;
		/**
		* Gets or sets the clef on this bar.
		*/
		clef = Clef.G2;
		/**
		* Gets or sets the ottava applied to the clef.
		*/
		clefOttava = Ottavia.Regular;
		/**
		* Gets or sets the reference to the parent staff.
		* @json_ignore
		*/
		staff;
		/**
		* Gets or sets the list of voices contained in this bar.
		* @json_add addVoice
		*/
		voices = [];
		/**
		* Gets or sets the simile mark on this bar.
		*/
		simileMark = SimileMark.None;
		_filledVoices = new Set([0]);
		/**
		* Gets a value indicating whether this bar contains multiple voices with notes.
		* @json_ignore
		*/
		get isMultiVoice() {
			return this._filledVoices.size > 1;
		}
		/**
		* Gets the number of voices which have content within this stuff.
		* @json_ignore
		*/
		get filledVoices() {
			return this._filledVoices;
		}
		/**
		* 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.
		*/
		displayScale = 1;
		/**
		* An absolute width of the bar to use when displaying in single track display scenarios.
		*/
		displayWidth = -1;
		/**
		* The sustain pedal markers within this bar.
		*/
		sustainPedals = [];
		get masterBar() {
			return this.staff.track.score.masterBars[this.index];
		}
		_isEmpty = true;
		_isRestOnly = true;
		/**
		* 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;
			if (this.keySignature !== this.previousBar.keySignature || this.keySignatureType !== this.previousBar.keySignatureType || this.clef !== this.previousBar.clef || this.clefOttava !== this.previousBar.clefOttava) return true;
			return this.simileMark !== SimileMark.None || this.sustainPedals.length > 0 || this.barLineLeft !== 0 || this.barLineRight !== 0;
		}
		/**
		* 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.
		* @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.
		*/
		barLineLeft = 0;
		/**
		* 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.
		*/
		barLineRight = 0;
		/**
		* Gets or sets the key signature used on all bars.
		*/
		keySignature = KeySignature.C;
		/**
		* Gets or sets the type of key signature (major/minor)
		*/
		keySignatureType = KeySignatureType.Major;
		/**
		* How bar numbers should be displayed.
		* If specified, overrides the value from the stylesheet on score level.
		*/
		barNumberDisplay;
		/**
		* The shortest duration contained across beats in this bar.
		* @internal
		* @json_ignore
		*/
		shortestDuration = Duration.DoubleWhole;
		/**
		* 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.
		*/
		getActualBarLineRight() {
			return Bar._actualBarLine(this, true, false);
		}
		static _automaticToActualType(masterBar, isRight, firstOfSystem) {
			let actualLineType;
			if (isRight) if (masterBar.isRepeatEnd) actualLineType = 6;
			else if (!masterBar.nextMasterBar) actualLineType = 6;
			else if (masterBar.isFreeTime) actualLineType = 1;
			else if (masterBar.isDoubleBar) actualLineType = 7;
			else actualLineType = 9;
			else if (masterBar.isRepeatStart) actualLineType = 5;
			else if (firstOfSystem) actualLineType = 9;
			else actualLineType = 8;
			return actualLineType;
		}
		static _actualBarLine(bar, isRight, firstOfSystem) {
			const masterBar = bar.masterBar;
			const requestedLineType = isRight ? bar.barLineRight : bar.barLineLeft;
			let actualLineType;
			if (requestedLineType === 0) actualLineType = Bar._automaticToActualType(masterBar, isRight, firstOfSystem);
			else actualLineType = requestedLineType;
			return actualLineType;
		}
		/**
		* The style customizations for this item.
		*/
		style;
		addVoice(voice) {
			voice.bar = this;
			voice.index = this.voices.length;
			this.voices.push(voice);
		}
		finish(settings, sharedDataBag = null) {
			this._filledVoices.clear();
			this._filledVoices.add(0);
			this._isEmpty = true;
			this._isRestOnly = true;
			this.shortestDuration = Duration.DoubleWhole;
			for (let i = 0, j = this.voices.length; i < j; i++) {
				const voice = this.voices[i];
				voice.finish(settings, sharedDataBag);
				if (!voice.isEmpty) {
					this._isEmpty = false;
					this._filledVoices.add(i);
					if (voice.shortestDuration > this.shortestDuration) this.shortestDuration = voice.shortestDuration;
				}
				if (!voice.isRestOnly) this._isRestOnly = false;
			}
			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];
					if (previousMarker.pedalType === 2) previousMarker = null;
				}
				const isDown = previousMarker !== null && previousMarker.pedalType !== 2;
				for (const marker of sustainPedals) {
					if (previousMarker && previousMarker.pedalType !== 2) {
						if (previousMarker.bar === this && marker.ratioPosition <= previousMarker.ratioPosition) continue;
						previousMarker.nextPedalMarker = marker;
						marker.previousPedalMarker = previousMarker;
					}
					if (isDown && marker.pedalType === 0) marker.pedalType = 1;
					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 !== 2) {
					const holdMarker = new SustainPedalMarker();
					holdMarker.ratioPosition = 0;
					holdMarker.bar = this;
					holdMarker.pedalType = 1;
					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;
		}
	};
	//#endregion
	//#region src/model/TripletFeel.ts
	/**
	* This public enumeration lists all feels of triplets.
	* @public
	*/
	var TripletFeel = /* @__PURE__ */ function(TripletFeel) {
		/**
		* No triplet feel
		*/
		TripletFeel[TripletFeel["NoTripletFeel"] = 0] = "NoTripletFeel";
		/**
		* Triplet 16th
		*/
		TripletFeel[TripletFeel["Triplet16th"] = 1] = "Triplet16th";
		/**
		* Triplet 8th
		*/
		TripletFeel[TripletFeel["Triplet8th"] = 2] = "Triplet8th";
		/**
		* Dotted 16th
		*/
		TripletFeel[TripletFeel["Dotted16th"] = 3] = "Dotted16th";
		/**
		* Dotted 8th
		*/
		TripletFeel[TripletFeel["Dotted8th"] = 4] = "Dotted8th";
		/**
		* Scottish 16th
		*/
		TripletFeel[TripletFeel["Scottish16th"] = 5] = "Scottish16th";
		/**
		* Scottish 8th
		*/
		TripletFeel[TripletFeel["Scottish8th"] = 6] = "Scottish8th";
		return TripletFeel;
	}({});
	//#endregion
	//#region src/model/MasterBar.ts
	/**
	* Defines the custom beaming rules which define how beats are beamed together or split apart
	* during the automatic beaming when displayed.
	* @json
	* @json_strict
	* @public
	*
	* @remarks
	* The beaming logic works like this:
	*
	* The time axis of the bar is sliced into even chunks. The chunk-size is defined by the respective group definition.
	* Within these chunks groups can then be placed spanning 1 or more chunks.
	*
	* If beats start within the same "group" they are beamed together.
	*/
	var BeamingRules = class BeamingRules {
		_singleGroupKey;
		/**
		* The the group for a given "longest duration" within the bar.
		* @remarks
		* The map key is the duration to which the bar will be sliced into.
		* The map value defines the "groups" placed within the sliced.
		*/
		groups = /* @__PURE__ */ new Map();
		/**
		* @internal
		* @json_ignore
		*/
		uniqueId = "";
		/**
		* @internal
		* @json_ignore
		*/
		timeSignatureNumerator = 0;
		/**
		* @internal
		* @json_ignore
		*/
		timeSignatureDenominator = 0;
		/**
		* @internal
		*/
		static createSimple(timeSignatureNumerator, timeSignatureDenominator, duration, groups) {
			const r = new BeamingRules();
			r.timeSignatureNumerator = timeSignatureNumerator;
			r.timeSignatureDenominator = timeSignatureDenominator;
			r.groups.set(duration, groups);
			r.finish();
			return r;
		}
		/**
		* @internal
		*/
		findRule(shortestDuration) {
			const singleGroupKey = this._singleGroupKey;
			if (singleGroupKey) return [singleGroupKey, this.groups.get(singleGroupKey)];
			if (shortestDuration < Duration.Quarter) return [shortestDuration, []];
			let durationValue = shortestDuration;
			do {
				const duration = durationValue;
				if (this.groups.has(duration)) return [duration, this.groups.get(duration)];
				durationValue = durationValue * 2;
			} while (durationValue <= Duration.TwoHundredFiftySixth);
			durationValue = shortestDuration / 2;
			do {
				const duration = durationValue;
				if (this.groups.has(duration)) return [duration, this.groups.get(duration)];
				durationValue = durationValue / 2;
			} while (durationValue > Duration.Half);
			return [shortestDuration, []];
		}
		/**
		* @internal
		*/
		finish() {
			let uniqueId = `${this.timeSignatureNumerator}_${this.timeSignatureDenominator}`;
			for (const [k, v] of this.groups) {
				uniqueId += `__${k}`;
				let lastZero = v.length;
				for (let i = v.length - 1; i >= 0; i--) if (v[i] === 0) lastZero = i;
				else break;
				if (lastZero < v.length) v.splice(lastZero, v.length - lastZero);
				uniqueId += `_${v.join("_")}`;
				if (this.groups.size === 1) this._singleGroupKey = k;
			}
			this.uniqueId = uniqueId;
		}
	};
	/**
	* The MasterBar stores information about a bar which affects
	* all tracks.
	* @json
	* @json_strict
	* @public
	*/
	var MasterBar = class {
		static MaxAlternateEndings = 8;
		/**
		* Gets or sets the bitflag for the alternate endings. Each bit defines for which repeat counts
		* the bar is played.
		*/
		alternateEndings = 0;
		/**
		* Gets or sets the next masterbar in the song.
		* @json_ignore
		*/
		nextMasterBar = null;
		/**
		* Gets or sets the next masterbar in the song.
		* @json_ignore
		*/
		previousMasterBar = null;
		/**
		* Gets the zero based index of the masterbar.
		* @json_ignore
		*/
		index = 0;
		/**
		* Whether the masterbar is has any changes applied to it (e.g. tempo changes, time signature changes etc)
		* The first bar is always considered changed due to initial setup of values. It does not consider
		* elements like whether the tempo really changes to the previous bar.
		*/
		get hasChanges() {
			if (this.index === 0) return false;
			if (this.timeSignatureCommon !== this.previousMasterBar.timeSignatureCommon || this.timeSignatureNumerator !== this.previousMasterBar.timeSignatureNumerator || this.timeSignatureDenominator !== this.previousMasterBar.timeSignatureDenominator || this.tripletFeel !== this.previousMasterBar.tripletFeel) return true;
			return this.alternateEndings !== 0 || this.isRepeatStart || this.isRepeatEnd || this.isFreeTime || this.isSectionStart || this.tempoAutomations.length > 0 || this.syncPoints && this.syncPoints.length > 0 || this.fermata !== null && this.fermata.size > 0 || this.directions !== null && this.directions.size > 0 || this.isAnacrusis;
		}
		/**
		* The key signature used on all bars.
		* @deprecated Use key signatures on bar level
		*/
		get keySignature() {
			return this.score.tracks[0].staves[0].bars[this.index].keySignature;
		}
		/**
		* The key signature used on all bars.
		* @deprecated Use key signatures on bar level
		*/
		set keySignature(value) {
			this.score.tracks[0].staves[0].bars[this.index].keySignature = value;
		}
		/**
		* The type of key signature (major/minor)
		* @deprecated Use key signatures on bar level
		*/
		get keySignatureType() {
			return this.score.tracks[0].staves[0].bars[this.index].keySignatureType;
		}
		/**
		* The type of key signature (major/minor)
		* @deprecated Use key signatures on bar level
		*/
		set keySignatureType(value) {
			this.score.tracks[0].staves[0].bars[this.index].keySignatureType = value;
		}
		/**
		* Gets or sets whether a double bar is shown for this masterbar.
		* @deprecated Use {@link Bar.barLineLeft} and {@link Bar.barLineRight}
		*/
		isDoubleBar = false;
		/**
		* Gets or sets whether a repeat section starts on this masterbar.
		*/
		isRepeatStart = false;
		get isRepeatEnd() {
			return this.repeatCount > 0;
		}
		/**
		* Gets or sets the number of repeats for the current repeat section.
		*/
		repeatCount = 0;
		/**
		* Gets or sets the repeat group this bar belongs to.
		* @json_ignore
		*/
		repeatGroup;
		/**
		* Gets or sets the time signature numerator.
		*/
		timeSignatureNumerator = 4;
		/**
		* Gets or sets the time signature denominiator.
		*/
		timeSignatureDenominator = 4;
		/**
		* Gets or sets whether this is bar has a common time signature.
		*/
		timeSignatureCommon = false;
		/**
		* Defines the custom beaming rules which should be applied to this bar and all bars following.
		*/
		beamingRules;
		/**
		* The actual (custom) beaming rules to use for this bar if any were specified.
		* @json_ignore
		* @internal
		*/
		actualBeamingRules;
		/**
		* Gets or sets whether the bar indicates a free time playing.
		*/
		isFreeTime = false;
		/**
		* Gets or sets the triplet feel that is valid for this bar.
		*/
		tripletFeel = TripletFeel.NoTripletFeel;
		/**
		* Gets or sets the new section information for this bar.
		*/
		section = null;
		get isSectionStart() {
			return !!this.section;
		}
		/**
		* Gets or sets the first tempo automation for this bar.
		* @deprecated Use {@link tempoAutomations}.
		*/
		get tempoAutomation() {
			return this.tempoAutomations.length > 0 ? this.tempoAutomations[0] : null;
		}
		/**
		* Gets or sets all tempo automation for this bar.
		*/
		tempoAutomations = [];
		/**
		* The sync points for this master bar to synchronize the alphaTab time axis with the
		* external backing track audio.
		* @json_add addSyncPoint
		*/
		syncPoints;
		/**
		* Gets or sets the reference to the score this song belongs to.
		* @json_ignore
		*/
		score;
		/**
		* Gets or sets the fermatas for this bar. The key is the offset of the fermata in midi ticks.
		* @json_add addFermata
		*/
		fermata = null;
		/**
		* The timeline position of the voice within the whole score. (unit: midi ticks)
		*/
		start = 0;
		/**
		* Gets or sets a value indicating whether the master bar is an anacrusis (aka. pickup bar)
		*/
		isAnacrusis = false;
		/**
		* Gets a percentual scale for the size of the bars when displayed in a multi-track layout.
		*/
		displayScale = 1;
		/**
		* An absolute width of the bar to use when displaying in a multi-track layout.
		*/
		displayWidth = -1;
		/**
		* The directions applied to this masterbar.
		* @json_add addDirection
		*/
		directions = null;
		/**
		* Calculates the time spent in this bar. (unit: midi ticks)
		*/
		calculateDuration(respectAnacrusis = true) {
			if (this.isAnacrusis && respectAnacrusis) {
				let duration = 0;
				for (const track of this.score.tracks) for (const staff of track.staves) {
					const barDuration = this.index < staff.bars.length ? staff.bars[this.index].calculateDuration() : 0;
					if (barDuration > duration) duration = barDuration;
				}
				return duration;
			}
			return this.timeSignatureNumerator * MidiUtils.valueToTicks(this.timeSignatureDenominator);
		}
		/**
		* Adds a fermata to the masterbar.
		* @param offset The offset of the fermata within the bar in midi ticks.
		* @param fermata The fermata.
		*/
		addFermata(offset, fermata) {
			let fermataMap = this.fermata;
			if (fermataMap === null) {
				fermataMap = /* @__PURE__ */ new Map();
				this.fermata = fermataMap;
			}
			fermataMap.set(offset, fermata);
		}
		/**
		* Adds a direction to the masterbar.
		* @param direction The direction to add.
		*/
		addDirection(direction) {
			if (this.directions == null) this.directions = /* @__PURE__ */ new Set();
			this.directions.add(direction);
		}
		/**
		* Gets the fermata for a given beat.
		* @param beat The beat to get the fermata for.
		* @returns
		*/
		getFermata(beat) {
			const fermataMap = this.fermata;
			if (fermataMap === null) return null;
			if (fermataMap.has(beat.playbackStart)) return fermataMap.get(beat.playbackStart);
			if (beat.index === 0 && fermataMap.has(0)) return fermataMap.get(0);
			return null;
		}
		/**
		* Adds the given sync point to the list of sync points for this bar.
		* @param syncPoint  The sync point to add.
		*/
		addSyncPoint(syncPoint) {
			if (!this.syncPoints) this.syncPoints = [];
			this.syncPoints.push(syncPoint);
		}
		finish(sharedDataBag) {
			let beamingRules = this.beamingRules;
			if (beamingRules) {
				beamingRules.timeSignatureNumerator = this.timeSignatureNumerator;
				beamingRules.timeSignatureDenominator = this.timeSignatureDenominator;
				beamingRules.finish();
			}
			if (this.index > 0) {
				this.start = this.previousMasterBar.start + this.previousMasterBar.calculateDuration();
				const previousRules = sharedDataBag.has("beamingRules") ? sharedDataBag.get("beamingRules") : void 0;
				if (previousRules && previousRules.uniqueId === beamingRules?.uniqueId) {
					this.beamingRules = void 0;
					beamingRules = previousRules;
				} else if (!beamingRules) beamingRules = previousRules;
			}
			this.actualBeamingRules = beamingRules;
			if (this.beamingRules) sharedDataBag.set("beamingRules", beamingRules);
		}
	};
	//#endregion
	//#region src/model/RenderStylesheet.ts
	/**
	* Lists the different modes on how the brackets/braces are drawn and extended.
	* @public
	*/
	var BracketExtendMode = /* @__PURE__ */ 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";
		return BracketExtendMode;
	}({});
	/**
	* Lists the different policies on how to display the track names.
	* @public
	*/
	var TrackNamePolicy = /* @__PURE__ */ 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";
		return TrackNamePolicy;
	}({});
	/**
	* Lists the different modes what text to display for track names.
	* @public
	*/
	var TrackNameMode = /* @__PURE__ */ 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";
		return TrackNameMode;
	}({});
	/**
	* Lists the different orientations modes how to render the track names.
	* @public
	*/
	var TrackNameOrientation = /* @__PURE__ */ function(TrackNameOrientation) {
		/**
		* Text is shown horizontally (left-to-right)
		*/
		TrackNameOrientation[TrackNameOrientation["Horizontal"] = 0] = "Horizontal";
		/**
		* Vertically rotated (bottom-to-top)
		*/
		TrackNameOrientation[TrackNameOrientation["Vertical"] = 1] = "Vertical";
		return TrackNameOrientation;
	}({});
	/**
	* How bar numbers are displayed
	* @public
	*/
	var BarNumberDisplay = /* @__PURE__ */ function(BarNumberDisplay) {
		/**
		* Show bar numbers on all bars.
		*/
		BarNumberDisplay[BarNumberDisplay["AllBars"] = 0] = "AllBars";
		/**
		* Show bar numbers on the first bar of every system.
		*/
		BarNumberDisplay[BarNumberDisplay["FirstOfSystem"] = 1] = "FirstOfSystem";
		/**
		* Hide all bar numbers
		*/
		BarNumberDisplay[BarNumberDisplay["Hide"] = 2] = "Hide";
		return BarNumberDisplay;
	}({});
	/**
	* This class represents the rendering stylesheet.
	* It contains settings which control the display of the score when rendered.
	* @json
	* @json_strict
	* @public
	*/
	var RenderStylesheet = class {
		/**
		* Whether dynamics are hidden.
		*/
		hideDynamics = false;
		/**
		* The mode in which brackets and braces are drawn.
		*/
		bracketExtendMode = 1;
		/**
		* Whether to draw the // sign to separate systems.
		*/
		useSystemSignSeparator = false;
		/**
		* Whether to show the tuning.
		*/
		globalDisplayTuning = true;
		/**
		* Whether to show the tuning.(per-track)
		*/
		perTrackDisplayTuning = null;
		/**
		* Whether to show the chord diagrams on top.
		*/
		globalDisplayChordDiagramsOnTop = true;
		/**
		* Whether to show the chord diagrams on top. (per-track)
		*/
		perTrackChordDiagramsOnTop = null;
		/**
		* Whether to show the chord diagrams in score.
		*/
		globalDisplayChordDiagramsInScore = false;
		/**
		* The policy where to show track names when a single track is rendered.
		*/
		singleTrackTrackNamePolicy = 1;
		/**
		* The policy where to show track names when a multiple tracks are rendered.
		*/
		multiTrackTrackNamePolicy = 1;
		/**
		* The mode what text to display for the track name on the first system
		*/
		firstSystemTrackNameMode = 1;
		/**
		* The mode what text to display for the track name on the first system
		*/
		otherSystemsTrackNameMode = 1;
		/**
		* The orientation of the the track names on the first system
		*/
		firstSystemTrackNameOrientation = 1;
		/**
		* The orientation of the the track names on other systems
		*/
		otherSystemsTrackNameOrientation = 1;
		/**
		* If multi track: Whether to render multiple subsequent empty (or rest-only) bars together as multi-bar rest.
		*/
		multiTrackMultiBarRest = false;
		/**
		* If single track: Whether to render multiple subsequent empty (or rest-only) bars together as multi-bar rest.
		*/
		perTrackMultiBarRest = null;
		/**
		* Whether barlines should be drawn across staves within the same system.
		*/
		extendBarLines = false;
		/**
		* Whether to hide empty staves.
		*/
		hideEmptyStaves = false;
		/**
		* Whether to also hide empty staves in the first system.
		* @remarks
		* Only has an effect when activating {@link hideEmptyStaves}.
		*/
		hideEmptyStavesInFirstSystem = false;
		/**
		* Whether to show brackets and braces across single staves.
		* @remarks
		* This allows a more consistent view for identifying staves when using
		* {@link hideEmptyStaves}
		*/
		showSingleStaffBrackets = false;
		/**
		* How bar numbers should be displayed.
		*/
		barNumberDisplay = 0;
	};
	//#endregion
	//#region src/model/RepeatGroup.ts
	/**
	* This public class can store the information about a group of measures which are repeated
	* @public
	*/
	var RepeatGroup = class {
		/**
		* All masterbars repeated within this group
		*/
		masterBars = [];
		/**
		* the masterbars which opens the group.
		*/
		opening = null;
		/**
		* 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] : [];
		}
		/**
		* a list of masterbars which close the group.
		*/
		closings = [];
		/**
		* Gets whether this repeat group is really opened as a repeat.
		*/
		get isOpened() {
			return this.opening?.isRepeatStart === true;
		}
		/**
		* true if the repeat group was closed well
		*/
		isClosed = false;
		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;
			}
		}
	};
	//#endregion
	//#region src/model/GraceGroup.ts
	/**
	* Represents a group of grace beats that belong together
	* @public
	*/
	var GraceGroup = class {
		/**
		* All beats within this group.
		*/
		beats = [];
		/**
		* Gets a unique ID for this grace group.
		*/
		id = "empty";
		/**
		* true if the grace beat are followed by a normal beat within the same
		* bar.
		*/
		isComplete = false;
		/**
		* Adds a new beat to this group
		* @param beat The beat to add
		*/
		addBeat(beat) {
			beat.graceIndex = this.beats.length;
			beat.graceGroup = this;
			this.beats.push(beat);
		}
		finish() {
			if (this.beats.length > 0) this.id = `${this.beats[0].absoluteDisplayStart}_${this.beats[0].voice.index}`;
		}
	};
	//#endregion
	//#region src/model/Voice.ts
	/**
	* Lists all graphical sub elements within a {@link Voice} which can be styled via {@link Voice.style}
	* @public
	*/
	var VoiceSubElement = /* @__PURE__ */ function(VoiceSubElement) {
		/**
		* All general glyphs (like notes heads and rests).
		*/
		VoiceSubElement[VoiceSubElement["Glyphs"] = 0] = "Glyphs";
		return VoiceSubElement;
	}({});
	/**
	* Defines the custom styles for voices.
	* @json
	* @json_strict
	* @public
	*/
	var VoiceStyle = class extends ElementStyle {};
	/**
	* A voice represents a group of beats
	* that can be played during a bar.
	* @json
	* @json_strict
	* @public
	*/
	var Voice$1 = class Voice$1 {
		_beatLookup;
		_isEmpty = true;
		_isRestOnly = true;
		static _globalVoiceId = 0;
		/**
		* @internal
		*/
		static resetIds() {
			Voice$1._globalVoiceId = 0;
		}
		/**
		* Gets or sets the unique id of this bar.
		*/
		id = Voice$1._globalVoiceId++;
		/**
		* Gets or sets the zero-based index of this voice within the bar.
		* @json_ignore
		*/
		index = 0;
		/**
		* Gets or sets the reference to the bar this voice belongs to.
		* @json_ignore
		*/
		bar;
		/**
		* Gets or sets the list of beats contained in this voice.
		* @json_add addBeat
		*/
		beats = [];
		/**
		* Gets or sets a value indicating whether this voice is empty.
		*/
		get isEmpty() {
			return this._isEmpty;
		}
		/**
		* The style customizations for this item.
		*/
		style;
		/**
		* @internal
		*/
		forceNonEmpty() {
			this._isEmpty = false;
		}
		/**
		* Gets or sets a value indicating whether this voice is empty.
		*/
		get isRestOnly() {
			return this._isRestOnly;
		}
		/**
		* The shortest duration contained across beats in this bar.
		* @internal
		* @json_ignore
		*/
		shortestDuration = Duration.DoubleWhole;
		insertBeat(after, newBeat) {
			newBeat.nextBeat = after.nextBeat;
			if (newBeat.nextBeat) newBeat.nextBeat.previousBeat = newBeat;
			newBeat.previousBeat = after;
			newBeat.voice = this;
			after.nextBeat = newBeat;
			this.beats.splice(after.index + 1, 0, newBeat);
		}
		addBeat(beat) {
			beat.voice = this;
			beat.index = this.beats.length;
			this.beats.push(beat);
			if (!beat.isEmpty) this._isEmpty = false;
			if (!beat.isRest) this._isRestOnly = false;
		}
		_chain(beat, sharedDataBag = null) {
			if (!this.bar) return;
			if (beat.index < this.beats.length - 1) {
				beat.nextBeat = this.beats[beat.index + 1];
				beat.nextBeat.previousBeat = beat;
			} else if (beat.isLastOfVoice && beat.voice.bar.nextBar) {
				const nextVoice = this.bar.nextBar.voices[this.index];
				if (nextVoice.beats.length > 0) {
					beat.nextBeat = nextVoice.beats[0];
					beat.nextBeat.previousBeat = beat;
				} else beat.nextBeat.previousBeat = beat;
			}
			beat.chain(sharedDataBag);
		}
		addGraceBeat(beat) {
			if (this.beats.length === 0) {
				this.addBeat(beat);
				return;
			}
			const lastBeat = this.beats[this.beats.length - 1];
			this.beats.splice(this.beats.length - 1, 1);
			this.addBeat(beat);
			this.addBeat(lastBeat);
			this._isEmpty = false;
			this._isRestOnly = false;
		}
		getBeatAtPlaybackStart(playbackStart) {
			if (this._beatLookup.has(playbackStart)) return this._beatLookup.get(playbackStart);
			return null;
		}
		finish(settings, sharedDataBag = null) {
			this._isEmpty = true;
			this._isRestOnly = true;
			this._beatLookup = /* @__PURE__ */ new Map();
			let currentGraceGroup = null;
			for (let index = 0; index < this.beats.length; index++) {
				const beat = this.beats[index];
				beat.index = index;
				this._chain(beat, sharedDataBag);
				if (beat.graceType === GraceType.None) {
					beat.graceGroup = currentGraceGroup;
					if (currentGraceGroup) currentGraceGroup.isComplete = true;
					currentGraceGroup = null;
				} else {
					if (!currentGraceGroup) currentGraceGroup = new GraceGroup();
					currentGraceGroup.addBeat(beat);
				}
				if (!beat.isEmpty) this._isEmpty = false;
				if (!beat.isRest) this._isRestOnly = false;
			}
			let currentDisplayTick = 0;
			let currentPlaybackTick = 0;
			this.shortestDuration = Duration.DoubleWhole;
			for (let i = 0; i < this.beats.length; i++) {
				const beat = this.beats[i];
				beat.index = i;
				beat.finish(settings, sharedDataBag);
				if (beat.graceType === GraceType.None) {
					if (beat.duration > this.shortestDuration) this.shortestDuration = beat.duration;
					if (beat.graceGroup) {
						const firstGraceBeat = beat.graceGroup.beats[0];
						const lastGraceBeat = beat.graceGroup.beats[beat.graceGroup.beats.length - 1];
						if (firstGraceBeat.graceType !== GraceType.BendGrace) {
							const stolenDuration = lastGraceBeat.playbackStart + lastGraceBeat.playbackDuration - firstGraceBeat.playbackStart;
							switch (firstGraceBeat.graceType) {
								case GraceType.BeforeBeat:
									if (firstGraceBeat.previousBeat) {
										firstGraceBeat.previousBeat.playbackDuration -= stolenDuration;
										if (firstGraceBeat.previousBeat.voice === this) currentPlaybackTick = firstGraceBeat.previousBeat.playbackStart + firstGraceBeat.previousBeat.playbackDuration;
										else currentPlaybackTick = -stolenDuration;
									} else currentPlaybackTick = -stolenDuration;
									for (const graceBeat of beat.graceGroup.beats) {
										this._beatLookup.delete(graceBeat.playbackStart);
										graceBeat.playbackStart = currentPlaybackTick;
										this._beatLookup.set(graceBeat.playbackStart, beat);
										currentPlaybackTick += graceBeat.playbackDuration;
									}
									break;
								case GraceType.OnBeat:
									beat.playbackDuration -= stolenDuration;
									if (lastGraceBeat.voice === this) currentPlaybackTick = lastGraceBeat.playbackStart + lastGraceBeat.playbackDuration;
									else currentPlaybackTick = -stolenDuration;
									break;
							}
						}
					}
					beat.displayStart = currentDisplayTick;
					beat.playbackStart = currentPlaybackTick;
					this._beatLookup.set(beat.playbackStart, beat);
				} else {
					beat.displayStart = currentDisplayTick;
					beat.playbackStart = currentPlaybackTick;
				}
				if (beat.fermata) this.bar.masterBar.addFermata(beat.playbackStart, beat.fermata);
				else beat.fermata = this.bar.masterBar.getFermata(beat);
				beat.finishTuplet();
				if (beat.graceGroup) beat.graceGroup.finish();
				currentDisplayTick += beat.displayDuration;
				currentPlaybackTick += beat.playbackDuration;
			}
		}
		calculateDuration() {
			if (this.isEmpty || this.beats.length === 0) return 0;
			const lastBeat = this.beats[this.beats.length - 1];
			const firstBeat = this.beats[0];
			return lastBeat.playbackStart + lastBeat.playbackDuration - firstBeat.playbackStart;
		}
	};
	//#endregion
	//#region src/platform/ICanvas.ts
	/**
	* This public enum lists all different text alignments
	* @public
	*/
	var TextAlign = /* @__PURE__ */ function(TextAlign) {
		/**
		* Text is left aligned.
		*/
		TextAlign[TextAlign["Left"] = 0] = "Left";
		/**
		* Text is centered.
		*/
		TextAlign[TextAlign["Center"] = 1] = "Center";
		/**
		* Text is right aligned.
		*/
		TextAlign[TextAlign["Right"] = 2] = "Right";
		return TextAlign;
	}({});
	/**
	* This public enum lists all base line modes
	* @public
	*/
	var TextBaseline = /* @__PURE__ */ function(TextBaseline) {
		/**
		* Text is aligned on top.
		*/
		TextBaseline[TextBaseline["Top"] = 0] = "Top";
		/**
		* Text is aligned middle
		*/
		TextBaseline[TextBaseline["Middle"] = 1] = "Middle";
		/**
		* Text is aligned on the bottom.
		*/
		TextBaseline[TextBaseline["Bottom"] = 2] = "Bottom";
		/**
		* Text is aligned on the alphabetic baseline.
		*/
		TextBaseline[TextBaseline["Alphabetic"] = 3] = "Alphabetic";
		return TextBaseline;
	}({});
	/**
	* The MeasuredText class represents the dimensions of a piece of text in the canvas;
	* @public
	*/
	var MeasuredText = class {
		/**
		* Returns the width of a segment of inline text in CSS pixels.
		*/
		width;
		/**
		* Returns the height of a segment of inline text in CSS pixels.
		*/
		height;
		constructor(width, height) {
			this.width = width;
			this.height = height;
		}
	};
	/**
	* @internal
	*/
	var CanvasHelper = class {
		static fillMusicFontSymbolSafe(canvas, x, y, relativeScale, symbol, centerAtPosition) {
			if (!canvas.settings.display.resources.engravingSettings.hasSymbol(symbol)) return;
			canvas.fillMusicFontSymbol(x, y, relativeScale, symbol, centerAtPosition);
		}
		static fillMusicFontSymbolsSafe(canvas, x, y, relativeScale, symbols, centerAtPosition) {
			const symbolsToDraw = symbols.filter((s) => canvas.settings.display.resources.engravingSettings.hasSymbol(s));
			if (symbolsToDraw.length === 0) return;
			canvas.fillMusicFontSymbols(x, y, relativeScale, symbolsToDraw, centerAtPosition);
		}
	};
	//#endregion
	//#region src/model/Score.ts
	/**
	* Lists all graphical sub elements within a {@link Score} which can be styled via {@link Score.style}
	* @public
	*/
	var ScoreSubElement = /* @__PURE__ */ function(ScoreSubElement) {
		/**
		* The title of the song
		*/
		ScoreSubElement[ScoreSubElement["Title"] = 0] = "Title";
		/**
		* The subtitle of the song
		*/
		ScoreSubElement[ScoreSubElement["SubTitle"] = 1] = "SubTitle";
		/**
		* The artist of the song
		*/
		ScoreSubElement[ScoreSubElement["Artist"] = 2] = "Artist";
		/**
		* The album of the song
		*/
		ScoreSubElement[ScoreSubElement["Album"] = 3] = "Album";
		/**
		* The word author of the song
		*/
		ScoreSubElement[ScoreSubElement["Words"] = 4] = "Words";
		/**
		* The Music author of the song
		*/
		ScoreSubElement[ScoreSubElement["Music"] = 5] = "Music";
		/**
		* The Words&Music author of the song
		*/
		ScoreSubElement[ScoreSubElement["WordsAndMusic"] = 6] = "WordsAndMusic";
		/**
		* The transcriber of the music sheet
		*/
		ScoreSubElement[ScoreSubElement["Transcriber"] = 7] = "Transcriber";
		/**
		* The copyright holder of the song
		*/
		ScoreSubElement[ScoreSubElement["Copyright"] = 8] = "Copyright";
		/**
		* The second copyright line (typically something like 'All Rights Reserved')
		*/
		ScoreSubElement[ScoreSubElement["CopyrightSecondLine"] = 9] = "CopyrightSecondLine";
		/**
		* The chord diagram list shown on top of the score.
		*/
		ScoreSubElement[ScoreSubElement["ChordDiagramList"] = 10] = "ChordDiagramList";
		return ScoreSubElement;
	}({});
	/**
	* The additional style and display information for header and footer elements.
	* @json
	* @json_strict
	* @public
	*/
	var HeaderFooterStyle = class HeaderFooterStyle {
		/**
		* The template how the text should be formatted. Following placeholders exist and are filled from the song information:
		* * `%TITLE%`
		* * `%SUBTITLE%`
		* * `%ARTIST%`
		* * `%ALBUM%`
		* * `%WORDS%`
		* * `%WORDSMUSIC%`
		* * `%MUSIC%`
		* * `%TABBER%`
		* * `%COPYRIGHT%`
		*/
		template;
		/**
		* Whether the element should be visible. Overriden by {@link NotationSettings.elements} if specified.
		*/
		isVisible;
		/**
		* The alignment of the element on the page.
		*/
		textAlign;
		constructor(template = "", isVisible = void 0, textAlign = TextAlign.Left) {
			this.template = template;
			this.isVisible = isVisible;
			this.textAlign = textAlign;
		}
		static equals(a, b) {
			if ((a.isVisible !== void 0 ? a.isVisible : true) !== (b.isVisible !== void 0 ? b.isVisible : true)) return false;
			if (a.template !== b.template) return false;
			if (a.textAlign !== b.textAlign) return false;
			return true;
		}
		buildText(score) {
			let anyPlaceholderFilled = false;
			let anyPlaceholder = false;
			const replaced = this.template.replace(HeaderFooterStyle._placeholderPattern, (_match, variable) => {
				anyPlaceholder = true;
				let value = "";
				switch (variable) {
					case "TITLE":
						value = score.title;
						break;
					case "SUBTITLE":
						value = score.subTitle;
						break;
					case "ARTIST":
						value = score.artist;
						break;
					case "ALBUM":
						value = score.album;
						break;
					case "WORDS":
					case "WORDSMUSIC":
						value = score.words;
						break;
					case "MUSIC":
						value = score.music;
						break;
					case "TABBER":
						value = score.tab;
						break;
					case "COPYRIGHT":
						value = score.copyright;
						break;
					default:
						value = "";
						break;
				}
				if (value) anyPlaceholderFilled = true;
				return value;
			});
			if (anyPlaceholder && !anyPlaceholderFilled) return "";
			return replaced;
		}
		static _placeholderPattern = /%([^%]+)%/g;
	};
	/**
	* Defines the custom styles for Scores.
	* @json
	* @json_strict
	* @public
	*/
	var ScoreStyle = class extends ElementStyle {
		/**
		* Changes additional style aspects fo the of the specified sub-element.
		*/
		headerAndFooter = /* @__PURE__ */ new Map();
		/**
		* The default styles applied to headers and footers if not specified
		*/
		static defaultHeaderAndFooter = new Map([
			[0, new HeaderFooterStyle("%TITLE%", void 0, TextAlign.Center)],
			[1, new HeaderFooterStyle("%SUBTITLE%", void 0, TextAlign.Center)],
			[2, new HeaderFooterStyle("%ARTIST%", void 0, TextAlign.Center)],
			[3, new HeaderFooterStyle("%ALBUM%", void 0, TextAlign.Center)],
			[4, new HeaderFooterStyle("Words by %WORDS%", void 0, TextAlign.Left)],
			[5, new HeaderFooterStyle("Music by %MUSIC%", void 0, TextAlign.Right)],
			[6, new HeaderFooterStyle("Words & Music by %MUSIC%", void 0, TextAlign.Right)],
			[7, new HeaderFooterStyle("Tabbed by %TABBER%", false, TextAlign.Right)],
			[8, new HeaderFooterStyle("%COPYRIGHT%", void 0, TextAlign.Center)],
			[9, new HeaderFooterStyle("All Rights Reserved - International Copyright Secured", true, TextAlign.Center)]
		]);
	};
	/**
	* The score is the root node of the complete
	* model. It stores the basic information of
	* a song and stores the sub components.
	* @json
	* @json_strict
	* @public
	*/
	var Score = class {
		_currentRepeatGroup = null;
		_openedRepeatGroups = [];
		_properlyOpenedRepeatGroups = 0;
		/**
		* Resets all internal ID generators.
		*/
		static resetIds() {
			Bar.resetIds();
			Beat.resetIds();
			Voice$1.resetIds();
			Note.resetIds();
		}
		/**
		* The album of this song.
		*/
		album = "";
		/**
		* The artist who performs this song.
		*/
		artist = "";
		/**
		* The owner of the copyright of this song.
		*/
		copyright = "";
		/**
		* Additional instructions
		*/
		instructions = "";
		/**
		* The author of the music.
		*/
		music = "";
		/**
		* Some additional notes about the song.
		*/
		notices = "";
		/**
		* The subtitle of the song.
		*/
		subTitle = "";
		/**
		* The title of the song.
		*/
		title = "";
		/**
		* The author of the song lyrics
		*/
		words = "";
		/**
		* The author of this tablature.
		*/
		tab = "";
		/**
		* The initial tempo of the song in BPM. The tempo might change via {@link MasterBar.tempoAutomations}.
		*/
		get tempo() {
			return this.masterBars.length && this.masterBars[0].tempoAutomations.length > 0 ? this.masterBars[0].tempoAutomations[0].value : 120;
		}
		/**
		* The name/label of the initial tempo.
		*/
		get tempoLabel() {
			return this.masterBars.length && this.masterBars[0].tempoAutomations.length > 0 ? this.masterBars[0].tempoAutomations[0].text : "";
		}
		/**
		* Gets or sets a list of all masterbars contained in this song.
		* @json_add addMasterBar
		*/
		masterBars = [];
		/**
		* Gets or sets a list of all tracks contained in this song.
		* @json_add addTrack
		*/
		tracks = [];
		/**
		* Defines how many bars are placed into the systems (rows) when displaying
		* multiple tracks unless a value is set in the systemsLayout.
		*/
		defaultSystemsLayout = 3;
		/**
		* Defines how many bars are placed into the systems (rows) when displaying
		* multiple tracks.
		*/
		systemsLayout = [];
		/**
		* Gets or sets the rendering stylesheet for this song.
		*/
		stylesheet = new RenderStylesheet();
		/**
		* Information about the backing track that can be used instead of the synthesized audio.
		*/
		backingTrack;
		/**
		* The style customizations for this item.
		*/
		style;
		rebuildRepeatGroups() {
			this._currentRepeatGroup = null;
			this._openedRepeatGroups = [];
			this._properlyOpenedRepeatGroups = 0;
			for (const bar of this.masterBars) this._addMasterBarToRepeatGroups(bar);
		}
		addMasterBar(bar) {
			bar.score = this;
			bar.index = this.masterBars.length;
			if (this.masterBars.length !== 0) {
				bar.previousMasterBar = this.masterBars[this.masterBars.length - 1];
				bar.previousMasterBar.nextMasterBar = bar;
				bar.start = bar.previousMasterBar.start + (bar.previousMasterBar.isAnacrusis ? 0 : bar.previousMasterBar.calculateDuration());
			}
			this._addMasterBarToRepeatGroups(bar);
			this.masterBars.push(bar);
		}
		/**
		* Adds the given bar correctly into the current repeat group setup.
		* @param bar
		*/
		_addMasterBarToRepeatGroups(bar) {
			if (bar.isRepeatStart) {
				if (this._currentRepeatGroup?.isClosed) {
					this._openedRepeatGroups.pop();
					this._properlyOpenedRepeatGroups--;
				}
				this._currentRepeatGroup = new RepeatGroup();
				this._openedRepeatGroups.push(this._currentRepeatGroup);
				this._properlyOpenedRepeatGroups++;
			} else if (!this._currentRepeatGroup) {
				this._currentRepeatGroup = new RepeatGroup();
				this._openedRepeatGroups.push(this._currentRepeatGroup);
			}
			this._currentRepeatGroup.addMasterBar(bar);
			if (bar.isRepeatEnd) {
				if (this._properlyOpenedRepeatGroups > 1) {
					this._openedRepeatGroups.pop();
					this._properlyOpenedRepeatGroups--;
					this._currentRepeatGroup = this._openedRepeatGroups.length > 0 ? this._openedRepeatGroups[this._openedRepeatGroups.length - 1] : null;
				}
			}
		}
		addTrack(track) {
			track.score = this;
			track.index = this.tracks.length;
			this.tracks.push(track);
		}
		finish(settings) {
			const sharedDataBag = /* @__PURE__ */ new Map();
			for (let i = 0, j = this.tracks.length; i < j; i++) this.tracks[i].finish(settings, sharedDataBag);
			for (const mb of this.masterBars) mb.finish(sharedDataBag);
		}
		/**
		* Applies the given list of {@link FlatSyncPoint} to this song.
		* @param syncPoints The list of sync points to apply.
		* @since 1.6.0
		*/
		applyFlatSyncPoints(syncPoints) {
			for (const b of this.masterBars) b.syncPoints = void 0;
			for (const syncPoint of syncPoints) {
				const automation = new Automation();
				automation.ratioPosition = Math.min(1, Math.max(0, syncPoint.barPosition));
				automation.type = AutomationType.SyncPoint;
				automation.syncPointValue = new SyncPointData();
				automation.syncPointValue.millisecondOffset = syncPoint.millisecondOffset;
				automation.syncPointValue.barOccurence = syncPoint.barOccurence;
				if (syncPoint.barIndex < this.masterBars.length) this.masterBars[syncPoint.barIndex].addSyncPoint(automation);
			}
			for (const b of this.masterBars) if (b.syncPoints) b.syncPoints.sort((a, b) => {
				const occurence = a.syncPointValue.barOccurence - b.syncPointValue.barOccurence;
				if (occurence !== 0) return occurence;
				return a.ratioPosition - b.ratioPosition;
			});
		}
		/**
		* Exports all sync points in this song to a {@link FlatSyncPoint} list.
		* @since 1.6.0
		*/
		exportFlatSyncPoints() {
			const syncPoints = [];
			for (const masterBar of this.masterBars) {
				const masterBarSyncPoints = masterBar.syncPoints;
				if (masterBarSyncPoints) for (const syncPoint of masterBarSyncPoints) syncPoints.push({
					barIndex: masterBar.index,
					barOccurence: syncPoint.syncPointValue.barOccurence,
					barPosition: syncPoint.ratioPosition,
					millisecondOffset: syncPoint.syncPointValue.millisecondOffset
				});
			}
			return syncPoints;
		}
	};
	//#endregion
	//#region src/synth/SynthConstants.ts
	/**
	* @internal
	*/
	var SynthConstants = class SynthConstants {
		static DefaultChannelCount = 17;
		static MetronomeKey = 33;
		static AudioChannels = 2;
		static MinVolume = 0;
		static MinProgram = 0;
		static MaxProgram = 127;
		static MinPlaybackSpeed = .125;
		static MaxPlaybackSpeed = 8;
		static PercussionChannel = 9;
		static PercussionBank = 128;
		/**
		* The Midi Pitch bend message is a 15-bit value
		*/
		static MaxPitchWheel = 16384;
		/**
		* The Midi 2.0 Pitch bend message is a 32-bit value
		*/
		static MaxPitchWheel20 = 4294967296;
		/**
		* The pitch wheel value for no pitch change at all.
		*/
		static DefaultPitchWheel = SynthConstants.MaxPitchWheel / 2;
		static MicroBufferCount = 32;
		static MicroBufferSize = 64;
		/**
		* approximately -60 dB, which is inaudible to humans
		*/
		static AudibleLevelThreshold = .001;
	};
	//#endregion
	//#region src/model/ModelUtils.ts
	/**
	* @internal
	*/
	var TuningParseResult = class {
		note = null;
		tone = new TuningParseResultTone();
		octave = 0;
		get realValue() {
			return this.octave * 12 + this.tone.noteValue;
		}
	};
	/**
	* @internal
	*/
	var TuningParseResultTone = class {
		noteValue;
		accidentalMode;
		constructor(noteValue = 0, accidentalMode = NoteAccidentalMode.Default) {
			this.noteValue = noteValue;
			this.accidentalMode = accidentalMode;
		}
	};
	/**
	* This public class contains some utilities for working with model public classes
	* @partial
	* @internal
	*/
	var ModelUtils = class ModelUtils {
		static _durationIndices = ModelUtils._buildDurationIndices();
		static _buildDurationIndices() {
			return new Map(Object.values(Duration).filter((k) => typeof k === "number").map((d) => [d, d < 0 ? 0 : Math.log2(d) | 0]));
		}
		static getIndex(duration) {
			return ModelUtils._durationIndices.get(duration);
		}
		static keySignatureIsFlat(ks) {
			return ks < 0;
		}
		static keySignatureIsNatural(ks) {
			return ks === 0;
		}
		static keySignatureIsSharp(ks) {
			return ks > 0;
		}
		static applyPitchOffsets(settings, score) {
			for (let i = 0; i < score.tracks.length; i++) {
				if (i < settings.notation.displayTranspositionPitches.length) for (const staff of score.tracks[i].staves) staff.displayTranspositionPitch = -settings.notation.displayTranspositionPitches[i];
				if (i < settings.notation.transpositionPitches.length) for (const staff of score.tracks[i].staves) staff.transpositionPitch = -settings.notation.transpositionPitches[i];
			}
		}
		/**
		* Checks if the given string is a tuning inticator.
		* @param name
		*/
		static isTuning(name) {
			return !!ModelUtils.parseTuning(name);
		}
		/**
		* @internal
		*/
		static tuningLetters = new Set([
			67,
			68,
			69,
			70,
			71,
			65,
			66,
			99,
			100,
			101,
			102,
			103,
			97,
			98,
			35
		]);
		static parseTuning(name) {
			let note = "";
			let octave = "";
			for (let i = 0; i < name.length; i++) {
				const c = name.charCodeAt(i);
				if (c >= 48 && c <= 57) {
					if (!note) return null;
					octave += String.fromCharCode(c);
				} else if (note.length === 0) if (ModelUtils.tuningLetters.has(c)) note += String.fromCharCode(c);
				else return null;
				else note += String.fromCharCode(c);
			}
			if (!octave || !note) return null;
			const result = new TuningParseResult();
			result.octave = Number.parseInt(octave, 10) + 1;
			result.note = note.toLowerCase();
			const tone = ModelUtils.getToneForText(result.note);
			if (tone === null) return null;
			result.tone = tone;
			if (result.tone.noteValue < 0) {
				result.octave--;
				result.tone.noteValue += 12;
			}
			return result;
		}
		static getTuningForText(str) {
			const result = ModelUtils.parseTuning(str);
			if (!result) return -1;
			return result.realValue;
		}
		static getToneForText(note) {
			const noteName = note.substring(0, 1);
			const accidental = note.substring(1);
			let noteValue;
			let noteAccidenalMode;
			switch (noteName.toLowerCase()) {
				case "c":
					noteValue = 0;
					break;
				case "d":
					noteValue = 2;
					break;
				case "e":
					noteValue = 4;
					break;
				case "f":
					noteValue = 5;
					break;
				case "g":
					noteValue = 7;
					break;
				case "a":
					noteValue = 9;
					break;
				case "b":
					noteValue = 11;
					break;
				default: return null;
			}
			if (!ModelUtils.accidentalModeMapping.has(accidental)) return null;
			noteAccidenalMode = ModelUtils.parseAccidentalMode(accidental);
			switch (noteAccidenalMode) {
				case NoteAccidentalMode.Default: break;
				case NoteAccidentalMode.ForceNone: break;
				case NoteAccidentalMode.ForceNatural: break;
				case NoteAccidentalMode.ForceSharp:
					noteValue++;
					break;
				case NoteAccidentalMode.ForceDoubleSharp:
					noteValue += 2;
					break;
				case NoteAccidentalMode.ForceFlat:
					noteValue--;
					break;
				case NoteAccidentalMode.ForceDoubleFlat:
					noteValue -= 2;
					break;
			}
			return new TuningParseResultTone(noteValue, noteAccidenalMode);
		}
		/**
		* @internal
		*/
		static reverseAccidentalModeMapping = new Map([
			[NoteAccidentalMode.Default, "d"],
			[NoteAccidentalMode.ForceNone, "forcenone"],
			[NoteAccidentalMode.ForceNatural, "forcenatural"],
			[NoteAccidentalMode.ForceSharp, "#"],
			[NoteAccidentalMode.ForceDoubleSharp, "x"],
			[NoteAccidentalMode.ForceFlat, "b"],
			[NoteAccidentalMode.ForceDoubleFlat, "bb"]
		]);
		/**
		* @internal
		*/
		static accidentalModeMapping = new Map([
			["default", NoteAccidentalMode.Default],
			["d", NoteAccidentalMode.Default],
			["", NoteAccidentalMode.Default],
			["forcenone", NoteAccidentalMode.ForceNone],
			["-", NoteAccidentalMode.ForceNone],
			["forcenatural", NoteAccidentalMode.ForceNatural],
			["n", NoteAccidentalMode.ForceNatural],
			["forcesharp", NoteAccidentalMode.ForceSharp],
			["#", NoteAccidentalMode.ForceSharp],
			["forcedoublesharp", NoteAccidentalMode.ForceDoubleSharp],
			["##", NoteAccidentalMode.ForceDoubleSharp],
			["x", NoteAccidentalMode.ForceDoubleSharp],
			["forceflat", NoteAccidentalMode.ForceFlat],
			["b", NoteAccidentalMode.ForceFlat],
			["forcedoubleflat", NoteAccidentalMode.ForceDoubleFlat],
			["bb", NoteAccidentalMode.ForceDoubleFlat]
		]);
		static parseAccidentalMode(data) {
			const key = data.toLowerCase();
			if (ModelUtils.accidentalModeMapping.has(key)) return ModelUtils.accidentalModeMapping.get(key);
			return NoteAccidentalMode.Default;
		}
		static newGuid() {
			return `${Math.floor((1 + Math.random()) * 65536).toString(16).substring(1) + Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)}-${Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)}-${Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)}-${Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)}-${Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)}${Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)}${Math.floor((1 + Math.random()) * 65536).toString(16).substring(1)}`;
		}
		static isAlmostEqualTo(a, b) {
			return Math.abs(a - b) < 1e-5;
		}
		static toHexString(n, digits = 0) {
			let s = "";
			const hexChars = "0123456789ABCDEF";
			do {
				s = String.fromCharCode(hexChars.charCodeAt(n & 15)) + s;
				n = n >> 4;
			} while (n > 0);
			while (s.length < digits) s = `0${s}`;
			return s;
		}
		/**
		* Gets the list of alternate endings on which the master bar is played.
		* @param bitflag The alternate endings bitflag.
		*/
		static getAlternateEndingsList(bitflag) {
			const endings = [];
			for (let i = 0; i < MasterBar.MaxAlternateEndings; i++) if ((bitflag & 1 << i) !== 0) endings.push(i);
			return endings;
		}
		static deltaFretToHarmonicValue(deltaFret) {
			switch (deltaFret) {
				case 2: return 2.4;
				case 3: return 3.2;
				case 4:
				case 5:
				case 7:
				case 9:
				case 12:
				case 16:
				case 17:
				case 19:
				case 24: return deltaFret;
				case 8: return 8.2;
				case 10: return 9.6;
				case 14:
				case 15: return 14.7;
				case 21:
				case 22: return 21.7;
				default: return 12;
			}
		}
		static clamp(value, min, max) {
			if (value <= min) return min;
			if (value >= max) return max;
			return value;
		}
		static buildMultiBarRestInfo(tracks, startIndex, endIndexInclusive) {
			if (!tracks) return null;
			const stylesheet = tracks[0].score.stylesheet;
			if (!(tracks.length > 1 ? stylesheet.multiTrackMultiBarRest : stylesheet.perTrackMultiBarRest?.has(tracks[0].index) === true)) return null;
			const lookup = /* @__PURE__ */ new Map();
			const score = tracks[0].score;
			let currentIndex = startIndex;
			let tempo = score.tempo;
			while (currentIndex <= endIndexInclusive) {
				const currentGroupStartIndex = currentIndex;
				let currentGroup = null;
				while (currentIndex <= endIndexInclusive) {
					const masterBar = score.masterBars[currentIndex];
					let hasTempoChange = false;
					for (const a of masterBar.tempoAutomations) {
						if (a.value !== tempo) hasTempoChange = true;
						tempo = a.value;
					}
					if (masterBar.alternateEndings || masterBar.isRepeatStart && masterBar.index !== currentGroupStartIndex || masterBar.isFreeTime || masterBar.isAnacrusis || masterBar.section !== null || masterBar.index !== currentGroupStartIndex && hasTempoChange || masterBar.fermata !== null && masterBar.fermata.size > 0 || masterBar.directions !== null && masterBar.directions.size > 0) break;
					if (currentGroupStartIndex > startIndex && masterBar.previousMasterBar && (masterBar.timeSignatureCommon !== masterBar.previousMasterBar.timeSignatureCommon || masterBar.timeSignatureNumerator !== masterBar.previousMasterBar.timeSignatureNumerator || masterBar.timeSignatureDenominator !== masterBar.previousMasterBar.timeSignatureDenominator || masterBar.tripletFeel !== masterBar.previousMasterBar.tripletFeel)) break;
					let areAllBarsSuitable = true;
					for (const t of tracks) {
						for (const s of t.staves) {
							const bar = s.bars[masterBar.index];
							if (!bar.isRestOnly) {
								areAllBarsSuitable = false;
								break;
							}
							if (bar.index > 0 && (bar.keySignature !== bar.previousBar.keySignature || bar.keySignatureType !== bar.previousBar.keySignatureType)) {
								areAllBarsSuitable = false;
								break;
							}
						}
						if (!areAllBarsSuitable) break;
					}
					if (!areAllBarsSuitable) break;
					currentIndex++;
					if (masterBar.index > currentGroupStartIndex) if (currentGroup === null) currentGroup = [masterBar.index];
					else currentGroup.push(masterBar.index);
					if (masterBar.isRepeatEnd) break;
				}
				if (currentGroup) lookup.set(currentGroupStartIndex, currentGroup);
				else currentIndex++;
			}
			return lookup;
		}
		static computeFirstDisplayedBarIndex(score, settings) {
			let startIndex = settings.display.startBar;
			startIndex--;
			startIndex = Math.min(score.masterBars.length - 1, Math.max(0, startIndex));
			return startIndex;
		}
		static computeLastDisplayedBarIndex(score, settings, startIndex) {
			let endBarIndex = settings.display.barCount;
			if (endBarIndex < 0) endBarIndex = score.masterBars.length;
			endBarIndex = startIndex + endBarIndex - 1;
			endBarIndex = Math.min(score.masterBars.length - 1, Math.max(0, endBarIndex));
			return endBarIndex;
		}
		static getOrCreateHeaderFooterStyle(score, element) {
			let style = score.style;
			if (!score.style) {
				style = new ScoreStyle();
				score.style = style;
			}
			let headerFooterStyle;
			if (style.headerAndFooter.has(element)) headerFooterStyle = style.headerAndFooter.get(element);
			else {
				headerFooterStyle = new HeaderFooterStyle();
				if (ScoreStyle.defaultHeaderAndFooter.has(element)) {
					const defaults = ScoreStyle.defaultHeaderAndFooter.get(element);
					headerFooterStyle.template = defaults.template;
					headerFooterStyle.textAlign = defaults.textAlign;
				}
				style.headerAndFooter.set(element, headerFooterStyle);
			}
			return headerFooterStyle;
		}
		/**
		* Performs some general consolidations of inconsistencies on the given score like
		* missing bars, beats, duplicated midi channels etc
		*/
		static consolidate(score) {
			if (score.masterBars.length === 0) {
				const master = new MasterBar();
				score.addMasterBar(master);
				const tempoAutomation = new Automation();
				tempoAutomation.isLinear = false;
				tempoAutomation.type = AutomationType.Tempo;
				tempoAutomation.value = score.tempo;
				master.tempoAutomations.push(tempoAutomation);
				const bar = new Bar();
				score.tracks[0].staves[0].addBar(bar);
				const v = new Voice$1();
				bar.addVoice(v);
				const emptyBeat = new Beat();
				emptyBeat.isEmpty = true;
				v.addBeat(emptyBeat);
				return;
			}
			const usedChannels = new Set([SynthConstants.PercussionChannel]);
			for (const track of score.tracks) {
				if (track.staves.length === 1 && track.staves[0].isPercussion) {
					track.playbackInfo.primaryChannel = SynthConstants.PercussionChannel;
					track.playbackInfo.secondaryChannel = SynthConstants.PercussionChannel;
				} else {
					if (track.playbackInfo.primaryChannel !== SynthConstants.PercussionChannel) while (usedChannels.has(track.playbackInfo.primaryChannel)) track.playbackInfo.primaryChannel++;
					usedChannels.add(track.playbackInfo.primaryChannel);
					if (track.playbackInfo.secondaryChannel !== SynthConstants.PercussionChannel) while (usedChannels.has(track.playbackInfo.secondaryChannel)) track.playbackInfo.secondaryChannel++;
					usedChannels.add(track.playbackInfo.secondaryChannel);
				}
				for (const staff of track.staves) {
					for (const b of staff.bars) for (const v of b.voices) if (v.isEmpty && v.beats.length === 0) {
						const emptyBeat = new Beat();
						emptyBeat.isEmpty = true;
						v.addBeat(emptyBeat);
					}
					const voiceCount = staff.bars.length === 0 ? 1 : staff.bars[0].voices.length;
					while (staff.bars.length < score.masterBars.length) {
						const bar = new Bar();
						staff.addBar(bar);
						const previousBar = bar.previousBar;
						if (previousBar) {
							bar.clef = previousBar.clef;
							bar.clefOttava = previousBar.clefOttava;
							bar.keySignature = bar.previousBar.keySignature;
							bar.keySignatureType = bar.previousBar.keySignatureType;
						}
						for (let i = 0; i < voiceCount; i++) {
							const v = new Voice$1();
							bar.addVoice(v);
							const emptyBeat = new Beat();
							emptyBeat.isEmpty = true;
							v.addBeat(emptyBeat);
						}
					}
				}
			}
			if (score.masterBars.length > 0) {
				if (!score.masterBars[0].tempoAutomations.find((a) => a.type === AutomationType.Tempo && a.ratioPosition === 0)) {
					const tempoAutomation = new Automation();
					tempoAutomation.isLinear = false;
					tempoAutomation.type = AutomationType.Tempo;
					tempoAutomation.value = score.tempo;
					tempoAutomation.text = score.tempoLabel;
					tempoAutomation.isVisible = false;
					score.masterBars[0].tempoAutomations.push(tempoAutomation);
				}
			}
		}
		/**
		* Trims any empty bars at the end of the song.
		* @param score
		*/
		static trimEmptyBarsAtEnd(score) {
			while (score.masterBars.length > 1) {
				const barIndex = score.masterBars.length - 1;
				const masterBar = score.masterBars[barIndex];
				if (masterBar.hasChanges) return;
				for (const track of score.tracks) for (const staff of track.staves) if (barIndex < staff.bars.length) {
					const bar = staff.bars[barIndex];
					if (!bar.isEmpty || bar.hasChanges) return;
				}
				for (const track of score.tracks) for (const staff of track.staves) if (barIndex < staff.bars.length) {
					const bar = staff.bars[barIndex];
					staff.bars.pop();
					bar.previousBar.nextBar = null;
				}
				score.masterBars.pop();
				masterBar.previousMasterBar.nextMasterBar = null;
			}
		}
		/**
		* Lists the display transpositions for some known midi instruments.
		* It is a common practice to transpose the standard notation for instruments like guitars.
		*/
		static displayTranspositionPitches = new Map([
			[24, -12],
			[25, -12],
			[26, -12],
			[27, -12],
			[28, -12],
			[29, -12],
			[30, -12],
			[31, -12],
			[32, -12],
			[33, -12],
			[34, -12],
			[35, -12],
			[36, -12],
			[37, -12],
			[38, -12],
			[39, -12],
			[43, -12]
		]);
		/**
		* @internal
		*/
		static flooredDivision(a, b) {
			return a - b * Math.floor(a / b);
		}
		/**
		* Converts the key transpose table to actual key signatures.
		* @param texts An array where every item indicates the number of accidentals and which accidental
		* placed for the key signature.
		*
		* e.g. 3# is 3-sharps -> KeySignature.A
		*/
		static _translateKeyTransposeTable(texts) {
			const keySignatures = [];
			for (const transpose of texts) {
				const transposeValues = [];
				keySignatures.push(transposeValues);
				for (const keySignatureText of transpose) {
					const keySignature = Number.parseInt(keySignatureText.charAt(0), 10) * (keySignatureText.charAt(1) === "b" ? -1 : 1);
					transposeValues.push(keySignature);
				}
			}
			return keySignatures;
		}
		/**
		* @internal
		*/
		static _keyTransposeTable = ModelUtils._translateKeyTransposeTable([
			[
				"7b",
				"6b",
				"5b",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#",
				"6#",
				"7#"
			],
			[
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#",
				"6#",
				"7#",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#"
			],
			[
				"3#",
				"4#",
				"7b",
				"6b",
				"5b",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#"
			],
			[
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#",
				"6#",
				"7#",
				"4b",
				"3b",
				"2b"
			],
			[
				"1#",
				"2#",
				"3#",
				"4#",
				"7b",
				"6b",
				"5b",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#"
			],
			[
				"6b",
				"5b",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#",
				"6#",
				"7#",
				"4b"
			],
			[
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"7b",
				"6#",
				"7#",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#"
			],
			[
				"4#",
				"7b",
				"6b",
				"5b",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#",
				"6#"
			],
			[
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#",
				"6#",
				"7#",
				"4b",
				"3b",
				"2b",
				"1b"
			],
			[
				"2#",
				"3#",
				"4#",
				"7b",
				"6b",
				"5b",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#"
			],
			[
				"5b",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"5#",
				"6#",
				"7#",
				"4b",
				"3b"
			],
			[
				"0#",
				"1#",
				"2#",
				"3#",
				"4#",
				"7b",
				"6b",
				"6#",
				"4b",
				"3b",
				"2b",
				"1b",
				"0#",
				"1#",
				"2#"
			]
		]);
		/**
		* Transposes the given key signature.
		* @internal
		* @param keySignature The key signature to transpose
		* @param transpose The number of semitones to transpose (+/- 0-11)
		* @returns
		*/
		static transposeKey(keySignature, transpose) {
			if (transpose === 0) return keySignature;
			if (transpose < 0) {
				const keySignatureIndex = ModelUtils._keyTransposeTable[-transpose].indexOf(keySignature);
				if (keySignatureIndex === -1) return keySignature;
				return keySignatureIndex - 7;
			} else return ModelUtils._keyTransposeTable[transpose][keySignature + 7];
		}
		/**
		* @internal
		*/
		static toArticulationId(plain) {
			return plain.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
		}
		static minBoundingBox(a, b) {
			if (Number.isNaN(a)) return b;
			else if (Number.isNaN(b)) return a;
			return a < b ? a : b;
		}
		static maxBoundingBox(a, b) {
			if (Number.isNaN(a)) return b;
			else if (Number.isNaN(b)) return a;
			return a > b ? a : b;
		}
		static getSystemLayout(score, systemIndex, displayedTracks) {
			let defaultSystemsLayout;
			let systemsLayout;
			if (displayedTracks.length === 1) {
				defaultSystemsLayout = displayedTracks[0].defaultSystemsLayout;
				systemsLayout = displayedTracks[0].systemsLayout;
			} else {
				defaultSystemsLayout = score.defaultSystemsLayout;
				systemsLayout = score.systemsLayout;
			}
			return systemIndex < systemsLayout.length ? systemsLayout[systemIndex] : defaultSystemsLayout;
		}
		static _degreeSemitones = [
			0,
			2,
			4,
			5,
			7,
			9,
			11
		];
		static _sharpPreferredSpellings = [
			{
				degree: 0,
				accidentalOffset: 0
			},
			{
				degree: 0,
				accidentalOffset: 1
			},
			{
				degree: 1,
				accidentalOffset: 0
			},
			{
				degree: 1,
				accidentalOffset: 1
			},
			{
				degree: 2,
				accidentalOffset: 0
			},
			{
				degree: 3,
				accidentalOffset: 0
			},
			{
				degree: 3,
				accidentalOffset: 1
			},
			{
				degree: 4,
				accidentalOffset: 0
			},
			{
				degree: 4,
				accidentalOffset: 1
			},
			{
				degree: 5,
				accidentalOffset: 0
			},
			{
				degree: 5,
				accidentalOffset: 1
			},
			{
				degree: 6,
				accidentalOffset: 0
			}
		];
		static _flatPreferredSpellings = [
			{
				degree: 0,
				accidentalOffset: 0
			},
			{
				degree: 1,
				accidentalOffset: -1
			},
			{
				degree: 1,
				accidentalOffset: 0
			},
			{
				degree: 2,
				accidentalOffset: -1
			},
			{
				degree: 2,
				accidentalOffset: 0
			},
			{
				degree: 3,
				accidentalOffset: 0
			},
			{
				degree: 4,
				accidentalOffset: -1
			},
			{
				degree: 4,
				accidentalOffset: 0
			},
			{
				degree: 5,
				accidentalOffset: -1
			},
			{
				degree: 5,
				accidentalOffset: 0
			},
			{
				degree: 6,
				accidentalOffset: -1
			},
			{
				degree: 6,
				accidentalOffset: 0
			}
		];
		static _spellingCandidates = [
			[
				{
					degree: 0,
					accidentalOffset: 0
				},
				{
					degree: 1,
					accidentalOffset: -2
				},
				{
					degree: 6,
					accidentalOffset: 1
				}
			],
			[
				{
					degree: 0,
					accidentalOffset: 1
				},
				{
					degree: 1,
					accidentalOffset: -1
				},
				{
					degree: 6,
					accidentalOffset: 2
				}
			],
			[
				{
					degree: 1,
					accidentalOffset: 0
				},
				{
					degree: 0,
					accidentalOffset: 2
				},
				{
					degree: 2,
					accidentalOffset: -2
				}
			],
			[
				{
					degree: 1,
					accidentalOffset: 1
				},
				{
					degree: 2,
					accidentalOffset: -1
				},
				{
					degree: 3,
					accidentalOffset: -2
				}
			],
			[
				{
					degree: 2,
					accidentalOffset: 0
				},
				{
					degree: 1,
					accidentalOffset: 2
				},
				{
					degree: 3,
					accidentalOffset: -1
				}
			],
			[
				{
					degree: 3,
					accidentalOffset: 0
				},
				{
					degree: 2,
					accidentalOffset: 1
				},
				{
					degree: 4,
					accidentalOffset: -2
				}
			],
			[
				{
					degree: 3,
					accidentalOffset: 1
				},
				{
					degree: 4,
					accidentalOffset: -1
				},
				{
					degree: 2,
					accidentalOffset: 2
				}
			],
			[
				{
					degree: 4,
					accidentalOffset: 0
				},
				{
					degree: 3,
					accidentalOffset: 2
				},
				{
					degree: 5,
					accidentalOffset: -2
				}
			],
			[{
				degree: 4,
				accidentalOffset: 1
			}, {
				degree: 5,
				accidentalOffset: -1
			}],
			[
				{
					degree: 5,
					accidentalOffset: 0
				},
				{
					degree: 4,
					accidentalOffset: 2
				},
				{
					degree: 6,
					accidentalOffset: -2
				}
			],
			[
				{
					degree: 5,
					accidentalOffset: 1
				},
				{
					degree: 6,
					accidentalOffset: -1
				},
				{
					degree: 0,
					accidentalOffset: -2
				}
			],
			[
				{
					degree: 6,
					accidentalOffset: 0
				},
				{
					degree: 5,
					accidentalOffset: 2
				},
				{
					degree: 0,
					accidentalOffset: -1
				}
			]
		];
		static _sharpKeySignatureOrder = [
			3,
			0,
			4,
			1,
			5,
			2,
			6
		];
		static _flatKeySignatureOrder = [
			6,
			2,
			5,
			1,
			4,
			0,
			3
		];
		static _keySignatureAccidentalByDegree = ModelUtils._buildKeySignatureAccidentalByDegree();
		static _accidentalOffsetToType = new Map([
			[-2, AccidentalType.DoubleFlat],
			[-1, AccidentalType.Flat],
			[0, AccidentalType.Natural],
			[1, AccidentalType.Sharp],
			[2, AccidentalType.DoubleSharp]
		]);
		static _forcedAccidentalOffsetByMode = new Map([
			[NoteAccidentalMode.ForceSharp, 1],
			[NoteAccidentalMode.ForceDoubleSharp, 2],
			[NoteAccidentalMode.ForceFlat, -1],
			[NoteAccidentalMode.ForceDoubleFlat, -2],
			[NoteAccidentalMode.ForceNatural, 0],
			[NoteAccidentalMode.ForceNone, 0],
			[NoteAccidentalMode.Default, NaN]
		]);
		static _buildKeySignatureAccidentalByDegree() {
			const lookup = [];
			for (let ks = -7; ks <= 7; ks++) {
				const row = [
					0,
					0,
					0,
					0,
					0,
					0,
					0
				];
				if (ks > 0) for (let i = 0; i < ks; i++) row[ModelUtils._sharpKeySignatureOrder[i]] = 1;
				else if (ks < 0) for (let i = 0; i < -ks; i++) row[ModelUtils._flatKeySignatureOrder[i]] = -1;
				lookup.push(row);
			}
			return lookup;
		}
		static getKeySignatureAccidentalOffset(keySignature, degree) {
			return ModelUtils._keySignatureAccidentalByDegree[keySignature + 7][degree];
		}
		static resolveSpelling(keySignature, noteValue, accidentalMode) {
			const chroma = ModelUtils.flooredDivision(noteValue, 12);
			const preferred = ModelUtils._getPreferredSpellingForKeySignature(keySignature, chroma);
			const desiredOffset = ModelUtils._forcedAccidentalOffsetByMode.has(accidentalMode) ? ModelUtils._forcedAccidentalOffsetByMode.get(accidentalMode) : NaN;
			let spelling = preferred;
			if (!Number.isNaN(desiredOffset)) {
				const exact = ModelUtils._spellingCandidates[chroma].find((c) => c.accidentalOffset === desiredOffset);
				if (exact) spelling = exact;
			}
			const baseSemitone = ModelUtils._degreeSemitones[spelling.degree] + spelling.accidentalOffset;
			const octave = Math.floor((noteValue - baseSemitone) / 12) - 1;
			return {
				degree: spelling.degree,
				accidentalOffset: spelling.accidentalOffset,
				chroma,
				octave
			};
		}
		static computeAccidental(keySignature, accidentalMode, noteValue, quarterBend, currentAccidentalOffset = null) {
			const spelling = ModelUtils.resolveSpelling(keySignature, noteValue, accidentalMode);
			return ModelUtils.computeAccidentalForSpelling(keySignature, accidentalMode, spelling, quarterBend, currentAccidentalOffset);
		}
		static computeAccidentalForSpelling(keySignature, accidentalMode, spelling, quarterBend, currentAccidentalOffset = null) {
			if (accidentalMode === NoteAccidentalMode.ForceNone) return AccidentalType.None;
			if (quarterBend) {
				if (spelling.accidentalOffset > 0) return AccidentalType.SharpQuarterNoteUp;
				if (spelling.accidentalOffset < 0) return AccidentalType.FlatQuarterNoteUp;
				return AccidentalType.NaturalQuarterNoteUp;
			}
			const desiredOffset = spelling.accidentalOffset;
			const ksOffset = ModelUtils.getKeySignatureAccidentalOffset(keySignature, spelling.degree);
			if (currentAccidentalOffset === desiredOffset) return AccidentalType.None;
			if (currentAccidentalOffset == null && desiredOffset === ksOffset) return AccidentalType.None;
			return ModelUtils.accidentalOffsetToType(desiredOffset);
		}
		static accidentalOffsetToType(offset) {
			return ModelUtils._accidentalOffsetToType.has(offset) ? ModelUtils._accidentalOffsetToType.get(offset) : AccidentalType.None;
		}
		static _getPreferredSpellingForKeySignature(keySignature, chroma) {
			const ksMatch = ModelUtils._spellingCandidates[chroma].find((c) => ModelUtils.getKeySignatureAccidentalOffset(keySignature, c.degree) === c.accidentalOffset);
			if (ksMatch) return ksMatch;
			return ModelUtils.keySignatureIsFlat(keySignature) ? ModelUtils._flatPreferredSpellings[chroma] : ModelUtils._sharpPreferredSpellings[chroma];
		}
		static _majorKeySignatureTonicDegrees = [
			0,
			4,
			1,
			5,
			2,
			6,
			3,
			0,
			4,
			1,
			5,
			2,
			6,
			3,
			0
		];
		static _minorKeySignatureTonicDegrees = [
			5,
			2,
			6,
			3,
			0,
			4,
			1,
			5,
			2,
			6,
			3,
			0,
			4,
			1,
			5
		];
		static getKeySignatureTonicDegree(keySignature, keySignatureType) {
			const ksi = keySignature + 7;
			return keySignatureType === KeySignatureType.Minor ? ModelUtils._minorKeySignatureTonicDegrees[ksi] : ModelUtils._majorKeySignatureTonicDegrees[ksi];
		}
	};
	//#endregion
	//#region src/model/PickStroke.ts
	/**
	* Lists all types of pick strokes.
	* @public
	*/
	var PickStroke = /* @__PURE__ */ function(PickStroke) {
		/**
		* No pickstroke used.
		*/
		PickStroke[PickStroke["None"] = 0] = "None";
		/**
		* Pickstroke up.
		*/
		PickStroke[PickStroke["Up"] = 1] = "Up";
		/**
		* Pickstroke down
		*/
		PickStroke[PickStroke["Down"] = 2] = "Down";
		return PickStroke;
	}({});
	//#endregion
	//#region src/model/MusicFontSymbol.ts
	/**
	* Lists all music font symbols used within alphaTab. The names
	* and values are aligned with the SMuFL standard.
	* @public
	*/
	var MusicFontSymbol = /* @__PURE__ */ function(MusicFontSymbol) {
		MusicFontSymbol[MusicFontSymbol["None"] = -1] = "None";
		MusicFontSymbol[MusicFontSymbol["Space"] = 32] = "Space";
		MusicFontSymbol[MusicFontSymbol["Brace"] = 57344] = "Brace";
		MusicFontSymbol[MusicFontSymbol["BracketTop"] = 57347] = "BracketTop";
		MusicFontSymbol[MusicFontSymbol["BracketBottom"] = 57348] = "BracketBottom";
		MusicFontSymbol[MusicFontSymbol["SystemDivider"] = 57351] = "SystemDivider";
		MusicFontSymbol[MusicFontSymbol["GClef"] = 57424] = "GClef";
		MusicFontSymbol[MusicFontSymbol["GClef15mb"] = 57425] = "GClef15mb";
		MusicFontSymbol[MusicFontSymbol["GClef8vb"] = 57426] = "GClef8vb";
		MusicFontSymbol[MusicFontSymbol["GClef8va"] = 57427] = "GClef8va";
		MusicFontSymbol[MusicFontSymbol["GClef15ma"] = 57428] = "GClef15ma";
		MusicFontSymbol[MusicFontSymbol["CClef"] = 57436] = "CClef";
		MusicFontSymbol[MusicFontSymbol["CClef8vb"] = 57437] = "CClef8vb";
		MusicFontSymbol[MusicFontSymbol["FClef"] = 57442] = "FClef";
		MusicFontSymbol[MusicFontSymbol["FClef15mb"] = 57443] = "FClef15mb";
		MusicFontSymbol[MusicFontSymbol["FClef8vb"] = 57444] = "FClef8vb";
		MusicFontSymbol[MusicFontSymbol["FClef8va"] = 57445] = "FClef8va";
		MusicFontSymbol[MusicFontSymbol["FClef15ma"] = 57446] = "FClef15ma";
		MusicFontSymbol[MusicFontSymbol["UnpitchedPercussionClef1"] = 57449] = "UnpitchedPercussionClef1";
		MusicFontSymbol[MusicFontSymbol["SixStringTabClef"] = 57453] = "SixStringTabClef";
		MusicFontSymbol[MusicFontSymbol["FourStringTabClef"] = 57454] = "FourStringTabClef";
		MusicFontSymbol[MusicFontSymbol["Clef8"] = 57469] = "Clef8";
		MusicFontSymbol[MusicFontSymbol["Clef15"] = 57470] = "Clef15";
		MusicFontSymbol[MusicFontSymbol["TimeSig0"] = 57472] = "TimeSig0";
		MusicFontSymbol[MusicFontSymbol["TimeSig1"] = 57473] = "TimeSig1";
		MusicFontSymbol[MusicFontSymbol["TimeSig2"] = 57474] = "TimeSig2";
		MusicFontSymbol[MusicFontSymbol["TimeSig3"] = 57475] = "TimeSig3";
		MusicFontSymbol[MusicFontSymbol["TimeSig4"] = 57476] = "TimeSig4";
		MusicFontSymbol[MusicFontSymbol["TimeSig5"] = 57477] = "TimeSig5";
		MusicFontSymbol[MusicFontSymbol["TimeSig6"] = 57478] = "TimeSig6";
		MusicFontSymbol[MusicFontSymbol["TimeSig7"] = 57479] = "TimeSig7";
		MusicFontSymbol[MusicFontSymbol["TimeSig8"] = 57480] = "TimeSig8";
		MusicFontSymbol[MusicFontSymbol["TimeSig9"] = 57481] = "TimeSig9";
		MusicFontSymbol[MusicFontSymbol["TimeSigCommon"] = 57482] = "TimeSigCommon";
		MusicFontSymbol[MusicFontSymbol["TimeSigCutCommon"] = 57483] = "TimeSigCutCommon";
		MusicFontSymbol[MusicFontSymbol["NoteheadDoubleWholeSquare"] = 57505] = "NoteheadDoubleWholeSquare";
		MusicFontSymbol[MusicFontSymbol["NoteheadDoubleWhole"] = 57504] = "NoteheadDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadWhole"] = 57506] = "NoteheadWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadHalf"] = 57507] = "NoteheadHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadBlack"] = 57508] = "NoteheadBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadNull"] = 57509] = "NoteheadNull";
		MusicFontSymbol[MusicFontSymbol["NoteheadXOrnate"] = 57514] = "NoteheadXOrnate";
		MusicFontSymbol[MusicFontSymbol["NoteheadPlusDoubleWhole"] = 57516] = "NoteheadPlusDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadPlusWhole"] = 57517] = "NoteheadPlusWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadPlusHalf"] = 57518] = "NoteheadPlusHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadPlusBlack"] = 57519] = "NoteheadPlusBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadSquareWhite"] = 57528] = "NoteheadSquareWhite";
		MusicFontSymbol[MusicFontSymbol["NoteheadSquareBlack"] = 57529] = "NoteheadSquareBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleUpDoubleWhole"] = 57530] = "NoteheadTriangleUpDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleUpWhole"] = 57531] = "NoteheadTriangleUpWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleUpHalf"] = 57532] = "NoteheadTriangleUpHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleUpBlack"] = 57534] = "NoteheadTriangleUpBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleRightWhite"] = 57537] = "NoteheadTriangleRightWhite";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleRightBlack"] = 57538] = "NoteheadTriangleRightBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleDownDoubleWhole"] = 57548] = "NoteheadTriangleDownDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleDownWhole"] = 57540] = "NoteheadTriangleDownWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleDownHalf"] = 57541] = "NoteheadTriangleDownHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadTriangleDownBlack"] = 57543] = "NoteheadTriangleDownBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadDiamondDoubleWhole"] = 57559] = "NoteheadDiamondDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadDiamondWhole"] = 57560] = "NoteheadDiamondWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadDiamondHalf"] = 57561] = "NoteheadDiamondHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadDiamondBlack"] = 57563] = "NoteheadDiamondBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadDiamondBlackWide"] = 57564] = "NoteheadDiamondBlackWide";
		MusicFontSymbol[MusicFontSymbol["NoteheadDiamondWhite"] = 57565] = "NoteheadDiamondWhite";
		MusicFontSymbol[MusicFontSymbol["NoteheadDiamondWhiteWide"] = 57566] = "NoteheadDiamondWhiteWide";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircleXDoubleWhole"] = 57520] = "NoteheadCircleXDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircleXWhole"] = 57521] = "NoteheadCircleXWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircleXHalf"] = 57522] = "NoteheadCircleXHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircleX"] = 57523] = "NoteheadCircleX";
		MusicFontSymbol[MusicFontSymbol["NoteheadXDoubleWhole"] = 57510] = "NoteheadXDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadXWhole"] = 57511] = "NoteheadXWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadXHalf"] = 57512] = "NoteheadXHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadXBlack"] = 57513] = "NoteheadXBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadParenthesis"] = 57550] = "NoteheadParenthesis";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedBlack1"] = 57551] = "NoteheadSlashedBlack1";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedBlack2"] = 57552] = "NoteheadSlashedBlack2";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedHalf1"] = 57553] = "NoteheadSlashedHalf1";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedHalf2"] = 57554] = "NoteheadSlashedHalf2";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedWhole1"] = 57555] = "NoteheadSlashedWhole1";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedWhole2"] = 57556] = "NoteheadSlashedWhole2";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedDoubleWhole1"] = 57557] = "NoteheadSlashedDoubleWhole1";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashedDoubleWhole2"] = 57558] = "NoteheadSlashedDoubleWhole2";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircledBlack"] = 57572] = "NoteheadCircledBlack";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircledHalf"] = 57573] = "NoteheadCircledHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircledWhole"] = 57574] = "NoteheadCircledWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircledDoubleWhole"] = 57575] = "NoteheadCircledDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadCircleSlash"] = 57591] = "NoteheadCircleSlash";
		MusicFontSymbol[MusicFontSymbol["NoteheadHeavyX"] = 57592] = "NoteheadHeavyX";
		MusicFontSymbol[MusicFontSymbol["NoteheadHeavyXHat"] = 57593] = "NoteheadHeavyXHat";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashHorizontalEnds"] = 57601] = "NoteheadSlashHorizontalEnds";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashWhiteWhole"] = 57602] = "NoteheadSlashWhiteWhole";
		MusicFontSymbol[MusicFontSymbol["NoteheadSlashWhiteHalf"] = 57603] = "NoteheadSlashWhiteHalf";
		MusicFontSymbol[MusicFontSymbol["NoteheadRoundWhiteWithDot"] = 57621] = "NoteheadRoundWhiteWithDot";
		MusicFontSymbol[MusicFontSymbol["NoteheadSquareBlackLarge"] = 57626] = "NoteheadSquareBlackLarge";
		MusicFontSymbol[MusicFontSymbol["NoteheadSquareBlackWhite"] = 57627] = "NoteheadSquareBlackWhite";
		MusicFontSymbol[MusicFontSymbol["NoteheadClusterDoubleWhole3rd"] = 57640] = "NoteheadClusterDoubleWhole3rd";
		MusicFontSymbol[MusicFontSymbol["NoteheadClusterWhole3rd"] = 57641] = "NoteheadClusterWhole3rd";
		MusicFontSymbol[MusicFontSymbol["NoteheadClusterHalf3rd"] = 57642] = "NoteheadClusterHalf3rd";
		MusicFontSymbol[MusicFontSymbol["NoteheadClusterQuarter3rd"] = 57643] = "NoteheadClusterQuarter3rd";
		MusicFontSymbol[MusicFontSymbol["NoteShapeRoundWhite"] = 57776] = "NoteShapeRoundWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeRoundBlack"] = 57777] = "NoteShapeRoundBlack";
		MusicFontSymbol[MusicFontSymbol["NoteShapeSquareWhite"] = 57778] = "NoteShapeSquareWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeSquareBlack"] = 57779] = "NoteShapeSquareBlack";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleRightWhite"] = 57780] = "NoteShapeTriangleRightWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleRightBlack"] = 57781] = "NoteShapeTriangleRightBlack";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleLeftWhite"] = 57782] = "NoteShapeTriangleLeftWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleLeftBlack"] = 57783] = "NoteShapeTriangleLeftBlack";
		MusicFontSymbol[MusicFontSymbol["NoteShapeDiamondWhite"] = 57784] = "NoteShapeDiamondWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeDiamondBlack"] = 57785] = "NoteShapeDiamondBlack";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleUpWhite"] = 57786] = "NoteShapeTriangleUpWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleUpBlack"] = 57787] = "NoteShapeTriangleUpBlack";
		MusicFontSymbol[MusicFontSymbol["NoteShapeMoonWhite"] = 57788] = "NoteShapeMoonWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeMoonBlack"] = 57789] = "NoteShapeMoonBlack";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleRoundWhite"] = 57790] = "NoteShapeTriangleRoundWhite";
		MusicFontSymbol[MusicFontSymbol["NoteShapeTriangleRoundBlack"] = 57791] = "NoteShapeTriangleRoundBlack";
		MusicFontSymbol[MusicFontSymbol["NoteQuarterUp"] = 57813] = "NoteQuarterUp";
		MusicFontSymbol[MusicFontSymbol["Note8thUp"] = 57815] = "Note8thUp";
		MusicFontSymbol[MusicFontSymbol["MetNoteQuarterUp"] = 60581] = "MetNoteQuarterUp";
		MusicFontSymbol[MusicFontSymbol["MetNote8thUp"] = 60583] = "MetNote8thUp";
		MusicFontSymbol[MusicFontSymbol["MetAugmentationDot"] = 60599] = "MetAugmentationDot";
		MusicFontSymbol[MusicFontSymbol["ArrowheadBlackUp"] = 60280] = "ArrowheadBlackUp";
		MusicFontSymbol[MusicFontSymbol["ArrowheadBlackDown"] = 60284] = "ArrowheadBlackDown";
		MusicFontSymbol[MusicFontSymbol["AugmentationDot"] = 57831] = "AugmentationDot";
		MusicFontSymbol[MusicFontSymbol["TextBlackNoteLongStem"] = 57841] = "TextBlackNoteLongStem";
		MusicFontSymbol[MusicFontSymbol["TextBlackNoteFrac8thLongStem"] = 57843] = "TextBlackNoteFrac8thLongStem";
		MusicFontSymbol[MusicFontSymbol["TextBlackNoteFrac16thLongStem"] = 57845] = "TextBlackNoteFrac16thLongStem";
		MusicFontSymbol[MusicFontSymbol["TextBlackNoteFrac32ndLongStem"] = 57846] = "TextBlackNoteFrac32ndLongStem";
		MusicFontSymbol[MusicFontSymbol["TextCont8thBeamLongStem"] = 57848] = "TextCont8thBeamLongStem";
		MusicFontSymbol[MusicFontSymbol["TextCont16thBeamLongStem"] = 57850] = "TextCont16thBeamLongStem";
		MusicFontSymbol[MusicFontSymbol["TextCont32ndBeamLongStem"] = 57851] = "TextCont32ndBeamLongStem";
		MusicFontSymbol[MusicFontSymbol["TextAugmentationDot"] = 57852] = "TextAugmentationDot";
		MusicFontSymbol[MusicFontSymbol["TextTupletBracketStartLongStem"] = 57857] = "TextTupletBracketStartLongStem";
		MusicFontSymbol[MusicFontSymbol["TextTuplet3LongStem"] = 57858] = "TextTuplet3LongStem";
		MusicFontSymbol[MusicFontSymbol["TextTupletBracketEndLongStem"] = 57859] = "TextTupletBracketEndLongStem";
		MusicFontSymbol[MusicFontSymbol["Tremolo1"] = 57888] = "Tremolo1";
		MusicFontSymbol[MusicFontSymbol["Tremolo2"] = 57889] = "Tremolo2";
		MusicFontSymbol[MusicFontSymbol["Tremolo3"] = 57890] = "Tremolo3";
		MusicFontSymbol[MusicFontSymbol["Tremolo4"] = 57891] = "Tremolo4";
		MusicFontSymbol[MusicFontSymbol["Tremolo5"] = 57892] = "Tremolo5";
		MusicFontSymbol[MusicFontSymbol["BuzzRoll"] = 57898] = "BuzzRoll";
		MusicFontSymbol[MusicFontSymbol["Flag8thUp"] = 57920] = "Flag8thUp";
		MusicFontSymbol[MusicFontSymbol["Flag8thDown"] = 57921] = "Flag8thDown";
		MusicFontSymbol[MusicFontSymbol["Flag16thUp"] = 57922] = "Flag16thUp";
		MusicFontSymbol[MusicFontSymbol["Flag16thDown"] = 57923] = "Flag16thDown";
		MusicFontSymbol[MusicFontSymbol["Flag32ndUp"] = 57924] = "Flag32ndUp";
		MusicFontSymbol[MusicFontSymbol["Flag32ndDown"] = 57925] = "Flag32ndDown";
		MusicFontSymbol[MusicFontSymbol["Flag64thUp"] = 57926] = "Flag64thUp";
		MusicFontSymbol[MusicFontSymbol["Flag64thDown"] = 57927] = "Flag64thDown";
		MusicFontSymbol[MusicFontSymbol["Flag128thUp"] = 57928] = "Flag128thUp";
		MusicFontSymbol[MusicFontSymbol["Flag128thDown"] = 57929] = "Flag128thDown";
		MusicFontSymbol[MusicFontSymbol["Flag256thUp"] = 57930] = "Flag256thUp";
		MusicFontSymbol[MusicFontSymbol["Flag256thDown"] = 57931] = "Flag256thDown";
		MusicFontSymbol[MusicFontSymbol["AccidentalFlat"] = 57952] = "AccidentalFlat";
		MusicFontSymbol[MusicFontSymbol["AccidentalNatural"] = 57953] = "AccidentalNatural";
		MusicFontSymbol[MusicFontSymbol["AccidentalSharp"] = 57954] = "AccidentalSharp";
		MusicFontSymbol[MusicFontSymbol["AccidentalDoubleSharp"] = 57955] = "AccidentalDoubleSharp";
		MusicFontSymbol[MusicFontSymbol["AccidentalDoubleFlat"] = 57956] = "AccidentalDoubleFlat";
		MusicFontSymbol[MusicFontSymbol["AccidentalQuarterToneFlatArrowUp"] = 57968] = "AccidentalQuarterToneFlatArrowUp";
		MusicFontSymbol[MusicFontSymbol["AccidentalQuarterToneSharpNaturalArrowUp"] = 57970] = "AccidentalQuarterToneSharpNaturalArrowUp";
		MusicFontSymbol[MusicFontSymbol["AccidentalThreeQuarterTonesSharpArrowUp"] = 57972] = "AccidentalThreeQuarterTonesSharpArrowUp";
		MusicFontSymbol[MusicFontSymbol["RepeatDot"] = 57412] = "RepeatDot";
		MusicFontSymbol[MusicFontSymbol["Segno"] = 57415] = "Segno";
		MusicFontSymbol[MusicFontSymbol["Coda"] = 57416] = "Coda";
		MusicFontSymbol[MusicFontSymbol["ArticAccentAbove"] = 58528] = "ArticAccentAbove";
		MusicFontSymbol[MusicFontSymbol["ArticAccentBelow"] = 58529] = "ArticAccentBelow";
		MusicFontSymbol[MusicFontSymbol["ArticStaccatoAbove"] = 58530] = "ArticStaccatoAbove";
		MusicFontSymbol[MusicFontSymbol["ArticStaccatoBelow"] = 58531] = "ArticStaccatoBelow";
		MusicFontSymbol[MusicFontSymbol["ArticTenutoAbove"] = 58532] = "ArticTenutoAbove";
		MusicFontSymbol[MusicFontSymbol["ArticTenutoBelow"] = 58533] = "ArticTenutoBelow";
		MusicFontSymbol[MusicFontSymbol["ArticMarcatoAbove"] = 58540] = "ArticMarcatoAbove";
		MusicFontSymbol[MusicFontSymbol["ArticMarcatoBelow"] = 58541] = "ArticMarcatoBelow";
		MusicFontSymbol[MusicFontSymbol["FermataAbove"] = 58560] = "FermataAbove";
		MusicFontSymbol[MusicFontSymbol["FermataShortAbove"] = 58564] = "FermataShortAbove";
		MusicFontSymbol[MusicFontSymbol["FermataLongAbove"] = 58566] = "FermataLongAbove";
		MusicFontSymbol[MusicFontSymbol["RestLonga"] = 58593] = "RestLonga";
		MusicFontSymbol[MusicFontSymbol["RestDoubleWhole"] = 58594] = "RestDoubleWhole";
		MusicFontSymbol[MusicFontSymbol["RestWhole"] = 58595] = "RestWhole";
		MusicFontSymbol[MusicFontSymbol["RestHalf"] = 58596] = "RestHalf";
		MusicFontSymbol[MusicFontSymbol["RestQuarter"] = 58597] = "RestQuarter";
		MusicFontSymbol[MusicFontSymbol["Rest8th"] = 58598] = "Rest8th";
		MusicFontSymbol[MusicFontSymbol["Rest16th"] = 58599] = "Rest16th";
		MusicFontSymbol[MusicFontSymbol["Rest32nd"] = 58600] = "Rest32nd";
		MusicFontSymbol[MusicFontSymbol["Rest64th"] = 58601] = "Rest64th";
		MusicFontSymbol[MusicFontSymbol["Rest128th"] = 58602] = "Rest128th";
		MusicFontSymbol[MusicFontSymbol["Rest256th"] = 58603] = "Rest256th";
		MusicFontSymbol[MusicFontSymbol["RestHBarLeft"] = 58607] = "RestHBarLeft";
		MusicFontSymbol[MusicFontSymbol["RestHBarMiddle"] = 58608] = "RestHBarMiddle";
		MusicFontSymbol[MusicFontSymbol["RestHBarRight"] = 58609] = "RestHBarRight";
		MusicFontSymbol[MusicFontSymbol["Repeat1Bar"] = 58624] = "Repeat1Bar";
		MusicFontSymbol[MusicFontSymbol["Repeat2Bars"] = 58625] = "Repeat2Bars";
		MusicFontSymbol[MusicFontSymbol["Ottava"] = 58640] = "Ottava";
		MusicFontSymbol[MusicFontSymbol["OttavaAlta"] = 58641] = "OttavaAlta";
		MusicFontSymbol[MusicFontSymbol["OttavaBassaVb"] = 58652] = "OttavaBassaVb";
		MusicFontSymbol[MusicFontSymbol["Quindicesima"] = 58644] = "Quindicesima";
		MusicFontSymbol[MusicFontSymbol["QuindicesimaAlta"] = 58645] = "QuindicesimaAlta";
		MusicFontSymbol[MusicFontSymbol["DynamicPPPPPP"] = 58663] = "DynamicPPPPPP";
		MusicFontSymbol[MusicFontSymbol["DynamicPPPPP"] = 58664] = "DynamicPPPPP";
		MusicFontSymbol[MusicFontSymbol["DynamicPPPP"] = 58665] = "DynamicPPPP";
		MusicFontSymbol[MusicFontSymbol["DynamicPPP"] = 58666] = "DynamicPPP";
		MusicFontSymbol[MusicFontSymbol["DynamicPP"] = 58667] = "DynamicPP";
		MusicFontSymbol[MusicFontSymbol["DynamicPiano"] = 58656] = "DynamicPiano";
		MusicFontSymbol[MusicFontSymbol["DynamicMP"] = 58668] = "DynamicMP";
		MusicFontSymbol[MusicFontSymbol["DynamicMF"] = 58669] = "DynamicMF";
		MusicFontSymbol[MusicFontSymbol["DynamicPF"] = 58670] = "DynamicPF";
		MusicFontSymbol[MusicFontSymbol["DynamicForte"] = 58658] = "DynamicForte";
		MusicFontSymbol[MusicFontSymbol["DynamicFF"] = 58671] = "DynamicFF";
		MusicFontSymbol[MusicFontSymbol["DynamicFFF"] = 58672] = "DynamicFFF";
		MusicFontSymbol[MusicFontSymbol["DynamicFFFF"] = 58673] = "DynamicFFFF";
		MusicFontSymbol[MusicFontSymbol["DynamicFFFFF"] = 58674] = "DynamicFFFFF";
		MusicFontSymbol[MusicFontSymbol["DynamicFFFFFF"] = 58675] = "DynamicFFFFFF";
		MusicFontSymbol[MusicFontSymbol["DynamicFortePiano"] = 58676] = "DynamicFortePiano";
		MusicFontSymbol[MusicFontSymbol["DynamicNiente"] = 58662] = "DynamicNiente";
		MusicFontSymbol[MusicFontSymbol["DynamicSforzando1"] = 58678] = "DynamicSforzando1";
		MusicFontSymbol[MusicFontSymbol["DynamicSforzandoPiano"] = 58679] = "DynamicSforzandoPiano";
		MusicFontSymbol[MusicFontSymbol["DynamicSforzandoPianissimo"] = 58680] = "DynamicSforzandoPianissimo";
		MusicFontSymbol[MusicFontSymbol["DynamicSforzato"] = 58681] = "DynamicSforzato";
		MusicFontSymbol[MusicFontSymbol["DynamicSforzatoPiano"] = 58682] = "DynamicSforzatoPiano";
		MusicFontSymbol[MusicFontSymbol["DynamicSforzatoFF"] = 58683] = "DynamicSforzatoFF";
		MusicFontSymbol[MusicFontSymbol["DynamicRinforzando1"] = 58684] = "DynamicRinforzando1";
		MusicFontSymbol[MusicFontSymbol["DynamicRinforzando2"] = 58685] = "DynamicRinforzando2";
		MusicFontSymbol[MusicFontSymbol["DynamicForzando"] = 58677] = "DynamicForzando";
		MusicFontSymbol[MusicFontSymbol["DynamicCrescendoHairpin"] = 58686] = "DynamicCrescendoHairpin";
		MusicFontSymbol[MusicFontSymbol["GraceNoteSlashStemUp"] = 58724] = "GraceNoteSlashStemUp";
		MusicFontSymbol[MusicFontSymbol["GraceNoteSlashStemDown"] = 58725] = "GraceNoteSlashStemDown";
		MusicFontSymbol[MusicFontSymbol["OrnamentTrill"] = 58726] = "OrnamentTrill";
		MusicFontSymbol[MusicFontSymbol["OrnamentTurn"] = 58727] = "OrnamentTurn";
		MusicFontSymbol[MusicFontSymbol["OrnamentTurnInverted"] = 58728] = "OrnamentTurnInverted";
		MusicFontSymbol[MusicFontSymbol["OrnamentShortTrill"] = 58732] = "OrnamentShortTrill";
		MusicFontSymbol[MusicFontSymbol["OrnamentMordent"] = 58733] = "OrnamentMordent";
		MusicFontSymbol[MusicFontSymbol["StringsDownBow"] = 58896] = "StringsDownBow";
		MusicFontSymbol[MusicFontSymbol["StringsUpBow"] = 58898] = "StringsUpBow";
		MusicFontSymbol[MusicFontSymbol["KeyboardPedalPed"] = 58960] = "KeyboardPedalPed";
		MusicFontSymbol[MusicFontSymbol["KeyboardPedalUp"] = 58965] = "KeyboardPedalUp";
		MusicFontSymbol[MusicFontSymbol["PictEdgeOfCymbal"] = 59177] = "PictEdgeOfCymbal";
		MusicFontSymbol[MusicFontSymbol["GuitarString0"] = 59443] = "GuitarString0";
		MusicFontSymbol[MusicFontSymbol["GuitarString1"] = 59444] = "GuitarString1";
		MusicFontSymbol[MusicFontSymbol["GuitarString2"] = 59445] = "GuitarString2";
		MusicFontSymbol[MusicFontSymbol["GuitarString3"] = 59446] = "GuitarString3";
		MusicFontSymbol[MusicFontSymbol["GuitarString4"] = 59447] = "GuitarString4";
		MusicFontSymbol[MusicFontSymbol["GuitarString5"] = 59448] = "GuitarString5";
		MusicFontSymbol[MusicFontSymbol["GuitarString6"] = 59449] = "GuitarString6";
		MusicFontSymbol[MusicFontSymbol["GuitarString7"] = 59450] = "GuitarString7";
		MusicFontSymbol[MusicFontSymbol["GuitarString8"] = 59451] = "GuitarString8";
		MusicFontSymbol[MusicFontSymbol["GuitarString9"] = 59452] = "GuitarString9";
		MusicFontSymbol[MusicFontSymbol["GuitarOpenPedal"] = 59453] = "GuitarOpenPedal";
		MusicFontSymbol[MusicFontSymbol["GuitarClosePedal"] = 59455] = "GuitarClosePedal";
		MusicFontSymbol[MusicFontSymbol["GuitarGolpe"] = 59458] = "GuitarGolpe";
		MusicFontSymbol[MusicFontSymbol["GuitarFadeIn"] = 59459] = "GuitarFadeIn";
		MusicFontSymbol[MusicFontSymbol["GuitarFadeOut"] = 59460] = "GuitarFadeOut";
		MusicFontSymbol[MusicFontSymbol["GuitarVolumeSwell"] = 59461] = "GuitarVolumeSwell";
		MusicFontSymbol[MusicFontSymbol["FretboardFilledCircle"] = 59480] = "FretboardFilledCircle";
		MusicFontSymbol[MusicFontSymbol["FretboardX"] = 59481] = "FretboardX";
		MusicFontSymbol[MusicFontSymbol["FretboardO"] = 59482] = "FretboardO";
		MusicFontSymbol[MusicFontSymbol["Tuplet0"] = 59520] = "Tuplet0";
		MusicFontSymbol[MusicFontSymbol["Tuplet1"] = 59521] = "Tuplet1";
		MusicFontSymbol[MusicFontSymbol["Tuplet2"] = 59522] = "Tuplet2";
		MusicFontSymbol[MusicFontSymbol["Tuplet3"] = 59523] = "Tuplet3";
		MusicFontSymbol[MusicFontSymbol["Tuplet4"] = 59524] = "Tuplet4";
		MusicFontSymbol[MusicFontSymbol["Tuplet5"] = 59525] = "Tuplet5";
		MusicFontSymbol[MusicFontSymbol["Tuplet6"] = 59526] = "Tuplet6";
		MusicFontSymbol[MusicFontSymbol["Tuplet7"] = 59527] = "Tuplet7";
		MusicFontSymbol[MusicFontSymbol["Tuplet8"] = 59528] = "Tuplet8";
		MusicFontSymbol[MusicFontSymbol["Tuplet9"] = 59529] = "Tuplet9";
		MusicFontSymbol[MusicFontSymbol["TupletColon"] = 59530] = "TupletColon";
		MusicFontSymbol[MusicFontSymbol["WiggleTrill"] = 60068] = "WiggleTrill";
		MusicFontSymbol[MusicFontSymbol["GuitarVibratoStroke"] = 60082] = "GuitarVibratoStroke";
		MusicFontSymbol[MusicFontSymbol["GuitarWideVibratoStroke"] = 60083] = "GuitarWideVibratoStroke";
		MusicFontSymbol[MusicFontSymbol["WiggleVibratoMediumFast"] = 60126] = "WiggleVibratoMediumFast";
		MusicFontSymbol[MusicFontSymbol["WiggleSawtoothNarrow"] = 60090] = "WiggleSawtoothNarrow";
		MusicFontSymbol[MusicFontSymbol["WiggleSawtooth"] = 60091] = "WiggleSawtooth";
		MusicFontSymbol[MusicFontSymbol["OctaveBaselineM"] = 60565] = "OctaveBaselineM";
		MusicFontSymbol[MusicFontSymbol["OctaveBaselineB"] = 60563] = "OctaveBaselineB";
		MusicFontSymbol[MusicFontSymbol["GuitarLeftHandTapping"] = 59456] = "GuitarLeftHandTapping";
		MusicFontSymbol[MusicFontSymbol["Fingering0"] = 60688] = "Fingering0";
		MusicFontSymbol[MusicFontSymbol["Fingering1"] = 60689] = "Fingering1";
		MusicFontSymbol[MusicFontSymbol["Fingering2"] = 60690] = "Fingering2";
		MusicFontSymbol[MusicFontSymbol["Fingering3"] = 60691] = "Fingering3";
		MusicFontSymbol[MusicFontSymbol["Fingering4"] = 60692] = "Fingering4";
		MusicFontSymbol[MusicFontSymbol["Fingering5"] = 60693] = "Fingering5";
		MusicFontSymbol[MusicFontSymbol["FingeringPLower"] = 60695] = "FingeringPLower";
		MusicFontSymbol[MusicFontSymbol["FingeringTLower"] = 60696] = "FingeringTLower";
		MusicFontSymbol[MusicFontSymbol["FingeringILower"] = 60697] = "FingeringILower";
		MusicFontSymbol[MusicFontSymbol["FingeringMLower"] = 60698] = "FingeringMLower";
		MusicFontSymbol[MusicFontSymbol["FingeringALower"] = 60699] = "FingeringALower";
		MusicFontSymbol[MusicFontSymbol["FingeringCLower"] = 60700] = "FingeringCLower";
		return MusicFontSymbol;
	}({});
	/**
	* @internal
	*/
	var MusicFontSymbolLookup = class MusicFontSymbolLookup {
		static _allMusicFontSymbols = [];
		static _blackNoteHeadGlyphs = /* @__PURE__ */ new Set();
		static _initialize() {
			const all = MusicFontSymbolLookup._allMusicFontSymbols;
			if (all.length === 0) for (const v of Object.values(MusicFontSymbol).filter((k) => typeof k === "number")) {
				const symbol = v;
				all.push(symbol);
				if (MusicFontSymbol[symbol].toLowerCase().endsWith("black")) MusicFontSymbolLookup._blackNoteHeadGlyphs.add(symbol);
			}
		}
		/**
		* Gets a list of all music font symbols used in alphaTab.
		*/
		static getAllMusicFontSymbols() {
			MusicFontSymbolLookup._initialize();
			return MusicFontSymbolLookup._allMusicFontSymbols;
		}
		static isBlackNoteHead(glph) {
			MusicFontSymbolLookup._initialize();
			return MusicFontSymbolLookup._blackNoteHeadGlyphs.has(glph);
		}
	};
	//#endregion
	//#region src/model/InstrumentArticulation.ts
	/**
	* This public enum lists all base line modes
	* @public
	*/
	var TechniqueSymbolPlacement = /* @__PURE__ */ function(TechniqueSymbolPlacement) {
		/**
		* Symbol is shown above
		*/
		TechniqueSymbolPlacement[TechniqueSymbolPlacement["Above"] = 0] = "Above";
		/**
		* Symbol is shown inside.
		*/
		TechniqueSymbolPlacement[TechniqueSymbolPlacement["Inside"] = 1] = "Inside";
		/**
		* Symbol is shown below.
		*/
		TechniqueSymbolPlacement[TechniqueSymbolPlacement["Below"] = 2] = "Below";
		/**
		* Symbol is shown outside.
		*/
		TechniqueSymbolPlacement[TechniqueSymbolPlacement["Outside"] = 3] = "Outside";
		return TechniqueSymbolPlacement;
	}({});
	/**
	* Describes an instrument articulation which is used for percussions.
	* @json
	* @json_strict
	* @public
	*/
	var InstrumentArticulation = class InstrumentArticulation {
		/**
		* An internal ID to identify this articulation for purposes like
		* mapping during exports.The exact meaning of the ID is not defined and dependes on the
		* importer source.
		*/
		id = 0;
		/**
		* A unique id for this articulation.
		*/
		get uniqueId() {
			return `${this.elementType}.${this.id}`;
		}
		/**
		* Gets or sets the type of the element for which this articulation is for.
		*/
		elementType;
		/**
		* The line the note head should be shown for standard notation.
		*
		* @remarks
		* This value is a bit special and its semantics are adopted from Guitar Pro:
		* Staff lines are actually "steps" including lines and spaces on the staff.
		* 1 means the note is on the top line of the staff and from there its counting downwards.
		*/
		staffLine;
		/**
		* Gets or sets the note head to display by default.
		*/
		noteHeadDefault;
		/**
		* Gets or sets the note head to display for half duration notes.
		*/
		noteHeadHalf;
		/**
		* Gets or sets the note head to display for whole duration notes.
		*/
		noteHeadWhole;
		/**
		* Gets or sets which additional technique symbol should be placed for the note head.
		*/
		techniqueSymbol;
		/**
		* Gets or sets where the technique symbol should be placed.
		*/
		techniqueSymbolPlacement;
		/**
		* Gets or sets which midi key to use when playing the note.
		*/
		outputMidiNumber;
		constructor(elementType = "", staffLine = 0, outputMidiNumber = 0, noteHeadDefault = MusicFontSymbol.None, noteHeadHalf = MusicFontSymbol.None, noteHeadWhole = MusicFontSymbol.None, techniqueSymbol = MusicFontSymbol.None, techniqueSymbolPlacement = 1, id = 0) {
			this.id = id;
			this.elementType = elementType;
			this.outputMidiNumber = outputMidiNumber;
			this.staffLine = staffLine;
			this.noteHeadDefault = noteHeadDefault;
			this.noteHeadHalf = noteHeadHalf !== MusicFontSymbol.None ? noteHeadHalf : noteHeadDefault;
			this.noteHeadWhole = noteHeadWhole !== MusicFontSymbol.None ? noteHeadWhole : noteHeadDefault;
			this.techniqueSymbol = techniqueSymbol;
			this.techniqueSymbolPlacement = techniqueSymbolPlacement;
		}
		/**
		* @internal
		*/
		static create(id = 0, elementType = "", staffLine = 0, outputMidiNumber = 0, noteHeadDefault = MusicFontSymbol.None, noteHeadHalf = MusicFontSymbol.None, noteHeadWhole = MusicFontSymbol.None, techniqueSymbol = MusicFontSymbol.None, techniqueSymbolPlacement = 1) {
			return new InstrumentArticulation(elementType, staffLine, outputMidiNumber, noteHeadDefault, noteHeadHalf, noteHeadWhole, techniqueSymbol, techniqueSymbolPlacement, id);
		}
		getSymbol(duration) {
			switch (duration) {
				case Duration.Whole: return this.noteHeadWhole;
				case Duration.Half: return this.noteHeadHalf;
				default: return this.noteHeadDefault;
			}
		}
	};
	//#endregion
	//#region src/model/PercussionMapper.ts
	/**
	* @internal
	*/
	var PercussionMapper = class PercussionMapper {
		static instrumentArticulations = new Map([
			InstrumentArticulation.create(38, "Snare", 3, 38, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(37, "Snare", 3, 37, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(91, "Snare", 3, 38, MusicFontSymbol.NoteheadDiamondWhite, MusicFontSymbol.NoteheadDiamondWhite, MusicFontSymbol.NoteheadDiamondWhite),
			InstrumentArticulation.create(42, "Charley", -1, 42, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(92, "Charley", -1, 46, MusicFontSymbol.NoteheadCircleSlash, MusicFontSymbol.NoteheadCircleSlash, MusicFontSymbol.NoteheadCircleSlash),
			InstrumentArticulation.create(46, "Charley", -1, 46, MusicFontSymbol.NoteheadCircleX, MusicFontSymbol.NoteheadCircleX, MusicFontSymbol.NoteheadCircleX),
			InstrumentArticulation.create(44, "Charley", 9, 44, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(35, "Acoustic Kick Drum", 8, 35, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(36, "Kick Drum", 7, 36, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(50, "Tom Very High", 1, 50, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(48, "Tom High", 2, 48, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(47, "Tom Medium", 4, 47, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(45, "Tom Low", 5, 45, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(43, "Tom Very Low", 6, 43, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(93, "Ride", 0, 51, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.PictEdgeOfCymbal, TechniqueSymbolPlacement.Above),
			InstrumentArticulation.create(51, "Ride", 0, 51, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(53, "Ride", 0, 53, MusicFontSymbol.NoteheadDiamondWhite, MusicFontSymbol.NoteheadDiamondWhite, MusicFontSymbol.NoteheadDiamondWhite),
			InstrumentArticulation.create(94, "Ride", 0, 51, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.ArticStaccatoAbove, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(55, "Splash", -2, 55, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(95, "Splash", -2, 55, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.ArticStaccatoAbove, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(52, "China", -3, 52, MusicFontSymbol.NoteheadHeavyXHat, MusicFontSymbol.NoteheadHeavyXHat, MusicFontSymbol.NoteheadHeavyXHat),
			InstrumentArticulation.create(96, "China", -3, 52, MusicFontSymbol.NoteheadHeavyXHat, MusicFontSymbol.NoteheadHeavyXHat, MusicFontSymbol.NoteheadHeavyXHat),
			InstrumentArticulation.create(49, "Crash High", -2, 49, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX),
			InstrumentArticulation.create(97, "Crash High", -2, 49, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.ArticStaccatoAbove, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(57, "Crash Medium", -1, 57, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX),
			InstrumentArticulation.create(98, "Crash Medium", -1, 57, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.NoteheadHeavyX, MusicFontSymbol.ArticStaccatoAbove, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(99, "Cowbell Low", 1, 56, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpHalf, MusicFontSymbol.NoteheadTriangleUpWhole),
			InstrumentArticulation.create(100, "Cowbell Low", 1, 56, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXHalf, MusicFontSymbol.NoteheadXWhole),
			InstrumentArticulation.create(56, "Cowbell Medium", 0, 56, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpHalf, MusicFontSymbol.NoteheadTriangleUpWhole),
			InstrumentArticulation.create(101, "Cowbell Medium", 0, 56, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXHalf, MusicFontSymbol.NoteheadXWhole),
			InstrumentArticulation.create(102, "Cowbell High", -1, 56, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpHalf, MusicFontSymbol.NoteheadTriangleUpWhole),
			InstrumentArticulation.create(103, "Cowbell High", -1, 56, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXHalf, MusicFontSymbol.NoteheadXWhole),
			InstrumentArticulation.create(77, "Woodblock Low", -9, 77, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack),
			InstrumentArticulation.create(76, "Woodblock High", -10, 76, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack),
			InstrumentArticulation.create(60, "Bongo High", -4, 60, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(104, "Bongo High", -5, 60, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.NoteheadParenthesis, TechniqueSymbolPlacement.Inside),
			InstrumentArticulation.create(105, "Bongo High", -6, 60, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(61, "Bongo Low", -7, 61, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(106, "Bongo Low", -8, 61, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.NoteheadParenthesis, TechniqueSymbolPlacement.Inside),
			InstrumentArticulation.create(107, "Bongo Low", -16, 61, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(66, "Timbale Low", 10, 66, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(65, "Timbale High", 9, 65, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(68, "Agogo Low", 12, 68, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(67, "Agogo High", 11, 67, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(64, "Conga Low", 17, 64, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(108, "Conga Low", 16, 64, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(109, "Conga Low", 15, 64, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.NoteheadParenthesis, TechniqueSymbolPlacement.Inside),
			InstrumentArticulation.create(63, "Conga High", 14, 63, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(110, "Conga High", 13, 63, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(62, "Conga High", 19, 62, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.NoteheadParenthesis, TechniqueSymbolPlacement.Inside),
			InstrumentArticulation.create(72, "Whistle Low", -11, 72, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(71, "Whistle High", -17, 71, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(73, "Guiro", 38, 73, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(74, "Guiro", 37, 74, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(86, "Surdo", 36, 86, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(87, "Surdo", 35, 87, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadParenthesis, TechniqueSymbolPlacement.Inside),
			InstrumentArticulation.create(54, "Tambourine", 3, 54, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack),
			InstrumentArticulation.create(111, "Tambourine", 2, 54, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.StringsUpBow, TechniqueSymbolPlacement.Above),
			InstrumentArticulation.create(112, "Tambourine", 1, 54, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.NoteheadTriangleUpBlack, MusicFontSymbol.StringsDownBow, TechniqueSymbolPlacement.Above),
			InstrumentArticulation.create(113, "Tambourine", -7, 54, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(79, "Cuica", 30, 79, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(78, "Cuica", 29, 78, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(58, "Vibraslap", 28, 58, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(81, "Triangle", 27, 81, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(80, "Triangle", 26, 80, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadParenthesis, TechniqueSymbolPlacement.Inside),
			InstrumentArticulation.create(114, "Grancassa", 25, 43, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(115, "Piatti", 18, 49, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(116, "Piatti", 24, 49, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(69, "Cabasa", 23, 69, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(117, "Cabasa", 22, 69, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.StringsUpBow, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(85, "Castanets", 21, 85, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(75, "Claves", 20, 75, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(70, "Left Maraca", -12, 70, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(118, "Left Maraca", -13, 70, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.StringsUpBow, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(119, "Right Maraca", -14, 70, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(120, "Right Maraca", -15, 70, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.StringsUpBow, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(82, "Shaker", -23, 82, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(122, "Shaker", -24, 82, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.StringsUpBow, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(84, "Bell Tree", -18, 53, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(123, "Bell Tree", -19, 53, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.StringsUpBow, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(83, "Jingle Bell", -20, 53, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(83, "Tinkle Bell", -20, 53, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(124, "Golpe", -21, 62, MusicFontSymbol.NoteheadNull, MusicFontSymbol.NoteheadNull, MusicFontSymbol.NoteheadNull, MusicFontSymbol.GuitarGolpe, TechniqueSymbolPlacement.Below),
			InstrumentArticulation.create(125, "Golpe", -22, 62, MusicFontSymbol.NoteheadNull, MusicFontSymbol.NoteheadNull, MusicFontSymbol.NoteheadNull, MusicFontSymbol.GuitarGolpe, TechniqueSymbolPlacement.Above),
			InstrumentArticulation.create(39, "Hand Clap", 3, 39, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(40, "Electric Snare", 3, 40, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(31, "Sticks", 3, 40, MusicFontSymbol.NoteheadSlashedBlack2, MusicFontSymbol.NoteheadSlashedBlack2, MusicFontSymbol.NoteheadSlashedBlack2),
			InstrumentArticulation.create(41, "Very Low Floor Tom", 5, 41, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole),
			InstrumentArticulation.create(59, "Ride Cymbal 2", 2, 59, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.PictEdgeOfCymbal, TechniqueSymbolPlacement.Above),
			InstrumentArticulation.create(126, "Ride Cymbal 2", 2, 59, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(127, "Ride Cymbal 2", 2, 59, MusicFontSymbol.NoteheadDiamondWhite, MusicFontSymbol.NoteheadDiamondWhite, MusicFontSymbol.NoteheadDiamondWhite),
			InstrumentArticulation.create(29, "Ride Cymbal 2", 2, 59, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.ArticStaccatoAbove, TechniqueSymbolPlacement.Outside),
			InstrumentArticulation.create(30, "Reverse Cymbal", -3, 49, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(33, "Metronome", 3, 37, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack, MusicFontSymbol.NoteheadXBlack),
			InstrumentArticulation.create(34, "Metronome", 3, 38, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadBlack)
		].map((articulation) => [articulation.uniqueId, articulation]));
		static _instrumentArticulationNames = new Map([
			["Snare (hit)", "Snare.38"],
			["Snare (side stick)", "Snare.37"],
			["Snare (rim shot)", "Snare.91"],
			["Hi-Hat (closed)", "Charley.42"],
			["Hi-Hat (half)", "Charley.92"],
			["Hi-Hat (open)", "Charley.46"],
			["Pedal Hi-Hat (hit)", "Charley.44"],
			["Kick (hit)", "Acoustic Kick Drum.35"],
			["Kick (hit) 2", "Kick Drum.36"],
			["High Floor Tom (hit)", "Tom Very High.50"],
			["High Tom (hit)", "Tom High.48"],
			["Mid Tom (hit)", "Tom Medium.47"],
			["Low Tom (hit)", "Tom Low.45"],
			["Very Low Tom (hit)", "Tom Very Low.43"],
			["Ride (edge)", "Ride.93"],
			["Ride (middle)", "Ride.51"],
			["Ride (bell)", "Ride.53"],
			["Ride (choke)", "Ride.94"],
			["Splash (hit)", "Splash.55"],
			["Splash (choke)", "Splash.95"],
			["China (hit)", "China.52"],
			["China (choke)", "China.96"],
			["Crash high (hit)", "Crash High.49"],
			["Crash high (choke)", "Crash High.97"],
			["Crash medium (hit)", "Crash Medium.57"],
			["Crash medium (choke)", "Crash Medium.98"],
			["Cowbell low (hit)", "Cowbell Low.99"],
			["Cowbell low (tip)", "Cowbell Low.100"],
			["Cowbell medium (hit)", "Cowbell Medium.56"],
			["Cowbell medium (tip)", "Cowbell Medium.101"],
			["Cowbell high (hit)", "Cowbell High.102"],
			["Cowbell high (tip)", "Cowbell High.103"],
			["Woodblock low (hit)", "Woodblock Low.77"],
			["Woodblock high (hit)", "Woodblock High.76"],
			["Bongo High (hit)", "Bongo High.60"],
			["Bongo High (mute)", "Bongo High.104"],
			["Bongo High (slap)", "Bongo High.105"],
			["Bongo Low (hit)", "Bongo Low.61"],
			["Bongo Low (mute)", "Bongo Low.106"],
			["Bongo Low (slap)", "Bongo Low.107"],
			["Timbale low (hit)", "Timbale Low.66"],
			["Timbale high (hit)", "Timbale High.65"],
			["Agogo low (hit)", "Agogo Low.68"],
			["Agogo high (hit)", "Agogo High.67"],
			["Conga low (hit)", "Conga Low.64"],
			["Conga low (slap)", "Conga Low.108"],
			["Conga low (mute)", "Conga Low.109"],
			["Conga high (hit)", "Conga High.63"],
			["Conga high (slap)", "Conga High.110"],
			["Conga high (mute)", "Conga High.62"],
			["Whistle low (hit)", "Whistle Low.72"],
			["Whistle high (hit)", "Whistle High.71"],
			["Guiro (hit)", "Guiro.73"],
			["Guiro (scrap-return)", "Guiro.74"],
			["Surdo (hit)", "Surdo.86"],
			["Surdo (mute)", "Surdo.87"],
			["Tambourine (hit)", "Tambourine.54"],
			["Tambourine (return)", "Tambourine.111"],
			["Tambourine (roll)", "Tambourine.112"],
			["Tambourine (hand)", "Tambourine.113"],
			["Cuica (open)", "Cuica.79"],
			["Cuica (mute)", "Cuica.78"],
			["Vibraslap (hit)", "Vibraslap.58"],
			["Triangle (hit)", "Triangle.81"],
			["Triangle (mute)", "Triangle.80"],
			["Grancassa (hit)", "Grancassa.114"],
			["Piatti (hit)", "Piatti.115"],
			["Piatti (hand)", "Piatti.116"],
			["Cabasa (hit)", "Cabasa.69"],
			["Cabasa (return)", "Cabasa.117"],
			["Castanets (hit)", "Castanets.85"],
			["Claves (hit)", "Claves.75"],
			["Left Maraca (hit)", "Left Maraca.70"],
			["Left Maraca (return)", "Left Maraca.118"],
			["Right Maraca (hit)", "Right Maraca.119"],
			["Right Maraca (return)", "Right Maraca.120"],
			["Shaker (hit)", "Shaker.82"],
			["Shaker (return)", "Shaker.122"],
			["Bell Tree (hit)", "Bell Tree.84"],
			["Bell Tree (return)", "Bell Tree.123"],
			["Jingle Bell (hit)", "Jingle Bell.83"],
			["Tinkle Bell (hit)", "Tinkle Bell.83"],
			["Golpe (thumb)", "Golpe.124"],
			["Golpe (finger)", "Golpe.125"],
			["Hand Clap (hit)", "Hand Clap.39"],
			["Electric Snare (hit)", "Electric Snare.40"],
			["Snare (side stick) 2", "Sticks.31"],
			["Low Floor Tom (hit)", "Very Low Floor Tom.41"],
			["Ride (edge) 2", "Ride Cymbal 2.59"],
			["Ride (middle) 2", "Ride Cymbal 2.126"],
			["Ride (bell) 2", "Ride Cymbal 2.127"],
			["Ride (choke) 2", "Ride Cymbal 2.29"],
			["Reverse Cymbal (hit)", "Reverse Cymbal.30"],
			["Metronome (hit)", "Metronome.33"],
			["Metronome (bell)", "Metronome.34"]
		]);
		static _gp6ElementAndVariationToArticulation = [
			[
				35,
				35,
				35
			],
			[
				38,
				91,
				37
			],
			[
				99,
				100,
				99
			],
			[
				56,
				100,
				56
			],
			[
				102,
				103,
				102
			],
			[
				43,
				43,
				43
			],
			[
				45,
				45,
				45
			],
			[
				47,
				47,
				47
			],
			[
				48,
				48,
				48
			],
			[
				50,
				50,
				50
			],
			[
				42,
				92,
				46
			],
			[
				44,
				44,
				44
			],
			[
				57,
				98,
				57
			],
			[
				49,
				97,
				49
			],
			[
				55,
				95,
				55
			],
			[
				51,
				93,
				127
			],
			[
				52,
				96,
				52
			]
		];
		static articulationFromElementVariation(element, variation) {
			if (element < PercussionMapper._gp6ElementAndVariationToArticulation.length) {
				if (variation >= PercussionMapper._gp6ElementAndVariationToArticulation.length) variation = 0;
				return PercussionMapper._gp6ElementAndVariationToArticulation[element][variation];
			}
			return 38;
		}
		static getArticulationName(n) {
			const articulation = PercussionMapper.getArticulation(n);
			if (articulation) {
				const uniqueId = articulation.uniqueId;
				for (const [name, value] of PercussionMapper.instrumentArticulationNames) if (value === uniqueId) return name;
			} else {
				const uniqueId = `.${n.percussionArticulation}`;
				for (const [name, value] of PercussionMapper.instrumentArticulationNames) if (value.endsWith(uniqueId)) return name;
			}
			return "Snare (hit)";
		}
		static getArticulation(n) {
			const articulationIndex = n.percussionArticulation;
			if (articulationIndex < 0) return null;
			const trackArticulations = n.beat.voice.bar.staff.track.percussionArticulations;
			if (articulationIndex < trackArticulations.length) return trackArticulations[articulationIndex];
			return PercussionMapper.getArticulationById(articulationIndex);
		}
		static _instrumentArticulationsById;
		static _initArticulationsById() {
			let lookup = PercussionMapper._instrumentArticulationsById;
			if (!lookup) {
				lookup = /* @__PURE__ */ new Map();
				for (const articulation of PercussionMapper.instrumentArticulations.values()) lookup.set(articulation.id, articulation);
				PercussionMapper._instrumentArticulationsById = lookup;
			}
			return lookup;
		}
		static instrumentArticulationIds() {
			return PercussionMapper._initArticulationsById().keys();
		}
		static getArticulationById(id) {
			const lookup = PercussionMapper._initArticulationsById();
			return lookup.has(id) ? lookup.get(id) : null;
		}
		static getElementAndVariation(n) {
			const articulation = PercussionMapper.getArticulation(n);
			if (!articulation) return [-1, -1];
			for (let element = 0; element < PercussionMapper._gp6ElementAndVariationToArticulation.length; element++) {
				const variations = PercussionMapper._gp6ElementAndVariationToArticulation[element];
				for (let variation = 0; variation < variations.length; variation++) if (PercussionMapper.getArticulationById(variations[variation])?.outputMidiNumber === articulation.outputMidiNumber) return [element, variation];
			}
			return [-1, -1];
		}
		static instrumentArticulationNames = PercussionMapper._mergeNames([new Map([
			["Hand (hit)", "Bongo Low.61"],
			["Tinkle Bell (hat)", "Tingle Bell.83"],
			["Cymbal (hit)", "Reverse Cymbal.30"],
			["Snare (side stick) 3", "Snare.37"],
			["Snare (hit) 2", "Snare.38"],
			["Snare (hit) 3", "Snare.40"],
			["Agogo tow (hit)", "Agogo Low.68"],
			["Triangle (rnute)", "Triangle.80"],
			["Hand (mute)", "Bongo High.104"],
			["Hand (slap)", "Bongo High.105"],
			["Hand (mute) 2", "Bongo Low.106"],
			["Hand (slap) 2", "Bongo Low.107"],
			["Piatti (hat)", "Piatti.115"],
			["Bell Tee (return)", "Bell Tree.123"]
		]), PercussionMapper._instrumentArticulationNames]);
		static _mergeNames(maps) {
			const merged = new Map(maps[0]);
			for (let i = 1; i < maps.length; i++) for (const [k, v] of maps[i]) merged.set(k, v);
			return merged;
		}
		static _articulationsByOutputNumber;
		static tryMatchKnownArticulation(articulation) {
			let articulationsByOutputNumber = PercussionMapper._articulationsByOutputNumber;
			if (!articulationsByOutputNumber) {
				articulationsByOutputNumber = /* @__PURE__ */ new Map();
				for (const a of PercussionMapper.instrumentArticulations.values()) if (!articulationsByOutputNumber.has(a.outputMidiNumber)) articulationsByOutputNumber.set(a.outputMidiNumber, a);
				PercussionMapper._articulationsByOutputNumber = articulationsByOutputNumber;
			}
			return articulationsByOutputNumber.has(articulation.outputMidiNumber) ? articulationsByOutputNumber.get(articulation.outputMidiNumber).id : -1;
		}
		static _instrumentArticulationsByUniqueId;
		static getInstrumentArticulationByUniqueId(uniqueId) {
			let lookup = PercussionMapper._instrumentArticulationsByUniqueId;
			if (!lookup) {
				lookup = /* @__PURE__ */ new Map();
				for (const articulation of PercussionMapper.instrumentArticulations.values()) lookup.set(articulation.uniqueId, articulation);
				PercussionMapper._instrumentArticulationsByUniqueId = lookup;
			}
			return lookup.has(uniqueId) ? lookup.get(uniqueId) : void 0;
		}
	};
	//#endregion
	//#region src/model/NoteOrnament.ts
	/**
	* Lists all note ornaments.
	* @public
	*/
	var NoteOrnament = /* @__PURE__ */ function(NoteOrnament) {
		NoteOrnament[NoteOrnament["None"] = 0] = "None";
		NoteOrnament[NoteOrnament["InvertedTurn"] = 1] = "InvertedTurn";
		NoteOrnament[NoteOrnament["Turn"] = 2] = "Turn";
		NoteOrnament[NoteOrnament["UpperMordent"] = 3] = "UpperMordent";
		NoteOrnament[NoteOrnament["LowerMordent"] = 4] = "LowerMordent";
		return NoteOrnament;
	}({});
	//#endregion
	//#region src/model/Note.ts
	/**
	* @internal
	*/
	var NoteIdBag = class {
		tieDestinationNoteId = -1;
		tieOriginNoteId = -1;
		slurDestinationNoteId = -1;
		slurOriginNoteId = -1;
		hammerPullDestinationNoteId = -1;
		hammerPullOriginNoteId = -1;
		slideTargetNoteId = -1;
		slideOriginNoteId = -1;
	};
	/**
	* Lists all graphical sub elements within a {@link Note} which can be styled via {@link Note.style}
	* @public
	*/
	var NoteSubElement = /* @__PURE__ */ function(NoteSubElement) {
		/**
		* The effects and annotations shown in dedicated effect bands above the staves (e.g. vibrato).
		* The style of the first note with the effect wins.
		*/
		NoteSubElement[NoteSubElement["Effects"] = 0] = "Effects";
		/**
		* The note head on the standard notation staff.
		*/
		NoteSubElement[NoteSubElement["StandardNotationNoteHead"] = 1] = "StandardNotationNoteHead";
		/**
		* The accidentals on the standard notation staff.
		*/
		NoteSubElement[NoteSubElement["StandardNotationAccidentals"] = 2] = "StandardNotationAccidentals";
		/**
		* The effects and annotations applied to this note on the standard notation staff (e.g. bends).
		* If effects on beats result in individual note elements shown, this color will apply.
		*/
		NoteSubElement[NoteSubElement["StandardNotationEffects"] = 3] = "StandardNotationEffects";
		/**
		* The fret number on the guitar tab staff.
		*/
		NoteSubElement[NoteSubElement["GuitarTabFretNumber"] = 4] = "GuitarTabFretNumber";
		/**
		* The effects and annotations applied to this note on the guitar tab staff (e.g. bends).
		* If effects on beats result in individual note elements shown, this color will apply.
		*/
		NoteSubElement[NoteSubElement["GuitarTabEffects"] = 5] = "GuitarTabEffects";
		/**
		* The note head on the slash notation staff.
		*/
		NoteSubElement[NoteSubElement["SlashNoteHead"] = 6] = "SlashNoteHead";
		/**
		* The effects and annotations applied to this note on the slash notation staff (e.g. dots).
		* If effects on beats result in individual note elements shown, this color will apply.
		*/
		NoteSubElement[NoteSubElement["SlashEffects"] = 7] = "SlashEffects";
		/**
		* The note number on the numbered notation staff.
		*/
		NoteSubElement[NoteSubElement["NumberedNumber"] = 8] = "NumberedNumber";
		/**
		* The accidentals on the numbered notation staff.
		*/
		NoteSubElement[NoteSubElement["NumberedAccidentals"] = 9] = "NumberedAccidentals";
		/**
		* The effects and annotations applied to this note on the number notation staff (e.g. dots).
		* If effects on beats result in individual note elements shown, this color will apply.
		*/
		NoteSubElement[NoteSubElement["NumberedEffects"] = 10] = "NumberedEffects";
		return NoteSubElement;
	}({});
	/**
	* Defines the custom styles for notes.
	* @json
	* @json_strict
	* @public
	*/
	var NoteStyle = class extends ElementStyle {
		/**
		* The symbol that should be used as note head.
		*/
		noteHead;
		/**
		* Whether the note head symbol should be centered on the stem (e.g. for arrow notes)
		*/
		noteHeadCenterOnStem;
	};
	/**
	* A note is a single played sound on a fretted instrument.
	* It consists of a fret offset and a string on which the note is played on.
	* It also can be modified by a lot of different effects.
	* @cloneable
	* @json
	* @json_strict
	* @public
	*/
	var Note = class Note {
		/**
		* @internal
		*/
		static globalNoteId = 0;
		/**
		* @internal
		*/
		static resetIds() {
			Note.globalNoteId = 0;
		}
		/**
		* Gets or sets the unique id of this note.
		* @clone_ignore
		*/
		id = Note.globalNoteId++;
		/**
		* Gets or sets the zero-based index of this note within the beat.
		* @json_ignore
		*/
		index = 0;
		/**
		* Gets or sets the accentuation of this note.
		*/
		accentuated = AccentuationType.None;
		/**
		* Gets or sets the bend type for this note.
		*/
		bendType = BendType.None;
		/**
		* Gets or sets the bend style for this note.
		*/
		bendStyle = BendStyle.Default;
		/**
		* Gets or sets the note from which this note continues the bend.
		* @clone_ignore
		* @json_ignore
		*/
		bendOrigin = null;
		/**
		* Gets or sets whether this note continues a bend from a previous note.
		*/
		isContinuedBend = false;
		/**
		* Gets or sets a list of the points defining the bend behavior.
		* @clone_add addBendPoint
		* @json_add addBendPoint
		*/
		bendPoints = null;
		/**
		* Gets or sets the bend point with the highest bend value.
		* @clone_ignore
		* @json_ignore
		*/
		maxBendPoint = null;
		get hasBend() {
			return this.bendPoints !== null && this.bendType !== BendType.None;
		}
		get isStringed() {
			return this.string >= 0;
		}
		/**
		* Gets or sets the fret on which this note is played on the instrument.
		* 0 is the nut.
		*/
		fret = -1;
		/**
		* Gets or sets the string number where the note is placed.
		* 1 is the lowest string on the guitar and the bottom line on the tablature.
		* It then increases the the number of strings on available on the track.
		*/
		string = -1;
		/**
		* Gets or sets whether the string number for this note should be shown.
		*/
		showStringNumber = false;
		get isPiano() {
			return !this.isStringed && this.octave >= 0 && this.tone >= 0;
		}
		/**
		* Gets or sets the octave on which this note is played.
		*/
		octave = -1;
		/**
		* Gets or sets the tone of this note within the octave.
		*/
		tone = -1;
		get isPercussion() {
			return !this.isStringed && this.percussionArticulation >= 0;
		}
		/**
		* Gets or sets the percusson element.
		* @deprecated
		*/
		get element() {
			return this.isPercussion ? PercussionMapper.getElementAndVariation(this)[0] : -1;
		}
		/**
		* Gets or sets the variation of this note.
		* @deprecated
		*/
		get variation() {
			return this.isPercussion ? PercussionMapper.getElementAndVariation(this)[1] : -1;
		}
		/**
		* Gets or sets the index of percussion articulation in the related `track.percussionArticulations`.
		* If the articulation is not listed in `track.percussionArticulations` the following list based on GP7 applies:
		* - 029 Ride (choke)
		* - 030 Cymbal (hit)
		* - 031 Snare (side stick)
		* - 033 Snare (side stick)
		* - 034 Snare (hit)
		* - 035 Kick (hit)
		* - 036 Kick (hit)
		* - 037 Snare (side stick)
		* - 038 Snare (hit)
		* - 039 Hand Clap (hit)
		* - 040 Snare (hit)
		* - 041 Low Floor Tom (hit)
		* - 042 Hi-Hat (closed)
		* - 043 Very Low Tom (hit)
		* - 044 Pedal Hi-Hat (hit)
		* - 045 Low Tom (hit)
		* - 046 Hi-Hat (open)
		* - 047 Mid Tom (hit)
		* - 048 High Tom (hit)
		* - 049 Crash high (hit)
		* - 050 High Floor Tom (hit)
		* - 051 Ride (middle)
		* - 052 China (hit)
		* - 053 Ride (bell)
		* - 054 Tambourine (hit)
		* - 055 Splash (hit)
		* - 056 Cowbell medium (hit)
		* - 057 Crash medium (hit)
		* - 058 Vibraslap (hit)
		* - 059 Ride (edge)
		* - 060 Hand (hit)
		* - 061 Hand (hit)
		* - 062 Conga high (mute)
		* - 063 Conga high (hit)
		* - 064 Conga low (hit)
		* - 065 Timbale high (hit)
		* - 066 Timbale low (hit)
		* - 067 Agogo high (hit)
		* - 068 Agogo tow (hit)
		* - 069 Cabasa (hit)
		* - 070 Left Maraca (hit)
		* - 071 Whistle high (hit)
		* - 072 Whistle low (hit)
		* - 073 Guiro (hit)
		* - 074 Guiro (scrap-return)
		* - 075 Claves (hit)
		* - 076 Woodblock high (hit)
		* - 077 Woodblock low (hit)
		* - 078 Cuica (mute)
		* - 079 Cuica (open)
		* - 080 Triangle (rnute)
		* - 081 Triangle (hit)
		* - 082 Shaker (hit)
		* - 083 Tinkle Bell (hat)
		* - 083 Jingle Bell (hit)
		* - 084 Bell Tree (hit)
		* - 085 Castanets (hit)
		* - 086 Surdo (hit)
		* - 087 Surdo (mute)
		* - 091 Snare (rim shot)
		* - 092 Hi-Hat (half)
		* - 093 Ride (edge)
		* - 094 Ride (choke)
		* - 095 Splash (choke)
		* - 096 China (choke)
		* - 097 Crash high (choke)
		* - 098 Crash medium (choke)
		* - 099 Cowbell low (hit)
		* - 100 Cowbell low (tip)
		* - 101 Cowbell medium (tip)
		* - 102 Cowbell high (hit)
		* - 103 Cowbell high (tip)
		* - 104 Hand (mute)
		* - 105 Hand (slap)
		* - 106 Hand (mute)
		* - 107 Hand (slap)
		* - 108 Conga low (slap)
		* - 109 Conga low (mute)
		* - 110 Conga high (slap)
		* - 111 Tambourine (return)
		* - 112 Tambourine (roll)
		* - 113 Tambourine (hand)
		* - 114 Grancassa (hit)
		* - 115 Piatti (hat)
		* - 116 Piatti (hand)
		* - 117 Cabasa (return)
		* - 118 Left Maraca (return)
		* - 119 Right Maraca (hit)
		* - 120 Right Maraca (return)
		* - 122 Shaker (return)
		* - 123 Bell Tee (return)
		* - 124 Golpe (thumb)
		* - 125 Golpe (finger)
		* - 126 Ride (middle)
		* - 127 Ride (bell)
		*/
		percussionArticulation = -1;
		/**
		* Gets or sets whether this note is visible on the music sheet.
		*/
		isVisible = true;
		/**
		* Gets a value indicating whether the note is left hand tapped.
		*/
		isLeftHandTapped = false;
		/**
		* Gets or sets whether this note starts a hammeron or pulloff.
		*/
		isHammerPullOrigin = false;
		get isHammerPullDestination() {
			return !!this.hammerPullOrigin;
		}
		/**
		* Gets the origin of the hammeron/pulloff of this note.
		* @clone_ignore
		* @json_ignore
		*/
		hammerPullOrigin = null;
		/**
		* Gets the destination for the hammeron/pullof started by this note.
		* @clone_ignore
		* @json_ignore
		*/
		hammerPullDestination = null;
		get isSlurOrigin() {
			return !!this.slurDestination;
		}
		/**
		* Gets or sets whether this note finishes a slur.
		*/
		isSlurDestination = false;
		/**
		* Gets or sets the note where the slur of this note starts.
		* @clone_ignore
		* @json_ignore
		*/
		slurOrigin = null;
		/**
		* Gets or sets the note where the slur of this note ends.
		* @clone_ignore
		* @json_ignore
		*/
		slurDestination = null;
		get isHarmonic() {
			return this.harmonicType !== HarmonicType.None;
		}
		/**
		* Gets or sets the harmonic type applied to this note.
		*/
		harmonicType = HarmonicType.None;
		/**
		* Gets or sets the value defining the harmonic pitch.
		*/
		harmonicValue = 0;
		/**
		* Gets or sets whether the note is a ghost note and shown in parenthesis. Also this will make the note a bit more silent.
		*/
		isGhost = false;
		/**
		* Gets or sets whether this note has a let-ring effect.
		*/
		isLetRing = false;
		/**
		* Gets or sets the destination note for the let-ring effect.
		* @clone_ignore
		* @json_ignore
		*/
		letRingDestination = null;
		/**
		* Gets or sets whether this note has a palm-mute effect.
		*/
		isPalmMute = false;
		/**
		* Gets or sets the destination note for the palm-mute effect.
		* @clone_ignore
		* @json_ignore
		*/
		palmMuteDestination = null;
		/**
		* Gets or sets whether the note is shown and played as dead note.
		*/
		isDead = false;
		/**
		* Gets or sets whether the note is played as staccato.
		*/
		isStaccato = false;
		/**
		* Gets or sets the slide-in type this note is played with.
		*/
		slideInType = SlideInType.None;
		/**
		* Gets or sets the slide-out type this note is played with.
		*/
		slideOutType = SlideOutType.None;
		/**
		* Gets or sets the target note for several slide types.
		* @clone_ignore
		* @json_ignore
		*/
		slideTarget = null;
		/**
		* Gets or sets the source note for several slide types.
		* @clone_ignore
		* @json_ignore
		*/
		slideOrigin = null;
		/**
		* Gets or sets whether a vibrato is played on the note.
		*/
		vibrato = VibratoType.None;
		/**
		* Gets the origin of the tied if this note is tied.
		* @clone_ignore
		* @json_ignore
		*/
		tieOrigin = null;
		/**
		* Gets the desination of the tie.
		* @clone_ignore
		* @json_ignore
		*/
		tieDestination = null;
		/**
		* Gets or sets whether this note is ends a tied note.
		*/
		isTieDestination = false;
		get isTieOrigin() {
			return this.tieDestination !== null;
		}
		/**
		* Gets or sets the fingers used for this note on the left hand.
		*/
		leftHandFinger = Fingers.Unknown;
		/**
		* Gets or sets the fingers used for this note on the right hand.
		*/
		rightHandFinger = Fingers.Unknown;
		/**
		* Gets or sets whether this note has fingering defined.
		*/
		get isFingering() {
			return this.leftHandFinger !== Fingers.Unknown || this.rightHandFinger !== Fingers.Unknown;
		}
		/**
		* Gets or sets the target note value for the trill effect.
		*/
		trillValue = -1;
		get trillFret() {
			return this.trillValue - this.stringTuning;
		}
		get isTrill() {
			return this.trillValue >= 0;
		}
		/**
		* Gets or sets the speed of the trill effect.
		*/
		trillSpeed = Duration.ThirtySecond;
		/**
		* Gets or sets the percentual duration of the note relative to the overall beat duration.
		*/
		durationPercent = 1;
		/**
		* Gets or sets how accidetnals for this note should  be handled.
		*/
		accidentalMode = NoteAccidentalMode.Default;
		/**
		* Gets or sets the reference to the parent beat to which this note belongs to.
		* @clone_ignore
		* @json_ignore
		*/
		beat;
		/**
		* Gets or sets the dynamics for this note.
		*/
		dynamics = DynamicValue.F;
		/**
		* @clone_ignore
		* @json_ignore
		*/
		isEffectSlurOrigin = false;
		/**
		* @clone_ignore
		* @json_ignore
		*/
		hasEffectSlur = false;
		get isEffectSlurDestination() {
			return !!this.effectSlurOrigin;
		}
		/**
		* @clone_ignore
		* @json_ignore
		*/
		effectSlurOrigin = null;
		/**
		* @clone_ignore
		* @json_ignore
		*/
		effectSlurDestination = null;
		/**
		* The {@link Slur} object whose origin is this note. Populated by
		* `finish()`; non-null only on the chain-origin note of an effect
		* slur. Carries the inner articulation segments used by the
		* renderer to paint H/P/sl. labels along the arc.
		* @clone_ignore
		* @json_ignore
		* @internal
		*/
		effectSlur = null;
		/**
		* The ornament applied on the note.
		*/
		ornament = NoteOrnament.None;
		/**
		* The style customizations for this item.
		* @clone_ignore
		*/
		style;
		get stringTuning() {
			return this.beat.voice.bar.staff.capo + Note.getStringTuning(this.beat.voice.bar.staff, this.string);
		}
		static getStringTuning(staff, noteString) {
			if (staff.tuning.length > 0) return staff.tuning[staff.tuning.length - (noteString - 1) - 1];
			return 0;
		}
		get realValue() {
			return this.calculateRealValue(true, true);
		}
		get realValueWithoutHarmonic() {
			return this.calculateRealValue(true, false);
		}
		/**
		* Calculates the real note value of this note as midi key respecting the given options.
		* @param applyTranspositionPitch Whether or not to apply the transposition pitch of the current staff.
		* @param applyHarmonic Whether or not to apply harmonic pitches to the note.
		* @returns The calculated note value as midi key.
		*/
		calculateRealValue(applyTranspositionPitch, applyHarmonic) {
			const transpositionPitch = applyTranspositionPitch ? this.beat.voice.bar.staff.transpositionPitch : 0;
			if (applyHarmonic) {
				let realValue = this.calculateRealValue(applyTranspositionPitch, false);
				if (this.isStringed) if (this.harmonicType === HarmonicType.Natural) realValue = this.harmonicPitch + this.stringTuning - transpositionPitch;
				else realValue += this.harmonicPitch;
				return realValue;
			}
			if (this.isPercussion) return this.percussionArticulation;
			if (this.isStringed) return this.fret + this.stringTuning - transpositionPitch;
			if (this.isPiano) return this.octave * 12 + this.tone - transpositionPitch;
			return 0;
		}
		get harmonicPitch() {
			if (this.harmonicType === HarmonicType.None || !this.isStringed) return 0;
			const value = this.harmonicValue;
			if (ModelUtils.isAlmostEqualTo(value, 2.4)) return 36;
			if (ModelUtils.isAlmostEqualTo(value, 2.7)) return 34;
			if (value < 3) return 0;
			if (value <= 3.5) return 31;
			if (value <= 4) return 28;
			if (value <= 5) return 24;
			if (value <= 6) return 34;
			if (value <= 7) return 19;
			if (value <= 8.5) return 36;
			if (value <= 9) return 28;
			if (value <= 10) return 34;
			if (value <= 11) return 0;
			if (value <= 12) return 12;
			if (value < 14) return 0;
			if (value <= 15) return 34;
			if (value <= 16) return 28;
			if (value <= 17) return 36;
			if (value <= 18) return 0;
			if (value <= 19) return 19;
			if (value <= 21) return 0;
			if (value <= 22) return 36;
			if (value <= 24) return 24;
			return 0;
		}
		get initialBendValue() {
			if (this.hasBend) return Math.floor(this.bendPoints[0].value / 2);
			if (this.bendOrigin) return Math.floor(this.bendOrigin.bendPoints[this.bendOrigin.bendPoints.length - 1].value / 2);
			if (this.isTieDestination && this.tieOrigin.bendOrigin) return Math.floor(this.tieOrigin.bendOrigin.bendPoints[this.tieOrigin.bendOrigin.bendPoints.length - 1].value / 2);
			if (this.beat.hasWhammyBar) return Math.floor(this.beat.whammyBarPoints[0].value / 2);
			if (this.beat.isContinuedWhammy) return Math.floor(this.beat.previousBeat.whammyBarPoints[this.beat.previousBeat.whammyBarPoints.length - 1].value / 2);
			return 0;
		}
		get displayValue() {
			return this.displayValueWithoutBend + this.initialBendValue;
		}
		get displayValueWithoutBend() {
			let noteValue = this.realValue;
			if (this.harmonicType !== HarmonicType.Natural && this.harmonicType !== HarmonicType.None) noteValue -= this.harmonicPitch;
			switch (this.beat.ottava) {
				case Ottavia._15ma:
					noteValue -= 24;
					break;
				case Ottavia._8va:
					noteValue -= 12;
					break;
				case Ottavia.Regular: break;
				case Ottavia._8vb:
					noteValue += 12;
					break;
				case Ottavia._15mb:
					noteValue += 24;
					break;
			}
			switch (this.beat.voice.bar.clefOttava) {
				case Ottavia._15ma:
					noteValue -= 24;
					break;
				case Ottavia._8va:
					noteValue -= 12;
					break;
				case Ottavia.Regular: break;
				case Ottavia._8vb:
					noteValue += 12;
					break;
				case Ottavia._15mb:
					noteValue += 24;
					break;
			}
			return noteValue - this.beat.voice.bar.staff.displayTranspositionPitch;
		}
		get hasQuarterToneOffset() {
			if (this.hasBend) return this.bendPoints[0].value % 2 !== 0;
			if (this.bendOrigin) return this.bendOrigin.bendPoints[this.bendOrigin.bendPoints.length - 1].value % 2 !== 0;
			if (this.beat.hasWhammyBar) return this.beat.whammyBarPoints[0].value % 2 !== 0;
			if (this.beat.isContinuedWhammy) return this.beat.previousBeat.whammyBarPoints[this.beat.previousBeat.whammyBarPoints.length - 1].value % 2 !== 0;
			return false;
		}
		addBendPoint(point) {
			let points = this.bendPoints;
			if (points === null) {
				points = [];
				this.bendPoints = points;
			}
			points.push(point);
			if (!this.maxBendPoint || point.value > this.maxBendPoint.value) this.maxBendPoint = point;
			if (this.bendType === BendType.None) this.bendType = BendType.Custom;
		}
		finish(settings, sharedDataBag = null) {
			const nextNoteOnLine = new Lazy(() => Note.nextNoteOnSameLine(this));
			const isSongBook = settings && settings.notation.notationMode === NotationMode.SongBook;
			if (this.isTieDestination) {
				this.chain(sharedDataBag);
				if (isSongBook && this.tieOrigin && this.tieOrigin.isLetRing) this.isLetRing = true;
			}
			if (this.isLetRing) {
				if (!nextNoteOnLine.value || !nextNoteOnLine.value.isLetRing) this.letRingDestination = this;
				else this.letRingDestination = nextNoteOnLine.value;
				if (isSongBook && this.isTieDestination && !this.tieOrigin.hasBend) this.isVisible = false;
			}
			if (this.isPalmMute) if (!nextNoteOnLine.value || !nextNoteOnLine.value.isPalmMute) this.palmMuteDestination = this;
			else this.palmMuteDestination = nextNoteOnLine.value;
			if (this.isHammerPullOrigin) {
				const hammerPullDestination = Note.findHammerPullDestination(this);
				if (!hammerPullDestination) this.isHammerPullOrigin = false;
				else {
					this.hammerPullDestination = hammerPullDestination;
					hammerPullDestination.hammerPullOrigin = this;
				}
			}
			switch (this.slideOutType) {
				case SlideOutType.Shift:
				case SlideOutType.Legato:
					if (!this.slideTarget) this.slideTarget = nextNoteOnLine.value;
					if (!this.slideTarget) this.slideOutType = SlideOutType.None;
					else this.slideTarget.slideOrigin = this;
					break;
			}
			let effectSlurDestination = null;
			let effectSlurSegmentKind = null;
			if (this.isHammerPullOrigin && this.hammerPullDestination) {
				effectSlurDestination = this.hammerPullDestination;
				effectSlurSegmentKind = SlurSegmentKind.HammerPull;
			} else if (this.slideOutType === SlideOutType.Legato && this.slideTarget) {
				effectSlurDestination = this.slideTarget;
				effectSlurSegmentKind = SlurSegmentKind.LegatoSlide;
			}
			if (effectSlurDestination) {
				this.hasEffectSlur = true;
				if (this.effectSlurOrigin && this.beat.pickStroke === PickStroke.None) {
					const chainOrigin = this.effectSlurOrigin;
					chainOrigin.effectSlurDestination = effectSlurDestination;
					effectSlurDestination.effectSlurOrigin = chainOrigin;
					this.effectSlurOrigin = null;
					if (effectSlurSegmentKind !== null && chainOrigin.effectSlur !== null) {
						chainOrigin.effectSlur.destinationNote = effectSlurDestination;
						chainOrigin.effectSlur.segments.push({
							fromNote: this,
							toNote: effectSlurDestination,
							kind: effectSlurSegmentKind,
							text: null
						});
					}
				} else {
					this.isEffectSlurOrigin = true;
					this.effectSlurDestination = effectSlurDestination;
					effectSlurDestination.effectSlurOrigin = this;
					const slur = new Slur();
					slur.originNote = this;
					slur.destinationNote = effectSlurDestination;
					if (effectSlurSegmentKind !== null) slur.segments.push({
						fromNote: this,
						toNote: effectSlurDestination,
						kind: effectSlurSegmentKind,
						text: null
					});
					this.effectSlur = slur;
				}
			}
			const points = this.bendPoints;
			const hasBend = points != null && points.length > 0;
			if (hasBend) {
				const isContinuedBend = this.isTieDestination && this.tieOrigin.hasBend;
				this.isContinuedBend = isContinuedBend;
			} else this.bendType = BendType.None;
			if (hasBend && this.bendType === BendType.Custom) {
				if (points.length === 4) {
					const origin = points[0];
					const middle1 = points[1];
					const middle2 = points[2];
					const destination = points[3];
					if (middle1.value === middle2.value) if (destination.value > origin.value) if (middle1.value > destination.value) this.bendType = BendType.BendRelease;
					else if (!this.isContinuedBend && origin.value > 0) {
						this.bendType = BendType.PrebendBend;
						points.splice(2, 1);
						points.splice(1, 1);
					} else {
						this.bendType = BendType.Bend;
						points.splice(2, 1);
						points.splice(1, 1);
					}
					else if (destination.value < origin.value) if (this.isContinuedBend) {
						this.bendType = BendType.Release;
						points.splice(2, 1);
						points.splice(1, 1);
					} else {
						this.bendType = BendType.PrebendRelease;
						points.splice(2, 1);
						points.splice(1, 1);
					}
					else if (middle1.value > origin.value) this.bendType = BendType.BendRelease;
					else if (origin.value > 0 && !this.isContinuedBend) {
						this.bendType = BendType.Prebend;
						points.splice(2, 1);
						points.splice(1, 1);
					} else {
						this.bendType = BendType.Hold;
						points.splice(2, 1);
						points.splice(1, 1);
					}
					else Logger.warning("Model", "Unsupported bend type detected, fallback to custom", null);
				} else if (points.length === 3) {
					const origin = points[0];
					const middle = points[1];
					const destination = points[2];
					if (destination.value > origin.value) if (middle.value > destination.value) {
						this.bendType = BendType.BendRelease;
						points.splice(1, 0, new BendPoint(middle.offset, middle.value));
					} else if (!this.isContinuedBend && origin.value > 0) {
						this.bendType = BendType.PrebendBend;
						points.splice(1, 1);
					} else {
						this.bendType = BendType.Bend;
						points.splice(1, 1);
					}
					else if (destination.value < origin.value) if (this.isContinuedBend) {
						this.bendType = BendType.Release;
						points.splice(1, 1);
					} else {
						this.bendType = BendType.PrebendRelease;
						points.splice(1, 1);
					}
					else if (middle.value > origin.value) {
						this.bendType = BendType.BendRelease;
						points.splice(1, 0, new BendPoint(middle.offset, middle.value));
					} else if (origin.value > 0 && !this.isContinuedBend) {
						this.bendType = BendType.Prebend;
						points.splice(1, 1);
					} else {
						this.bendType = BendType.Hold;
						points.splice(1, 1);
					}
				} else if (points.length === 2) {
					const origin = points[0];
					const destination = points[1];
					if (destination.value > origin.value) if (!this.isContinuedBend && origin.value > 0) this.bendType = BendType.PrebendBend;
					else this.bendType = BendType.Bend;
					else if (destination.value < origin.value) if (this.isContinuedBend) this.bendType = BendType.Release;
					else this.bendType = BendType.PrebendRelease;
					else if (origin.value > 0 && !this.isContinuedBend) this.bendType = BendType.Prebend;
					else this.bendType = BendType.Hold;
				}
			}
			if (this.initialBendValue > 0) this.accidentalMode = NoteAccidentalMode.Default;
		}
		static _maxOffsetForSameLineSearch = 3;
		static nextNoteOnSameLine(note) {
			let nextBeat = note.beat.nextBeat;
			while (nextBeat && nextBeat.voice.bar.index <= note.beat.voice.bar.index + Note._maxOffsetForSameLineSearch) {
				const noteOnString = nextBeat.getNoteOnString(note.string);
				if (noteOnString) return noteOnString;
				nextBeat = nextBeat.nextBeat;
			}
			return null;
		}
		static findHammerPullDestination(note) {
			let nextBeat = note.beat.nextBeat;
			while (nextBeat && nextBeat.voice.bar.index <= note.beat.voice.bar.index + Note._maxOffsetForSameLineSearch) {
				let noteOnString = nextBeat.getNoteOnString(note.string);
				if (noteOnString) return noteOnString;
				for (let str = note.string; str > 0; str--) {
					noteOnString = nextBeat.getNoteOnString(str);
					if (noteOnString) {
						if (noteOnString.isLeftHandTapped) return noteOnString;
						break;
					}
				}
				for (let str = note.string; str <= note.beat.voice.bar.staff.tuning.length; str++) {
					noteOnString = nextBeat.getNoteOnString(str);
					if (noteOnString) {
						if (noteOnString.isLeftHandTapped) return noteOnString;
						break;
					}
				}
				nextBeat = nextBeat.nextBeat;
			}
			return null;
		}
		static findTieOrigin(note) {
			let previousBeat = note.beat.previousBeat;
			while (previousBeat && previousBeat.voice.bar.index >= note.beat.voice.bar.index - Note._maxOffsetForSameLineSearch) {
				if (note.isStringed) {
					const noteOnString = previousBeat.getNoteOnString(note.string);
					if (noteOnString) return noteOnString;
				} else if (note.octave === -1 && note.tone === -1) {
					if (note.index < previousBeat.notes.length) return previousBeat.notes[note.index];
				} else {
					const noteWithValue = previousBeat.getNoteWithRealValue(note.realValue);
					if (noteWithValue) return noteWithValue;
				}
				previousBeat = previousBeat.previousBeat;
			}
			return null;
		}
		static _noteIdLookupKey = "NoteIdLookup";
		_noteIdBag = null;
		chain(sharedDataBag = null) {
			if (sharedDataBag === null) return;
			if (this._noteIdBag !== null) {
				let noteIdLookup;
				if (sharedDataBag.has(Note._noteIdLookupKey)) noteIdLookup = sharedDataBag.get(Note._noteIdLookupKey);
				else {
					noteIdLookup = /* @__PURE__ */ new Map();
					sharedDataBag.set(Note._noteIdLookupKey, noteIdLookup);
				}
				if (this._noteIdBag.hammerPullDestinationNoteId !== -1 || this._noteIdBag.tieDestinationNoteId !== -1 || this._noteIdBag.slurDestinationNoteId !== -1 || this._noteIdBag.slideTargetNoteId !== -1) noteIdLookup.set(this.id, this);
				if (this._noteIdBag.hammerPullOriginNoteId !== -1) {
					this.hammerPullOrigin = noteIdLookup.get(this._noteIdBag.hammerPullOriginNoteId);
					this.hammerPullOrigin.hammerPullDestination = this;
				}
				if (this._noteIdBag.tieOriginNoteId !== -1) {
					this.tieOrigin = noteIdLookup.get(this._noteIdBag.tieOriginNoteId);
					this.tieOrigin.tieDestination = this;
				}
				if (this._noteIdBag.slurOriginNoteId !== -1) {
					this.slurOrigin = noteIdLookup.get(this._noteIdBag.slurOriginNoteId);
					this.slurOrigin.slurDestination = this;
				}
				if (this._noteIdBag.slideOriginNoteId !== -1) {
					this.slideOrigin = noteIdLookup.get(this._noteIdBag.slideOriginNoteId);
					this.slideOrigin.slideTarget = this;
				}
				this._noteIdBag = null;
			} else {
				if (!this.isTieDestination && this.tieOrigin === null) return;
				const tieOrigin = this.tieOrigin ?? Note.findTieOrigin(this);
				if (!tieOrigin) this.isTieDestination = false;
				else {
					tieOrigin.tieDestination = this;
					this.tieOrigin = tieOrigin;
					this.fret = tieOrigin.fret;
					this.octave = tieOrigin.octave;
					this.tone = tieOrigin.tone;
					if (tieOrigin.hasBend) this.bendOrigin = this.tieOrigin;
				}
			}
		}
		/**
		* @internal
		*/
		toJson(o) {
			if (this.tieDestination !== null) o.set("tiedestinationnoteid", this.tieDestination.id);
			if (this.tieOrigin !== null) o.set("tieoriginnoteid", this.tieOrigin.id);
			if (this.slurDestination !== null) o.set("slurdestinationnoteid", this.slurDestination.id);
			if (this.slurOrigin !== null) o.set("sluroriginnoteid", this.slurOrigin.id);
			if (this.hammerPullOrigin !== null) o.set("hammerpulloriginnoteid", this.hammerPullOrigin.id);
			if (this.hammerPullDestination !== null) o.set("hammerpulldestinationnoteid", this.hammerPullDestination.id);
			if (this.slideTarget !== null) o.set("slidetargetnoteid", this.slideTarget.id);
			if (this.slideOrigin !== null) o.set("slideoriginnoteid", this.slideOrigin.id);
		}
		/**
		* @internal
		*/
		setProperty(property, v) {
			switch (property) {
				case "tiedestinationnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.tieDestinationNoteId = v;
					return true;
				case "tieoriginnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.tieOriginNoteId = v;
					return true;
				case "slurdestinationnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.slurDestinationNoteId = v;
					return true;
				case "sluroriginnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.slurOriginNoteId = v;
					return true;
				case "hammerpulloriginnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.hammerPullOriginNoteId = v;
					return true;
				case "hammerpulldestinationnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.hammerPullDestinationNoteId = v;
					return true;
				case "slidetargetnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.slideTargetNoteId = v;
					return true;
				case "slideoriginnoteid":
					if (this._noteIdBag == null) this._noteIdBag = new NoteIdBag();
					this._noteIdBag.slideOriginNoteId = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/model/TupletGroup.ts
	/**
	* Represents a list of beats that are grouped within the same tuplet.
	* @public
	*/
	var TupletGroup = class TupletGroup {
		static _halfTicks = 1920;
		static _quarterTicks = 960;
		static _eighthTicks = 480;
		static _sixteenthTicks = 240;
		static _thirtySecondTicks = 120;
		static _sixtyFourthTicks = 60;
		static _oneHundredTwentyEighthTicks = 30;
		static _twoHundredFiftySixthTicks = 15;
		static _allTicks = [
			TupletGroup._halfTicks,
			TupletGroup._quarterTicks,
			TupletGroup._eighthTicks,
			TupletGroup._sixteenthTicks,
			TupletGroup._thirtySecondTicks,
			TupletGroup._sixtyFourthTicks,
			TupletGroup._oneHundredTwentyEighthTicks,
			TupletGroup._twoHundredFiftySixthTicks
		];
		_isEqualLengthTuplet = true;
		totalDuration = 0;
		/**
		* Gets or sets the list of beats contained in this group.
		*/
		beats = [];
		/**
		* Gets or sets the voice this group belongs to.
		*/
		voice;
		/**
		* Gets a value indicating whether the tuplet group is fully filled.
		*/
		isFull = false;
		/**
		* Initializes a new instance of the {@link TupletGroup} class.
		* @param voice The voice this group belongs to.
		*/
		constructor(voice) {
			this.voice = voice;
		}
		check(beat) {
			if (this.beats.length === 0) {
				this.beats.push(beat);
				this.totalDuration += beat.playbackDuration;
				return true;
			}
			if (beat.graceType !== GraceType.None) return true;
			if (beat.voice !== this.voice || this.isFull || beat.tupletNumerator !== this.beats[0].tupletNumerator || beat.tupletDenominator !== this.beats[0].tupletDenominator) return false;
			if (beat.displayDuration !== this.beats[0].displayDuration) this._isEqualLengthTuplet = false;
			this.beats.push(beat);
			this.totalDuration += beat.displayDuration;
			if (this._isEqualLengthTuplet) {
				if (this.beats.length === this.beats[0].tupletNumerator) this.isFull = true;
			} else {
				const factor = this.beats[0].tupletNumerator / this.beats[0].tupletDenominator | 0;
				for (const potentialMatch of TupletGroup._allTicks) if (this.totalDuration === potentialMatch * factor) {
					this.isFull = true;
					break;
				}
			}
			return true;
		}
	};
	//#endregion
	//#region src/model/WhammyType.ts
	/**
	* Lists all types of whammy bars
	* @public
	*/
	var WhammyType = /* @__PURE__ */ function(WhammyType) {
		/**
		* No whammy at all
		*/
		WhammyType[WhammyType["None"] = 0] = "None";
		/**
		* Individual points define the whammy in a flexible manner.
		* This system was mainly used in Guitar Pro 3-5
		*/
		WhammyType[WhammyType["Custom"] = 1] = "Custom";
		/**
		* Simple dive to a lower or higher note.
		*/
		WhammyType[WhammyType["Dive"] = 2] = "Dive";
		/**
		* A dive to a lower or higher note and releasing it back to normal.
		*/
		WhammyType[WhammyType["Dip"] = 3] = "Dip";
		/**
		* Continue to hold the whammy at the position from a previous whammy.
		*/
		WhammyType[WhammyType["Hold"] = 4] = "Hold";
		/**
		* Dive to a lower or higher note before playing it.
		*/
		WhammyType[WhammyType["Predive"] = 5] = "Predive";
		/**
		* Dive to a lower or higher note before playing it, then change to another
		* note.
		*/
		WhammyType[WhammyType["PrediveDive"] = 6] = "PrediveDive";
		return WhammyType;
	}({});
	//#endregion
	//#region src/model/GolpeType.ts
	/**
	* Lists all golpe types.
	* @public
	*/
	var GolpeType = /* @__PURE__ */ function(GolpeType) {
		/**
		* No Golpe played.
		*/
		GolpeType[GolpeType["None"] = 0] = "None";
		/**
		* Play a golpe with the thumb.
		*/
		GolpeType[GolpeType["Thumb"] = 1] = "Thumb";
		/**
		* Play a golpe with a finger.
		*/
		GolpeType[GolpeType["Finger"] = 2] = "Finger";
		return GolpeType;
	}({});
	//#endregion
	//#region src/model/FadeType.ts
	/**
	* Lists the different fade types.
	* @public
	*/
	var FadeType = /* @__PURE__ */ function(FadeType) {
		/**
		* No fading
		*/
		FadeType[FadeType["None"] = 0] = "None";
		/**
		* Fade-in the sound.
		*/
		FadeType[FadeType["FadeIn"] = 1] = "FadeIn";
		/**
		* Fade-out the sound.
		*/
		FadeType[FadeType["FadeOut"] = 2] = "FadeOut";
		/**
		* Fade-in and then fade-out the sound.
		*/
		FadeType[FadeType["VolumeSwell"] = 3] = "VolumeSwell";
		return FadeType;
	}({});
	//#endregion
	//#region src/model/WahPedal.ts
	/**
	* Lists all wah pedal modes.
	* @public
	*/
	var WahPedal = /* @__PURE__ */ function(WahPedal) {
		WahPedal[WahPedal["None"] = 0] = "None";
		WahPedal[WahPedal["Open"] = 1] = "Open";
		WahPedal[WahPedal["Closed"] = 2] = "Closed";
		return WahPedal;
	}({});
	//#endregion
	//#region src/model/BarreShape.ts
	/**
	* Lists all beat barré types.
	* @public
	*/
	var BarreShape = /* @__PURE__ */ function(BarreShape) {
		/**
		* No Barré
		*/
		BarreShape[BarreShape["None"] = 0] = "None";
		/**
		* Full Barré (play all strings)
		*/
		BarreShape[BarreShape["Full"] = 1] = "Full";
		/**
		* 1/2 Barré (play only half the strings)
		*/
		BarreShape[BarreShape["Half"] = 2] = "Half";
		return BarreShape;
	}({});
	//#endregion
	//#region src/model/Rasgueado.ts
	/**
	* Lists all Rasgueado types.
	* @public
	*/
	var Rasgueado = /* @__PURE__ */ function(Rasgueado) {
		Rasgueado[Rasgueado["None"] = 0] = "None";
		Rasgueado[Rasgueado["Ii"] = 1] = "Ii";
		Rasgueado[Rasgueado["Mi"] = 2] = "Mi";
		Rasgueado[Rasgueado["MiiTriplet"] = 3] = "MiiTriplet";
		Rasgueado[Rasgueado["MiiAnapaest"] = 4] = "MiiAnapaest";
		Rasgueado[Rasgueado["PmpTriplet"] = 5] = "PmpTriplet";
		Rasgueado[Rasgueado["PmpAnapaest"] = 6] = "PmpAnapaest";
		Rasgueado[Rasgueado["PeiTriplet"] = 7] = "PeiTriplet";
		Rasgueado[Rasgueado["PeiAnapaest"] = 8] = "PeiAnapaest";
		Rasgueado[Rasgueado["PaiTriplet"] = 9] = "PaiTriplet";
		Rasgueado[Rasgueado["PaiAnapaest"] = 10] = "PaiAnapaest";
		Rasgueado[Rasgueado["AmiTriplet"] = 11] = "AmiTriplet";
		Rasgueado[Rasgueado["AmiAnapaest"] = 12] = "AmiAnapaest";
		Rasgueado[Rasgueado["Ppp"] = 13] = "Ppp";
		Rasgueado[Rasgueado["Amii"] = 14] = "Amii";
		Rasgueado[Rasgueado["Amip"] = 15] = "Amip";
		Rasgueado[Rasgueado["Eami"] = 16] = "Eami";
		Rasgueado[Rasgueado["Eamii"] = 17] = "Eamii";
		Rasgueado[Rasgueado["Peami"] = 18] = "Peami";
		return Rasgueado;
	}({});
	//#endregion
	//#region src/model/TremoloPickingEffect.ts
	/**
	* The style of tremolo affecting mainly the display of the effect.
	* @public
	*/
	var TremoloPickingStyle = /* @__PURE__ */ function(TremoloPickingStyle) {
		/**
		* A classic tremolo expressed by diagonal bars on the stem.
		*/
		TremoloPickingStyle[TremoloPickingStyle["Default"] = 0] = "Default";
		/**
		* A buzz roll tremolo expressed by a 'z' shaped symbol.
		*/
		TremoloPickingStyle[TremoloPickingStyle["BuzzRoll"] = 1] = "BuzzRoll";
		return TremoloPickingStyle;
	}({});
	/**
	* Describes a tremolo picking effect.
	* @json
	* @json_strict
	* @cloneable
	* @public
	*/
	var TremoloPickingEffect = class {
		/**
		* The minimum number of marks for the tremolo picking effect to be valid.
		*/
		static minMarks = 0;
		/**
		* The max number of marks for the tremolo picking effect to be valid.
		*/
		static maxMarks = 5;
		/**
		* The number of marks for the tremolo.
		* A mark is equal to a single bar shown for a default tremolos.
		*/
		marks = 0;
		/**
		* The style of the tremolo picking.
		*/
		style = 0;
		/**
		* @internal
		* @deprecated use {@link getDurationAsTicks} to handle tremolo durations shorter than typical durations.
		*/
		getDuration(beatDuration) {
			let marks = this.marks;
			if (marks < 1) marks = 1;
			const actualDuration = beatDuration * Math.pow(2, marks);
			if (actualDuration <= Duration.TwoHundredFiftySixth) return actualDuration;
			else return Duration.TwoHundredFiftySixth;
		}
		/**
		* Gets the duration of a single tremolo note played in a beat of the given duration
		* based on the configured marks.
		*/
		getDurationAsTicks(beatDuration) {
			let marks = this.marks;
			if (marks < 1) marks = 1;
			const actualDuration = beatDuration * Math.pow(2, marks);
			return MidiUtils.valueToTicks(actualDuration);
		}
	};
	//#endregion
	//#region src/model/Beat.ts
	/**
	* Lists the different modes on how beaming for a beat should be done.
	* @public
	*/
	var BeatBeamingMode = /* @__PURE__ */ function(BeatBeamingMode) {
		/**
		* Automatic beaming based on the timing rules.
		*/
		BeatBeamingMode[BeatBeamingMode["Auto"] = 0] = "Auto";
		/**
		* Force a split to the next beat.
		*/
		BeatBeamingMode[BeatBeamingMode["ForceSplitToNext"] = 1] = "ForceSplitToNext";
		/**
		* Force a merge with the next beat.
		*/
		BeatBeamingMode[BeatBeamingMode["ForceMergeWithNext"] = 2] = "ForceMergeWithNext";
		/**
		* Force a split to the next beat on the secondary beam.
		*/
		BeatBeamingMode[BeatBeamingMode["ForceSplitOnSecondaryToNext"] = 3] = "ForceSplitOnSecondaryToNext";
		return BeatBeamingMode;
	}({});
	/**
	* Lists all graphical sub elements within a {@link Beat} which can be styled via {@link Beat.style}
	* @public
	*/
	var BeatSubElement = /* @__PURE__ */ function(BeatSubElement) {
		/**
		* The effects and annotations shown in dedicated effect bands above the staves (e.g. fermata).
		* Only applies to items which are on beat level but not any individual note level effects.
		*/
		BeatSubElement[BeatSubElement["Effects"] = 0] = "Effects";
		/**
		* The stems drawn for note heads in this beat on the standard notation staff.
		*/
		BeatSubElement[BeatSubElement["StandardNotationStem"] = 1] = "StandardNotationStem";
		/**
		* The flags drawn for note heads in this beat on the standard notation staff.
		*/
		BeatSubElement[BeatSubElement["StandardNotationFlags"] = 2] = "StandardNotationFlags";
		/**
		* The beams drawn between this and the next beat on the standard notation staff.
		*/
		BeatSubElement[BeatSubElement["StandardNotationBeams"] = 3] = "StandardNotationBeams";
		/**
		* The tuplet drawn on the standard notation staff (the first beat affects the whole tuplet if grouped).
		*/
		BeatSubElement[BeatSubElement["StandardNotationTuplet"] = 4] = "StandardNotationTuplet";
		/**
		* The effects and annotations applied to this beat on the standard notation staff (e.g. brushes).
		* Only applies to items which are on beat level but not any individual note level effects.
		*/
		BeatSubElement[BeatSubElement["StandardNotationEffects"] = 5] = "StandardNotationEffects";
		/**
		* The rest symbol on the standard notation staff.
		*/
		BeatSubElement[BeatSubElement["StandardNotationRests"] = 6] = "StandardNotationRests";
		/**
		* The stems drawn for note heads in this beat on the guitar tab staff.
		*/
		BeatSubElement[BeatSubElement["GuitarTabStem"] = 7] = "GuitarTabStem";
		/**
		* The flags drawn for note heads in this beat on the guitar tab staff.
		*/
		BeatSubElement[BeatSubElement["GuitarTabFlags"] = 8] = "GuitarTabFlags";
		/**
		* The beams drawn between this and the next beat on the guitar tab staff.
		*/
		BeatSubElement[BeatSubElement["GuitarTabBeams"] = 9] = "GuitarTabBeams";
		/**
		* The tuplet drawn on the guitar tab staff (the first beat affects the whole tuplet if grouped).
		*/
		BeatSubElement[BeatSubElement["GuitarTabTuplet"] = 10] = "GuitarTabTuplet";
		/**
		* The effects and annotations applied to this beat on the guitar tab staff (e.g. brushes).
		* Only applies to items which are on beat level but not any individual note level effects.
		*/
		BeatSubElement[BeatSubElement["GuitarTabEffects"] = 11] = "GuitarTabEffects";
		/**
		* The rest symbol on the guitar tab staff.
		*/
		BeatSubElement[BeatSubElement["GuitarTabRests"] = 12] = "GuitarTabRests";
		/**
		* The stems drawn for note heads in this beat on the slash staff.
		*/
		BeatSubElement[BeatSubElement["SlashStem"] = 13] = "SlashStem";
		/**
		* The flags drawn for note heads in this beat on the slash staff.
		*/
		BeatSubElement[BeatSubElement["SlashFlags"] = 14] = "SlashFlags";
		/**
		* The beams drawn between this and the next beat on the slash staff.
		*/
		BeatSubElement[BeatSubElement["SlashBeams"] = 15] = "SlashBeams";
		/**
		* The tuplet drawn on the slash staff (the first beat affects the whole tuplet if grouped).
		*/
		BeatSubElement[BeatSubElement["SlashTuplet"] = 16] = "SlashTuplet";
		/**
		* The rest symbol on the slash staff.
		*/
		BeatSubElement[BeatSubElement["SlashRests"] = 17] = "SlashRests";
		/**
		* The effects and annotations applied to this beat on the slash staff (e.g. brushes).
		* Only applies to items which are on beat level but not any individual note level effects.
		*/
		BeatSubElement[BeatSubElement["SlashEffects"] = 18] = "SlashEffects";
		/**
		* The duration lines drawn for this beat on the numbered notation staff.
		*/
		BeatSubElement[BeatSubElement["NumberedDuration"] = 19] = "NumberedDuration";
		/**
		* The effects and annotations applied to this beat on the numbered notation staff (e.g. brushes).
		* Only applies to items which are on beat level but not any individual note level effects.
		*/
		BeatSubElement[BeatSubElement["NumberedEffects"] = 20] = "NumberedEffects";
		/**
		* The rest (0) on the numbered notation staff.
		*/
		BeatSubElement[BeatSubElement["NumberedRests"] = 21] = "NumberedRests";
		/**
		* The tuplet drawn on the numbered notation staff (the first beat affects the whole tuplet if grouped).
		*/
		BeatSubElement[BeatSubElement["NumberedTuplet"] = 22] = "NumberedTuplet";
		return BeatSubElement;
	}({});
	/**
	* Defines the custom styles for beats.
	* @json
	* @json_strict
	* @public
	*/
	var BeatStyle = class extends ElementStyle {};
	/**
	* A beat is a single block within a bar. A beat is a combination
	* of several notes played at the same time.
	* @json
	* @json_strict
	* @cloneable
	* @public
	*/
	var Beat = class Beat {
		static _globalBeatId = 0;
		/**
		* @internal
		*/
		static resetIds() {
			Beat._globalBeatId = 0;
		}
		/**
		* Gets or sets the unique id of this beat.
		* @clone_ignore
		*/
		id = Beat._globalBeatId++;
		/**
		* Gets or sets the zero-based index of this beat within the voice.
		* @json_ignore
		*/
		index = 0;
		/**
		* Gets or sets the previous beat within the whole song.
		* @json_ignore
		* @clone_ignore
		*/
		previousBeat = null;
		/**
		* Gets or sets the next beat within the whole song.
		* @json_ignore
		* @clone_ignore
		*/
		nextBeat = null;
		get isLastOfVoice() {
			return this.index === this.voice.beats.length - 1;
		}
		/**
		* Gets or sets the reference to the parent voice this beat belongs to.
		* @json_ignore
		* @clone_ignore
		*/
		voice;
		/**
		* Gets or sets the list of notes contained in this beat.
		* @json_add addNote
		* @clone_add addNote
		*/
		notes = [];
		/**
		* Gets the lookup where the notes per string are registered.
		* If this staff contains string based notes this lookup allows fast access.
		* @json_ignore
		*/
		noteStringLookup = /* @__PURE__ */ new Map();
		/**
		* Gets the lookup where the notes per value are registered.
		* If this staff contains string based notes this lookup allows fast access.
		* @json_ignore
		*/
		noteValueLookup = /* @__PURE__ */ new Map();
		/**
		* Gets or sets a value indicating whether this beat is considered empty.
		*/
		isEmpty = false;
		/**
		* Gets or sets which whammy bar style should be used for this bar.
		*/
		whammyStyle = BendStyle.Default;
		/**
		* Gets or sets the ottava applied to this beat.
		*/
		ottava = Ottavia.Regular;
		/**
		* Gets or sets the fermata applied to this beat.
		* @clone_ignore
		* @json_ignore
		*/
		fermata = null;
		/**
		* Gets a value indicating whether this beat starts a legato slur.
		*/
		isLegatoOrigin = false;
		get isLegatoDestination() {
			return !!this.previousBeat && this.previousBeat.isLegatoOrigin;
		}
		/**
		* Gets or sets the note with the lowest pitch in this beat. Only visible notes are considered.
		* @json_ignore
		* @clone_ignore
		*/
		minNote = null;
		/**
		* Gets or sets the note with the highest pitch in this beat. Only visible notes are considered.
		* @json_ignore
		* @clone_ignore
		*/
		maxNote = null;
		/**
		* Gets or sets the note with the highest string number in this beat. Only visible notes are considered.
		* @json_ignore
		* @clone_ignore
		*/
		maxStringNote = null;
		/**
		* Gets or sets the note with the lowest string number in this beat. Only visible notes are considered.
		* @json_ignore
		* @clone_ignore
		*/
		minStringNote = null;
		/**
		* Gets or sets the duration of this beat.
		*/
		duration = Duration.Quarter;
		get isRest() {
			return this.isEmpty || !this.deadSlapped && this.notes.length === 0;
		}
		/**
		* Gets a value indicating whether this beat is a full bar rest.
		*/
		get isFullBarRest() {
			return this.isRest && this.voice.beats.length === 1 && this.duration === Duration.Whole;
		}
		/**
		* Gets or sets whether any note in this beat has a let-ring applied.
		* @json_ignore
		*/
		isLetRing = false;
		/**
		* Gets or sets whether any note in this beat has a palm-mute applied.
		* @json_ignore
		*/
		isPalmMute = false;
		/**
		* Gets or sets a list of all automations on this beat.
		*/
		automations = [];
		/**
		* Gets or sets the number of dots applied to the duration of this beat.
		*/
		dots = 0;
		/**
		* Gets a value indicating whether this beat is fade-in.
		* @deprecated Use `fade`
		*/
		get fadeIn() {
			return this.fade === FadeType.FadeIn;
		}
		/**
		* Sets a value indicating whether this beat is fade-in.
		* @deprecated Use `fade`
		*/
		set fadeIn(value) {
			this.fade = value ? FadeType.FadeIn : FadeType.None;
		}
		/**
		* Gets or sets a value indicating whether this beat is fade-in.
		*/
		fade = FadeType.None;
		/**
		* Gets or sets the lyrics shown on this beat.
		*/
		lyrics = null;
		/**
		* Gets or sets a value indicating whether the beat is played in rasgueado style.
		*/
		get hasRasgueado() {
			return this.rasgueado !== Rasgueado.None;
		}
		/**
		* Gets or sets a value indicating whether the notes on this beat are played with a pop-style (bass).
		*/
		pop = false;
		/**
		* Gets or sets a value indicating whether the notes on this beat are played with a slap-style (bass).
		*/
		slap = false;
		/**
		* Gets or sets a value indicating whether the notes on this beat are played with a tap-style (bass).
		*/
		tap = false;
		/**
		* Gets or sets the text annotation shown on this beat.
		*/
		text = null;
		/**
		* Gets or sets whether this beat should be rendered as slashed note.
		*/
		slashed = false;
		/**
		* Whether this beat should rendered and played as "dead slapped".
		*/
		deadSlapped = false;
		/**
		* Gets or sets the brush type applied to the notes of this beat.
		*/
		brushType = BrushType.None;
		/**
		* Gets or sets the duration of the brush between the notes in midi ticks.
		*/
		brushDuration = 0;
		/**
		* Gets or sets the tuplet denominator.
		*/
		tupletDenominator = -1;
		/**
		* Gets or sets the tuplet numerator.
		*/
		tupletNumerator = -1;
		get hasTuplet() {
			return !(this.tupletDenominator === -1 && this.tupletNumerator === -1) && !(this.tupletDenominator === 1 && this.tupletNumerator === 1);
		}
		/**
		* @clone_ignore
		* @json_ignore
		*/
		tupletGroup = null;
		/**
		* Gets or sets whether this beat continues a whammy effect.
		*/
		isContinuedWhammy = false;
		/**
		* Gets or sets the whammy bar style of this beat.
		*/
		whammyBarType = WhammyType.None;
		/**
		* Gets or sets the points defining the whammy bar usage.
		* @json_add addWhammyBarPoint
		* @clone_add addWhammyBarPoint
		*/
		whammyBarPoints = null;
		/**
		* Gets or sets the highest point with for the highest whammy bar value.
		* @json_ignore
		* @clone_ignore
		*/
		maxWhammyPoint = null;
		/**
		* Gets or sets the highest point with for the lowest whammy bar value.
		* @json_ignore
		* @clone_ignore
		*/
		minWhammyPoint = null;
		get hasWhammyBar() {
			return this.whammyBarPoints !== null && this.whammyBarType !== WhammyType.None;
		}
		/**
		* Gets or sets the vibrato effect used on this beat.
		*/
		vibrato = VibratoType.None;
		/**
		* Gets or sets the ID of the chord used on this beat.
		*/
		chordId = null;
		get hasChord() {
			return !!this.chordId;
		}
		get chord() {
			return this.chordId ? this.voice.bar.staff.getChord(this.chordId) : null;
		}
		/**
		* Gets or sets the grace style of this beat.
		*/
		graceType = GraceType.None;
		/**
		* Gets or sets the grace group this beat belongs to.
		* If this beat is not a grace note, it holds the group which belongs to this beat.
		* @json_ignore
		* @clone_ignore
		*/
		graceGroup = null;
		/**
		* Gets or sets the index of this beat within the grace group if
		* this is a grace beat.
		* @json_ignore
		* @clone_ignore
		*/
		graceIndex = -1;
		/**
		* Gets or sets the pickstroke applied on this beat.
		*/
		pickStroke = PickStroke.None;
		/**
		* Whether this beat has a tremolo picking effect.
		*/
		get isTremolo() {
			return this.tremoloPicking !== void 0;
		}
		/**
		* The tremolo picking effect.
		*/
		tremoloPicking;
		/**
		* The speed of the tremolo.
		* @deprecated Set {@link tremoloPicking} instead.
		*/
		get tremoloSpeed() {
			const tremolo = this.tremoloPicking;
			if (tremolo) return tremolo.getDuration(this.duration);
			return null;
		}
		/**
		* The speed of the tremolo.
		* @deprecated Set {@link tremoloPicking} instead.
		*/
		set tremoloSpeed(value) {
			if (value === null) {
				this.tremoloPicking = void 0;
				return;
			}
			let effect = this.tremoloPicking;
			if (effect === void 0) {
				effect = new TremoloPickingEffect();
				this.tremoloPicking = effect;
			}
			switch (value) {
				case Duration.Eighth:
					effect.marks = 1;
					break;
				case Duration.Sixteenth:
					effect.marks = 2;
					break;
				case Duration.ThirtySecond:
					effect.marks = 3;
					break;
				case Duration.SixtyFourth:
					effect.marks = 4;
					break;
				case Duration.OneHundredTwentyEighth:
					effect.marks = 5;
					break;
			}
		}
		/**
		* Gets or sets whether a crescendo/decrescendo is applied on this beat.
		*/
		crescendo = CrescendoType.None;
		/**
		* The timeline position of the voice within the current bar as it is displayed. (unit: midi ticks)
		* This might differ from the actual playback time due to special grace types.
		*/
		displayStart = 0;
		/**
		* The calculated visual end position of this beat in midi ticks.
		*/
		get displayEnd() {
			return this.displayStart + this.displayDuration;
		}
		/**
		* The timeline position of the voice within the current bar as it is played. (unit: midi ticks)
		* This might differ from the actual playback time due to special grace types.
		*/
		playbackStart = 0;
		/**
		* Gets or sets the duration that is used for the display of this beat. It defines the size/width of the beat in
		* the music sheet. (unit: midi ticks).
		*/
		displayDuration = 0;
		/**
		* Gets or sets the duration that the note is played during the audio generation.
		*/
		playbackDuration = 0;
		/**
		* The duration in midi ticks to use for this beat on the {@link displayDuration}
		* controlling the visual display of the beat.
		* @remarks
		* This is used in scenarios where the bar might not have 100% exactly
		* a linear structure between the beats. e.g. in MusicXML when using `<forward />`.
		*/
		overrideDisplayDuration;
		/**
		* The type of golpe to play.
		*/
		golpe = GolpeType.None;
		get absoluteDisplayStart() {
			return this.voice.bar.masterBar.start + this.displayStart;
		}
		get absolutePlaybackStart() {
			return this.voice.bar.masterBar.start + this.playbackStart;
		}
		/**
		* Gets or sets the dynamics applied to this beat.
		*/
		dynamics = DynamicValue.F;
		/**
		* Gets or sets a value indicating whether the beam direction should be inverted.
		*/
		invertBeamDirection = false;
		/**
		* Gets or sets the preferred beam direction as specified in the input source.
		*/
		preferredBeamDirection = null;
		/**
		* @json_ignore
		*/
		isEffectSlurOrigin = false;
		get isEffectSlurDestination() {
			return !!this.effectSlurOrigin;
		}
		/**
		* @clone_ignore
		* @json_ignore
		*/
		effectSlurOrigin = null;
		/**
		* @clone_ignore
		* @json_ignore
		*/
		effectSlurDestination = null;
		/**
		* Convenience accessor for the {@link Slur} of this beat. Returns
		* the effect slur of whichever note in this beat owns it (the
		* chain-origin note populated during `Note.finish()`), or `null`
		* when no note in the beat is an effect-slur origin.
		* @clone_ignore
		* @json_ignore
		* @internal
		*/
		get effectSlur() {
			for (const n of this.notes) if (n.effectSlur !== null) return n.effectSlur;
			return null;
		}
		/**
		* Gets or sets how the beaming should be done for this beat.
		*/
		beamingMode = 0;
		/**
		* Whether the wah pedal should be used when playing the beat.
		*/
		wahPedal = WahPedal.None;
		/**
		* The fret of a barré being played on this beat.
		*/
		barreFret = -1;
		/**
		* The shape how the barre should be played on this beat.
		*/
		barreShape = BarreShape.None;
		/**
		* Gets a value indicating whether the beat should be played as Barré
		*/
		get isBarre() {
			return this.barreShape !== BarreShape.None && this.barreFret >= 0;
		}
		/**
		* The Rasgueado pattern to play with this beat.
		*/
		rasgueado = Rasgueado.None;
		/**
		* Whether to show the time when this beat is played the first time.
		* (requires that the midi for the song is generated so that times are calculated).
		* If no midi is generated the timer value might be filled from the input file (or manually).
		*/
		showTimer = false;
		/**
		* The absolute time in milliseconds when this beat will be played the first time.
		*/
		timer = null;
		/**
		* The style customizations for this item.
		* @clone_ignore
		*/
		style;
		addWhammyBarPoint(point) {
			let points = this.whammyBarPoints;
			if (points === null) {
				points = [];
				this.whammyBarPoints = points;
			}
			points.push(point);
			if (!this.maxWhammyPoint || point.value > this.maxWhammyPoint.value) this.maxWhammyPoint = point;
			if (!this.minWhammyPoint || point.value < this.minWhammyPoint.value) this.minWhammyPoint = point;
			if (this.whammyBarType === WhammyType.None) this.whammyBarType = WhammyType.Custom;
		}
		removeWhammyBarPoint(index) {
			const points = this.whammyBarPoints;
			if (points === null || index < 0 || index >= points.length) return;
			points.splice(index, 1);
			const point = points[index];
			if (point === this.maxWhammyPoint) {
				this.maxWhammyPoint = null;
				for (const currentPoint of points) if (!this.maxWhammyPoint || currentPoint.value > this.maxWhammyPoint.value) this.maxWhammyPoint = currentPoint;
			}
			if (point === this.minWhammyPoint) {
				this.minWhammyPoint = null;
				for (const currentPoint of points) if (!this.minWhammyPoint || currentPoint.value < this.minWhammyPoint.value) this.minWhammyPoint = currentPoint;
			}
		}
		addNote(note) {
			note.beat = this;
			note.index = this.notes.length;
			this.notes.push(note);
			if (note.isStringed) this.noteStringLookup.set(note.string, note);
		}
		removeNote(note) {
			const index = this.notes.indexOf(note);
			if (index >= 0) {
				this.notes.splice(index, 1);
				if (note.isStringed) this.noteStringLookup.delete(note.string);
			}
		}
		getAutomation(type) {
			for (let i = 0, j = this.automations.length; i < j; i++) {
				const automation = this.automations[i];
				if (automation.type === type) return automation;
			}
			return null;
		}
		getNoteOnString(noteString) {
			if (this.noteStringLookup.has(noteString)) return this.noteStringLookup.get(noteString);
			return null;
		}
		_calculateDuration() {
			if (this.overrideDisplayDuration !== void 0) return this.overrideDisplayDuration;
			if (this.isFullBarRest) return this.voice.bar.masterBar.calculateDuration();
			let ticks = MidiUtils.toTicks(this.duration);
			if (this.dots === 2) ticks = MidiUtils.applyDot(ticks, true);
			else if (this.dots === 1) ticks = MidiUtils.applyDot(ticks, false);
			if (this.tupletDenominator > 0 && this.tupletNumerator >= 0) ticks = MidiUtils.applyTuplet(ticks, this.tupletNumerator, this.tupletDenominator);
			return ticks;
		}
		updateDurations() {
			const ticks = this._calculateDuration();
			this.playbackDuration = ticks;
			switch (this.graceType) {
				case GraceType.BeforeBeat:
				case GraceType.OnBeat:
					switch (this.duration) {
						case Duration.Sixteenth:
							this.playbackDuration = MidiUtils.toTicks(Duration.SixtyFourth);
							break;
						case Duration.ThirtySecond:
							this.playbackDuration = MidiUtils.toTicks(Duration.OneHundredTwentyEighth);
							break;
						default:
							this.playbackDuration = MidiUtils.toTicks(Duration.ThirtySecond);
							break;
					}
					this.displayDuration = 0;
					break;
				case GraceType.BendGrace:
					this.playbackDuration /= 2;
					this.displayDuration = 0;
					break;
				default:
					this.displayDuration = ticks;
					const previous = this.previousBeat;
					if (previous && previous.graceType === GraceType.BendGrace) this.playbackDuration = previous.playbackDuration;
					break;
			}
		}
		finishTuplet() {
			const previousBeat = this.previousBeat;
			let currentTupletGroup = previousBeat ? previousBeat.tupletGroup : null;
			if (this.hasTuplet || this.graceType !== GraceType.None && currentTupletGroup) {
				if (!previousBeat || !currentTupletGroup || !currentTupletGroup.check(this)) {
					currentTupletGroup = new TupletGroup(this.voice);
					currentTupletGroup.check(this);
				}
				this.tupletGroup = currentTupletGroup;
			}
			const barDuration = this.voice.bar.masterBar.calculateDuration(false);
			const validBeatAutomations = [];
			for (const automation of this.automations) {
				if (automation.ratioPosition === 0) automation.ratioPosition = this.playbackStart / barDuration;
				if (automation.type !== AutomationType.Tempo) validBeatAutomations.push(automation);
			}
			this.automations = validBeatAutomations;
		}
		finish(settings, sharedDataBag = null) {
			if (this.getAutomation(AutomationType.Instrument) === null && this.index === 0 && this.voice.index === 0 && this.voice.bar.index === 0 && this.voice.bar.staff.index === 0) this.automations.push(Automation.buildInstrumentAutomation(false, 0, this.voice.bar.staff.track.playbackInfo.program));
			switch (this.graceType) {
				case GraceType.OnBeat:
				case GraceType.BeforeBeat:
					const numberOfGraceBeats = this.graceGroup.beats.length;
					if (numberOfGraceBeats === 1) this.duration = Duration.Eighth;
					else if (numberOfGraceBeats === 2) this.duration = Duration.Sixteenth;
					else this.duration = Duration.ThirtySecond;
					break;
			}
			if (this.brushType === BrushType.None) this.brushDuration = 0;
			const tremolo = this.tremoloPicking;
			if (tremolo !== void 0) {
				if (tremolo.marks < TremoloPickingEffect.minMarks || tremolo.marks > TremoloPickingEffect.maxMarks) this.tremoloPicking = void 0;
			}
			const displayMode = !settings ? NotationMode.GuitarPro : settings.notation.notationMode;
			let isGradual = this.text === "grad" || this.text === "grad.";
			if (isGradual && displayMode === NotationMode.SongBook) this.text = "";
			let needCopyBeatForBend = false;
			this.minNote = null;
			this.maxNote = null;
			this.minStringNote = null;
			this.maxStringNote = null;
			let visibleNotes = 0;
			let isEffectSlurBeat = false;
			for (let i = 0, j = this.notes.length; i < j; i++) {
				const note = this.notes[i];
				note.dynamics = this.dynamics;
				note.finish(settings, sharedDataBag);
				if (note.isLetRing) this.isLetRing = true;
				if (note.isPalmMute) this.isPalmMute = true;
				if (displayMode === NotationMode.SongBook && note.hasBend && this.graceType !== GraceType.BendGrace) {
					if (!note.isTieOrigin) switch (note.bendType) {
						case BendType.Bend:
						case BendType.PrebendRelease:
						case BendType.PrebendBend:
							needCopyBeatForBend = true;
							break;
					}
					if (isGradual || note.bendStyle === BendStyle.Gradual) {
						isGradual = true;
						note.bendStyle = BendStyle.Gradual;
						needCopyBeatForBend = false;
					} else note.bendStyle = BendStyle.Fast;
				}
				if (note.isVisible) {
					visibleNotes++;
					if (!this.minNote || note.realValue < this.minNote.realValue) this.minNote = note;
					if (!this.maxNote || note.realValue > this.maxNote.realValue) this.maxNote = note;
					if (!this.minStringNote || note.string < this.minStringNote.string) this.minStringNote = note;
					if (!this.maxStringNote || note.string > this.maxStringNote.string) this.maxStringNote = note;
					if (note.hasEffectSlur) isEffectSlurBeat = true;
				}
			}
			if (isEffectSlurBeat) if (this.effectSlurOrigin) {
				this.effectSlurOrigin.effectSlurDestination = this.nextBeat;
				if (this.effectSlurOrigin.effectSlurDestination) this.effectSlurOrigin.effectSlurDestination.effectSlurOrigin = this.effectSlurOrigin;
				this.effectSlurOrigin = null;
			} else {
				this.isEffectSlurOrigin = true;
				this.effectSlurDestination = this.nextBeat;
				if (this.effectSlurDestination) this.effectSlurDestination.effectSlurOrigin = this;
			}
			if (this.notes.length > 0 && visibleNotes === 0) this.isEmpty = true;
			if (!this.isRest && (!this.isLetRing || !this.isPalmMute)) {
				let currentBeat = this.previousBeat;
				while (currentBeat && currentBeat.isRest) {
					if (!this.isLetRing) currentBeat.isLetRing = false;
					if (!this.isPalmMute) currentBeat.isPalmMute = false;
					currentBeat = currentBeat.previousBeat;
				}
			} else if (this.isRest && this.previousBeat && settings && settings.notation.notationMode === NotationMode.GuitarPro) {
				if (this.previousBeat.isLetRing) this.isLetRing = true;
				if (this.previousBeat.isPalmMute) this.isPalmMute = true;
			}
			const points = this.whammyBarPoints;
			const hasWhammy = points !== null && points.length > 0;
			if (hasWhammy) {
				const isContinuedWhammy = !!this.previousBeat && this.previousBeat.hasWhammyBar;
				this.isContinuedWhammy = isContinuedWhammy;
			} else this.whammyBarType = WhammyType.None;
			if (hasWhammy && this.whammyBarType === WhammyType.Custom) {
				if (displayMode === NotationMode.SongBook) this.whammyStyle = isGradual ? BendStyle.Gradual : BendStyle.Fast;
				if (points.length === 4) {
					const origin = points[0];
					const middle1 = points[1];
					const middle2 = points[2];
					const destination = points[3];
					if (middle1.value === middle2.value) {
						if (origin.value < middle1.value && middle1.value < destination.value || origin.value > middle1.value && middle1.value > destination.value) {
							if (origin.value !== 0 && !this.isContinuedWhammy) this.whammyBarType = WhammyType.PrediveDive;
							else this.whammyBarType = WhammyType.Dive;
							points.splice(2, 1);
							points.splice(1, 1);
						} else if (origin.value > middle1.value && middle1.value < destination.value || origin.value < middle1.value && middle1.value > destination.value) {
							this.whammyBarType = WhammyType.Dip;
							if (middle1.offset === middle2.offset || displayMode === NotationMode.SongBook) points.splice(2, 1);
						} else if (origin.value === middle1.value && middle1.value === destination.value) {
							if (origin.value !== 0 && !this.isContinuedWhammy) this.whammyBarType = WhammyType.Predive;
							else this.whammyBarType = WhammyType.Hold;
							points.splice(2, 1);
							points.splice(1, 1);
						}
					}
				} else if (points.length === 3) {
					const origin = points[0];
					const middle = points[1];
					const destination = points[2];
					if (origin.value < middle.value && middle.value < destination.value || origin.value > middle.value && middle.value > destination.value) {
						if (origin.value !== 0 && !this.isContinuedWhammy) this.whammyBarType = WhammyType.PrediveDive;
						else this.whammyBarType = WhammyType.Dive;
						points.splice(1, 1);
					} else if (origin.value > middle.value && middle.value < destination.value || origin.value < middle.value && middle.value > destination.value) this.whammyBarType = WhammyType.Dip;
					else if (origin.value === middle.value && middle.value === destination.value) {
						if (origin.value !== 0 && !this.isContinuedWhammy) this.whammyBarType = WhammyType.Predive;
						else this.whammyBarType = WhammyType.Hold;
						points.splice(1, 1);
					}
				} else if (points.length === 2) {
					const origin = points[0];
					const destination = points[1];
					if (origin.value < destination.value || origin.value > destination.value) if (origin.value !== 0 && !this.isContinuedWhammy) this.whammyBarType = WhammyType.PrediveDive;
					else this.whammyBarType = WhammyType.Dive;
					else if (origin.value === destination.value) if (origin.value !== 0 && !this.isContinuedWhammy) this.whammyBarType = WhammyType.Predive;
					else this.whammyBarType = WhammyType.Hold;
				}
			}
			this.updateDurations();
			if (needCopyBeatForBend) {
				const cloneBeat = BeatCloner.clone(this);
				cloneBeat.id = Beat._globalBeatId++;
				cloneBeat.pickStroke = PickStroke.None;
				for (let i = 0, j = cloneBeat.notes.length; i < j; i++) {
					const cloneNote = cloneBeat.notes[i];
					const note = this.notes[i];
					cloneNote.bendType = BendType.None;
					cloneNote.maxBendPoint = null;
					cloneNote.bendPoints = null;
					cloneNote.bendStyle = BendStyle.Default;
					cloneNote.id = Note.globalNoteId++;
					if (note.isTieOrigin) {
						cloneNote.tieDestination = note.tieDestination;
						note.tieDestination.tieOrigin = cloneNote;
					}
					if (note.isTieDestination) {
						cloneNote.tieOrigin = note.tieOrigin ? note.tieOrigin : null;
						note.tieOrigin.tieDestination = cloneNote;
					}
					if (note.hasBend && note.isTieOrigin) {
						const tieDestination = Note.findTieOrigin(note);
						if (tieDestination && tieDestination.hasBend) {
							cloneNote.bendType = BendType.Hold;
							const lastPoint = note.bendPoints[note.bendPoints.length - 1];
							cloneNote.addBendPoint(new BendPoint(0, lastPoint.value));
							cloneNote.addBendPoint(new BendPoint(BendPoint.MaxPosition, lastPoint.value));
						}
					}
					cloneNote.isTieDestination = true;
				}
				this.graceType = GraceType.BendGrace;
				this.graceGroup = new GraceGroup();
				this.graceGroup.addBeat(this);
				this.graceGroup.isComplete = true;
				this.graceGroup.finish();
				this.updateDurations();
				this.voice.insertBeat(this, cloneBeat);
				cloneBeat.graceGroup = new GraceGroup();
				cloneBeat.graceGroup.addBeat(this);
				cloneBeat.graceGroup.isComplete = true;
				cloneBeat.graceGroup.finish();
			}
		}
		/**
		* Checks whether the current beat is timewise before the given beat.
		* @param beat
		* @returns
		*/
		isBefore(beat) {
			return this.voice.bar.index < beat.voice.bar.index || beat.voice.bar.index === this.voice.bar.index && this.index < beat.index;
		}
		/**
		* Checks whether the current beat is timewise after the given beat.
		* @param beat
		* @returns
		*/
		isAfter(beat) {
			return this.voice.bar.index > beat.voice.bar.index || beat.voice.bar.index === this.voice.bar.index && this.index > beat.index;
		}
		hasNoteOnString(noteString) {
			return this.noteStringLookup.has(noteString);
		}
		getNoteWithRealValue(noteRealValue) {
			if (this.noteValueLookup.has(noteRealValue)) return this.noteValueLookup.get(noteRealValue);
			return null;
		}
		chain(sharedDataBag = null) {
			for (const n of this.notes) {
				this.noteValueLookup.set(n.realValue, n);
				n.chain(sharedDataBag);
			}
		}
	};
	//#endregion
	//#region src/generated/model/BendPointCloner.ts
	/**
	* @internal
	*/
	var BendPointCloner = class {
		static clone(original) {
			const clone = new BendPoint();
			clone.offset = original.offset;
			clone.value = original.value;
			return clone;
		}
	};
	//#endregion
	//#region src/generated/model/NoteCloner.ts
	/**
	* @internal
	*/
	var NoteCloner = class {
		static clone(original) {
			const clone = new Note();
			clone.index = original.index;
			clone.accentuated = original.accentuated;
			clone.bendType = original.bendType;
			clone.bendStyle = original.bendStyle;
			clone.isContinuedBend = original.isContinuedBend;
			if (original.bendPoints) {
				clone.bendPoints = [];
				for (const i of original.bendPoints) clone.addBendPoint(BendPointCloner.clone(i));
			}
			clone.fret = original.fret;
			clone.string = original.string;
			clone.showStringNumber = original.showStringNumber;
			clone.octave = original.octave;
			clone.tone = original.tone;
			clone.percussionArticulation = original.percussionArticulation;
			clone.isVisible = original.isVisible;
			clone.isLeftHandTapped = original.isLeftHandTapped;
			clone.isHammerPullOrigin = original.isHammerPullOrigin;
			clone.isSlurDestination = original.isSlurDestination;
			clone.harmonicType = original.harmonicType;
			clone.harmonicValue = original.harmonicValue;
			clone.isGhost = original.isGhost;
			clone.isLetRing = original.isLetRing;
			clone.isPalmMute = original.isPalmMute;
			clone.isDead = original.isDead;
			clone.isStaccato = original.isStaccato;
			clone.slideInType = original.slideInType;
			clone.slideOutType = original.slideOutType;
			clone.vibrato = original.vibrato;
			clone.isTieDestination = original.isTieDestination;
			clone.leftHandFinger = original.leftHandFinger;
			clone.rightHandFinger = original.rightHandFinger;
			clone.trillValue = original.trillValue;
			clone.trillSpeed = original.trillSpeed;
			clone.durationPercent = original.durationPercent;
			clone.accidentalMode = original.accidentalMode;
			clone.dynamics = original.dynamics;
			clone.ornament = original.ornament;
			return clone;
		}
	};
	//#endregion
	//#region src/generated/model/SyncPointDataCloner.ts
	/**
	* @internal
	*/
	var SyncPointDataCloner = class {
		static clone(original) {
			const clone = new SyncPointData();
			clone.barOccurence = original.barOccurence;
			clone.millisecondOffset = original.millisecondOffset;
			return clone;
		}
	};
	//#endregion
	//#region src/generated/model/AutomationCloner.ts
	/**
	* @internal
	*/
	var AutomationCloner = class {
		static clone(original) {
			const clone = new Automation();
			clone.isLinear = original.isLinear;
			clone.type = original.type;
			clone.value = original.value;
			clone.syncPointValue = original.syncPointValue ? SyncPointDataCloner.clone(original.syncPointValue) : void 0;
			clone.ratioPosition = original.ratioPosition;
			clone.text = original.text;
			clone.isVisible = original.isVisible;
			return clone;
		}
	};
	//#endregion
	//#region src/generated/model/TremoloPickingEffectCloner.ts
	/**
	* @internal
	*/
	var TremoloPickingEffectCloner = class {
		static clone(original) {
			const clone = new TremoloPickingEffect();
			clone.marks = original.marks;
			clone.style = original.style;
			return clone;
		}
	};
	//#endregion
	//#region src/generated/model/BeatCloner.ts
	/**
	* @internal
	*/
	var BeatCloner = class {
		static clone(original) {
			const clone = new Beat();
			clone.index = original.index;
			clone.notes = [];
			for (const i of original.notes) clone.addNote(NoteCloner.clone(i));
			clone.isEmpty = original.isEmpty;
			clone.whammyStyle = original.whammyStyle;
			clone.ottava = original.ottava;
			clone.isLegatoOrigin = original.isLegatoOrigin;
			clone.duration = original.duration;
			clone.isLetRing = original.isLetRing;
			clone.isPalmMute = original.isPalmMute;
			clone.automations = [];
			for (const i of original.automations) clone.automations.push(AutomationCloner.clone(i));
			clone.dots = original.dots;
			clone.fade = original.fade;
			clone.lyrics = original.lyrics ? original.lyrics.slice() : null;
			clone.pop = original.pop;
			clone.slap = original.slap;
			clone.tap = original.tap;
			clone.text = original.text;
			clone.slashed = original.slashed;
			clone.deadSlapped = original.deadSlapped;
			clone.brushType = original.brushType;
			clone.brushDuration = original.brushDuration;
			clone.tupletDenominator = original.tupletDenominator;
			clone.tupletNumerator = original.tupletNumerator;
			clone.isContinuedWhammy = original.isContinuedWhammy;
			clone.whammyBarType = original.whammyBarType;
			if (original.whammyBarPoints) {
				clone.whammyBarPoints = [];
				for (const i of original.whammyBarPoints) clone.addWhammyBarPoint(BendPointCloner.clone(i));
			}
			clone.vibrato = original.vibrato;
			clone.chordId = original.chordId;
			clone.graceType = original.graceType;
			clone.pickStroke = original.pickStroke;
			clone.tremoloPicking = original.tremoloPicking ? TremoloPickingEffectCloner.clone(original.tremoloPicking) : void 0;
			clone.crescendo = original.crescendo;
			clone.displayStart = original.displayStart;
			clone.playbackStart = original.playbackStart;
			clone.displayDuration = original.displayDuration;
			clone.playbackDuration = original.playbackDuration;
			clone.overrideDisplayDuration = original.overrideDisplayDuration;
			clone.golpe = original.golpe;
			clone.dynamics = original.dynamics;
			clone.invertBeamDirection = original.invertBeamDirection;
			clone.preferredBeamDirection = original.preferredBeamDirection;
			clone.isEffectSlurOrigin = original.isEffectSlurOrigin;
			clone.beamingMode = original.beamingMode;
			clone.wahPedal = original.wahPedal;
			clone.barreFret = original.barreFret;
			clone.barreShape = original.barreShape;
			clone.rasgueado = original.rasgueado;
			clone.showTimer = original.showTimer;
			clone.timer = original.timer;
			return clone;
		}
	};
	//#endregion
	//#region src/importer/alphaTex/AlphaTex1EnumMappings.ts
	/**
	* @internal
	* @partial
	*/
	var AlphaTex1EnumMappings = class AlphaTex1EnumMappings {
		static _reverse(map) {
			const reversed = /* @__PURE__ */ new Map();
			for (const [k, v] of map) if (!reversed.has(v)) reversed.set(v, k);
			return reversed;
		}
		static whammyType = new Map([
			["custom", 1],
			["dive", 2],
			["dip", 3],
			["hold", 4],
			["predive", 5],
			["predivedive", 6]
		]);
		static whammyTypeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.whammyType);
		static bendStyle = new Map([
			["default", 0],
			["gradual", 1],
			["fast", 2]
		]);
		static bendStyleReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.bendStyle);
		static graceType = new Map([
			["onbeat", 1],
			["beforebeat", 2],
			["bendgrace", 3],
			["ob", 1],
			["bb", 2],
			["b", 3]
		]);
		static graceTypeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.graceType);
		static fermataType = new Map([
			["short", 0],
			["medium", 1],
			["long", 2]
		]);
		static fermataTypeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.fermataType);
		static alphaTexAccidentalMode = new Map([["auto", 0], ["explicit", 1]]);
		static alphaTexAccidentalModeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.alphaTexAccidentalMode);
		static alphaTexVoiceMode = new Map([["staffwise", 0], ["barwise", 1]]);
		static alphaTexVoiceModeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.alphaTexVoiceMode);
		static noteAccidentalMode = new Map([
			["default", 0],
			["forcenone", 1],
			["forcenatural", 2],
			["forcesharp", 3],
			["forcedoublesharp", 4],
			["forceflat", 5],
			["forcedoubleflat", 6],
			["d", 0],
			["-", 1],
			["n", 2],
			["#", 3],
			["##", 4],
			["x", 4],
			["b", 5],
			["bb", 6]
		]);
		static noteAccidentalModeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.noteAccidentalMode);
		static barreShape = new Map([["full", 1], ["half", 2]]);
		static barreShapeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.barreShape);
		static ottavia = new Map([
			["15ma", 0],
			["8va", 1],
			["regular", 2],
			["8vb", 3],
			["15mb", 4],
			["15ma", 0],
			["8va", 1],
			["8vb", 3],
			["15mb", 4]
		]);
		static ottaviaReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.ottavia);
		static rasgueado = new Map([
			["ii", 1],
			["mi", 2],
			["miitriplet", 3],
			["miianapaest", 4],
			["pmptriplet", 5],
			["pmpanapaest", 6],
			["peitriplet", 7],
			["peianapaest", 8],
			["paitriplet", 9],
			["paianapaest", 10],
			["amitriplet", 11],
			["amianapaest", 12],
			["ppp", 13],
			["amii", 14],
			["amip", 15],
			["eami", 16],
			["eamii", 17],
			["peami", 18]
		]);
		static rasgueadoReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.rasgueado);
		static dynamicValue = new Map([
			["ppp", 0],
			["pp", 1],
			["p", 2],
			["mp", 3],
			["mf", 4],
			["f", 5],
			["ff", 6],
			["fff", 7],
			["pppp", 8],
			["ppppp", 9],
			["pppppp", 10],
			["ffff", 11],
			["fffff", 12],
			["ffffff", 13],
			["sf", 14],
			["sfp", 15],
			["sfpp", 16],
			["fp", 17],
			["rf", 18],
			["rfz", 19],
			["sfz", 20],
			["sffz", 21],
			["fz", 22],
			["n", 23],
			["pf", 24],
			["sfzp", 25]
		]);
		static dynamicValueReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.dynamicValue);
		static bracketExtendMode = new Map([
			["nobrackets", 0],
			["groupstaves", 1],
			["groupsimilarinstruments", 2]
		]);
		static bracketExtendModeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.bracketExtendMode);
		static trackNamePolicy = new Map([
			["hidden", 0],
			["firstsystem", 1],
			["allsystems", 2]
		]);
		static trackNamePolicyReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.trackNamePolicy);
		static trackNameOrientation = new Map([["horizontal", 0], ["vertical", 1]]);
		static trackNameOrientationReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.trackNameOrientation);
		static trackNameMode = new Map([["fullname", 0], ["shortname", 1]]);
		static trackNameModeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.trackNameMode);
		static textAlign = new Map([
			["left", 0],
			["center", 1],
			["right", 2]
		]);
		static textAlignReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.textAlign);
		static bendType = new Map([
			["custom", 1],
			["bend", 2],
			["release", 3],
			["bendrelease", 4],
			["hold", 5],
			["prebend", 6],
			["prebendbend", 7],
			["prebendrelease", 8]
		]);
		static bendTypeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.bendType);
		static keySignature = new Map([
			["cb", -7],
			["gb", -6],
			["db", -5],
			["ab", -4],
			["eb", -3],
			["bb", -2],
			["f", -1],
			["c", 0],
			["g", 1],
			["d", 2],
			["a", 3],
			["e", 4],
			["b", 5],
			["f#", 6],
			["c#", 7],
			["cbmajor", -7],
			["abminor", -7],
			["gbmajor", -6],
			["ebminor", -6],
			["dbmajor", -5],
			["bbminor", -5],
			["abmajor", -4],
			["fminor", -4],
			["ebmajor", -3],
			["cminor", -3],
			["bbmajor", -2],
			["gminor", -2],
			["fmajor", -1],
			["dminor", -1],
			["cmajor", 0],
			["aminor", 0],
			["gmajor", 1],
			["eminor", 1],
			["dmajor", 2],
			["bminor", 2],
			["amajor", 3],
			["f#minor", 3],
			["emajor", 4],
			["c#minor", 4],
			["bmajor", 5],
			["g#minor", 5],
			["f#major", 6],
			["d#minor", 6],
			["f#", 6],
			["c#major", 7],
			["a#minor", 7],
			["c#", 7]
		]);
		static keySignatureReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.keySignature);
		static keySignatureType = new Map([
			["major", 0],
			["minor", 1],
			["cb", 0],
			["cbmajor", 0],
			["gb", 0],
			["gbmajor", 0],
			["db", 0],
			["dbmajor", 0],
			["ab", 0],
			["abmajor", 0],
			["eb", 0],
			["ebmajor", 0],
			["bb", 0],
			["bbmajor", 0],
			["f", 0],
			["fmajor", 0],
			["c", 0],
			["cmajor", 0],
			["g", 0],
			["gmajor", 0],
			["d", 0],
			["dmajor", 0],
			["a", 0],
			["amajor", 0],
			["e", 0],
			["emajor", 0],
			["b", 0],
			["bmajor", 0],
			["f#", 0],
			["f#major", 0],
			["c#", 0],
			["c#major", 0],
			["abminor", 1],
			["ebminor", 1],
			["bbminor", 1],
			["fminor", 1],
			["cminor", 1],
			["gminor", 1],
			["dminor", 1],
			["aminor", 1],
			["eminor", 1],
			["bminor", 1],
			["f#minor", 1],
			["c#minor", 1],
			["g#minor", 1],
			["d#minor", 1],
			["a#minor", 1]
		]);
		static keySignatureTypeReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.keySignatureType);
		static clef = new Map([
			["neutral", 0],
			["c3", 1],
			["c4", 2],
			["f4", 3],
			["g2", 4],
			["n", 0],
			["alto", 1],
			["tenor", 2],
			["bass", 3],
			["treble", 4]
		]);
		static clefReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.clef);
		static tripletFeel = new Map([
			["none", 0],
			["triplet16th", 1],
			["triplet8th", 2],
			["dotted16th", 3],
			["dotted8th", 4],
			["scottish16th", 5],
			["scottish8th", 6],
			["none", 0],
			["no", 0],
			["notripletfeel", 0],
			["t16", 1],
			["triplet-16th", 1],
			["t8", 2],
			["triplet-8th", 2],
			["d16", 3],
			["dotted-16th", 3],
			["d8", 4],
			["dotted-8th", 4],
			["s16", 5],
			["scottish-16th", 5],
			["s8", 6],
			["scottish-8th", 6]
		]);
		static tripletFeelReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.tripletFeel);
		static barLineStyle = new Map([
			["automatic", 0],
			["dashed", 1],
			["dotted", 2],
			["heavy", 3],
			["heavyheavy", 4],
			["heavylight", 5],
			["lightheavy", 6],
			["lightlight", 7],
			["none", 8],
			["regular", 9],
			["short", 10],
			["tick", 11]
		]);
		static barLineStyleReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.barLineStyle);
		static simileMark = new Map([
			["none", 0],
			["simple", 1],
			["firstofdouble", 2],
			["secondofdouble", 3]
		]);
		static simileMarkReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.simileMark);
		static direction = new Map([
			["fine", 0],
			["segno", 1],
			["segnosegno", 2],
			["coda", 3],
			["doublecoda", 4],
			["dacapo", 5],
			["dacapoalcoda", 6],
			["dacapoaldoublecoda", 7],
			["dacapoalfine", 8],
			["dalsegno", 9],
			["dalsegnoalcoda", 10],
			["dalsegnoaldoublecoda", 11],
			["dalsegnoalfine", 12],
			["dalsegnosegno", 13],
			["dalsegnosegnoalcoda", 14],
			["dalsegnosegnoaldoublecoda", 15],
			["dalsegnosegnoalfine", 16],
			["dacoda", 17],
			["dadoublecoda", 18]
		]);
		static directionReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.direction);
		static tremoloPickingStyle = new Map([["default", 0], ["buzzroll", 1]]);
		static tremoloPickingStyleReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.tremoloPickingStyle);
		static barNumberDisplay = new Map([
			["allbars", 0],
			["firstofsystem", 1],
			["hide", 2]
		]);
		static barNumberDisplayReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.barNumberDisplay);
		static keySignaturesMinorReversed = new Map([
			[-7, "abminor"],
			[-6, "ebminor"],
			[-5, "bbminor"],
			[-4, "fminor"],
			[-3, "cminor"],
			[-2, "gminor"],
			[-1, "dminor"],
			[0, "aminor"],
			[1, "eminor"],
			[2, "bminor"],
			[3, "f#minor"],
			[4, "c#minor"],
			[5, "g#minor"],
			[6, "d#minor"],
			[7, "a#minor"]
		]);
		static keySignaturesMajorReversed = new Map([
			[-7, "cb"],
			[-6, "gb"],
			[-5, "db"],
			[-4, "ab"],
			[-3, "eb"],
			[-2, "bb"],
			[-1, "f"],
			[0, "c"],
			[1, "g"],
			[2, "d"],
			[3, "a"],
			[4, "e"],
			[5, "b"],
			[6, "f#"],
			[7, "c#"]
		]);
	};
	//#endregion
	//#region src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts
	/**
	* @internal
	*/
	var AlphaTex1LanguageDefinitions = class AlphaTex1LanguageDefinitions {
		static _param(simple) {
			if (!simple) return null;
			return {
				expectedTypes: new Set(simple[0]),
				parseMode: simple[1],
				allowedValues: simple.length > 2 && simple[2] && simple[2].length > 0 ? new Set(simple[2]) : void 0,
				reservedIdentifiers: simple.length > 3 && simple[3] && simple[3].length > 0 ? new Set(simple[3]) : void 0
			};
		}
		static _simple(signature) {
			if (signature == null) return null;
			return signature.map((s) => ({
				isStrict: s.length > 0 && s[0] === null,
				parameters: s.map(AlphaTex1LanguageDefinitions._param).filter((p) => p !== null)
			}));
		}
		static _metaProps(props) {
			return new Map(props.map((p) => [p[0], p[1] === null ? null : new Map(p[1].map((p) => [p[0], AlphaTex1LanguageDefinitions._simple(p[1])]))]));
		}
		static _props(props) {
			return new Map(props.map((p) => [p[0], AlphaTex1LanguageDefinitions._simple(p[1])]));
		}
		static _signatures(signatures) {
			return new Map(signatures.map((s) => [s[0], AlphaTex1LanguageDefinitions._simple(s[1])]));
		}
		static scoreMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([
			["title", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["subtitle", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["artist", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["album", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["words", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["music", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["wordsandmusic", [[[[17], 0], [
				[10, 17],
				1,
				[
					"left",
					"center",
					"right"
				]
			]]]],
			["copyright", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["copyright2", [[[[17], 0], [
				[10, 17],
				1,
				[
					"left",
					"center",
					"right"
				]
			]]]],
			["instructions", [[[[17, 10], 0]]]],
			["notices", [[[[17, 10], 0]]]],
			["tab", [[
				[[17, 10], 0],
				[[17], 1],
				[
					[10, 17],
					1,
					[
						"left",
						"center",
						"right"
					]
				]
			]]],
			["systemslayout", [[[[16], 5]]]],
			["defaultsystemslayout", [[[[16], 0]]]],
			["showdynamics", null],
			["hidedynamics", null],
			["usesystemsignseparator", null],
			["multibarrest", null],
			["bracketextendmode", [[[
				[10, 17],
				0,
				[
					"nobrackets",
					"groupstaves",
					"groupsimilarinstruments"
				]
			]]]],
			["singletracktracknamepolicy", [[[
				[10, 17],
				0,
				[
					"hidden",
					"firstsystem",
					"allsystems"
				]
			]]]],
			["multitracktracknamepolicy", [[[
				[10, 17],
				0,
				[
					"hidden",
					"firstsystem",
					"allsystems"
				]
			]]]],
			["firstsystemtracknamemode", [[[
				[10, 17],
				0,
				["fullname", "shortname"]
			]]]],
			["othersystemstracknamemode", [[[
				[10, 17],
				0,
				["fullname", "shortname"]
			]]]],
			["firstsystemtracknameorientation", [[[
				[10, 17],
				0,
				["horizontal", "vertical"]
			]]]],
			["othersystemstracknameorientation", [[[
				[10, 17],
				0,
				["horizontal", "vertical"]
			]]]],
			["extendbarlines", null],
			["chorddiagramsinscore", [[[
				[10],
				1,
				["true", "false"]
			]]]],
			["hideemptystaves", null],
			["hideemptystavesinfirstsystem", null],
			["showsinglestaffbrackets", null],
			["defaultbarnumberdisplay", [[[
				[10, 17],
				0,
				[
					"allbars",
					"firstofsystem",
					"hide"
				]
			]]]]
		]);
		static staffMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([
			["tuning", [[[
				[10, 17],
				0,
				[
					"piano",
					"none",
					"voice"
				]
			]], [[[10, 17], 5]]]],
			["chord", [[[[17, 10], 0], [[
				10,
				17,
				16
			], 5]]]],
			["capo", [[[[16], 0]]]],
			["lyrics", [[[[17], 0]], [[[16], 0], [[17], 0]]]],
			["articulation", [[[
				[10],
				0,
				["defaults"]
			]], [[[17, 10], 0], [[16], 0]]]],
			["displaytranspose", [[[[16], 0]]]],
			["transpose", [[[[16], 0]]]],
			["instrument", [
				[[[16], 0]],
				[[[17, 10], 0]],
				[[
					[10],
					0,
					["percussion"]
				]]
			]]
		]);
		static structuralMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([
			["track", [[[[17], 1], [[17], 1]]]],
			["staff", null],
			["voice", null]
		]);
		static barMetaDataSignatures = AlphaTex1LanguageDefinitions._signatures([
			["ts", [[[
				[10, 17],
				0,
				["common"]
			]], [[[16], 0], [[16], 0]]]],
			["ro", null],
			["rc", [[[[16], 0]]]],
			["ae", [[[[16, 13], 4]]]],
			["ks", [[[
				[10, 17],
				0,
				[
					"cb",
					"gb",
					"db",
					"ab",
					"eb",
					"bb",
					"f",
					"c",
					"g",
					"d",
					"a",
					"e",
					"b",
					"f#",
					"c#",
					"cbmajor",
					"abminor",
					"gbmajor",
					"ebminor",
					"dbmajor",
					"bbminor",
					"abmajor",
					"fminor",
					"ebmajor",
					"cminor",
					"bbmajor",
					"gminor",
					"fmajor",
					"dminor",
					"cmajor",
					"aminor",
					"gmajor",
					"eminor",
					"dmajor",
					"bminor",
					"amajor",
					"f#minor",
					"emajor",
					"c#minor",
					"bmajor",
					"g#minor",
					"f#major",
					"d#minor",
					"f#",
					"c#major",
					"a#minor",
					"c#"
				]
			]]]],
			["clef", [[[
				[
					10,
					16,
					17
				],
				0,
				[
					"neutral",
					"c3",
					"c4",
					"f4",
					"g2",
					"n",
					"alto",
					"tenor",
					"bass",
					"treble"
				]
			]]]],
			["ottava", [[[
				[10, 17],
				0,
				[
					"15ma",
					"8va",
					"regular",
					"8vb",
					"15mb",
					"15ma",
					"8va",
					"8vb",
					"15mb"
				]
			]]]],
			["tempo", [[[[16], 2], [[17], 1]], [
				null,
				[[16], 2],
				[[17], 0],
				[[16], 1],
				[
					[10],
					1,
					["hide"]
				]
			]]],
			["tf", [[[
				[
					10,
					16,
					17
				],
				0,
				[
					"none",
					"triplet16th",
					"triplet8th",
					"dotted16th",
					"dotted8th",
					"scottish16th",
					"scottish8th",
					"none",
					"no",
					"notripletfeel",
					"t16",
					"triplet-16th",
					"t8",
					"triplet-8th",
					"d16",
					"dotted-16th",
					"d8",
					"dotted-8th",
					"s16",
					"scottish-16th",
					"s8",
					"scottish-8th"
				]
			]]]],
			["ac", null],
			["section", [[[[17, 10], 0]], [[[17, 10], 0], [
				[17, 10],
				0,
				null,
				[
					"x",
					"-",
					"r"
				]
			]]]],
			["jump", [[[
				[10, 17],
				0,
				[
					"fine",
					"segno",
					"segnosegno",
					"coda",
					"doublecoda",
					"dacapo",
					"dacapoalcoda",
					"dacapoaldoublecoda",
					"dacapoalfine",
					"dalsegno",
					"dalsegnoalcoda",
					"dalsegnoaldoublecoda",
					"dalsegnoalfine",
					"dalsegnosegno",
					"dalsegnosegnoalcoda",
					"dalsegnosegnoaldoublecoda",
					"dalsegnosegnoalfine",
					"dacoda",
					"dadoublecoda"
				]
			]]]],
			["ft", null],
			["simile", [[[
				[10, 17],
				0,
				[
					"none",
					"simple",
					"firstofdouble",
					"secondofdouble"
				]
			]]]],
			["barlineleft", [[[
				[10, 17],
				0,
				[
					"automatic",
					"dashed",
					"dotted",
					"heavy",
					"heavyheavy",
					"heavylight",
					"lightheavy",
					"lightlight",
					"none",
					"regular",
					"short",
					"tick"
				]
			]]]],
			["barlineright", [[[
				[10, 17],
				0,
				[
					"automatic",
					"dashed",
					"dotted",
					"heavy",
					"heavyheavy",
					"heavylight",
					"lightheavy",
					"lightlight",
					"none",
					"regular",
					"short",
					"tick"
				]
			]]]],
			["scale", [[[[16], 2]]]],
			["width", [[[[16], 2]]]],
			["sync", [[
				[[16], 0],
				[[16], 0],
				[[16], 0],
				[[16], 3]
			]]],
			["accidentals", [[[
				[10, 17],
				0,
				["auto", "explicit"]
			]]]],
			["spd", [[[[16], 2]]]],
			["sph", [[[[16], 2]]]],
			["spu", [[[[16], 2]]]],
			["db", null],
			["voicemode", [[[
				[10, 17],
				0,
				["staffwise", "barwise"]
			]]]],
			["barnumberdisplay", [[[
				[10, 17],
				0,
				[
					"allbars",
					"firstofsystem",
					"hide"
				]
			]]]],
			["beaming", [[[[16], 0], [[16], 5]]]]
		]);
		static metaDataProperties = AlphaTex1LanguageDefinitions._metaProps([
			["track", [
				["color", [[[[17], 0]]]],
				["systemslayout", [[[[16], 5]]]],
				["defaultsystemslayout", [[[[16], 0]]]],
				["solo", null],
				["mute", null],
				["volume", [[[[16], 0]]]],
				["balance", [[[[16], 0]]]],
				["instrument", [
					[[[16], 0]],
					[[[17, 10], 0]],
					[[
						[10],
						0,
						["percussion"]
					]]
				]],
				["bank", [[[[16], 0]]]],
				["multibarrest", null]
			]],
			["staff", [
				["score", [[[[16], 1]]]],
				["tabs", null],
				["slash", null],
				["numbered", null]
			]],
			["voice", null],
			["title", null],
			["subtitle", null],
			["artist", null],
			["album", null],
			["words", null],
			["music", null],
			["wordsandmusic", null],
			["copyright", null],
			["copyright2", null],
			["instructions", null],
			["notices", null],
			["tab", null],
			["systemslayout", null],
			["defaultsystemslayout", null],
			["showdynamics", null],
			["hidedynamics", null],
			["usesystemsignseparator", null],
			["multibarrest", null],
			["bracketextendmode", null],
			["singletracktracknamepolicy", null],
			["multitracktracknamepolicy", null],
			["firstsystemtracknamemode", null],
			["othersystemstracknamemode", null],
			["firstsystemtracknameorientation", null],
			["othersystemstracknameorientation", null],
			["extendbarlines", null],
			["chorddiagramsinscore", null],
			["hideemptystaves", null],
			["hideemptystavesinfirstsystem", null],
			["showsinglestaffbrackets", null],
			["defaultbarnumberdisplay", null],
			["tuning", [["hide", null], ["label", [[[[17], 0]]]]]],
			["chord", [
				["firstfret", [[[[16], 0]]]],
				["barre", [[[[16], 5]]]],
				["showdiagram", [
					[],
					[[
						[17],
						0,
						["true", "false"]
					]],
					[[
						[10],
						0,
						["true", "false"]
					]],
					[[
						[16],
						0,
						["1", "0"]
					]]
				]],
				["showfingering", [
					[],
					[[
						[17],
						0,
						["true", "false"]
					]],
					[[
						[10],
						0,
						["true", "false"]
					]],
					[[
						[16],
						0,
						["1", "0"]
					]]
				]],
				["showname", [
					[],
					[[
						[17],
						0,
						["true", "false"]
					]],
					[[
						[10],
						0,
						["true", "false"]
					]],
					[[
						[16],
						0,
						["1", "0"]
					]]
				]]
			]],
			["capo", null],
			["lyrics", null],
			["articulation", null],
			["displaytranspose", null],
			["transpose", null],
			["instrument", null],
			["ts", null],
			["ro", null],
			["rc", null],
			["ae", null],
			["ks", null],
			["clef", null],
			["ottava", null],
			["tempo", null],
			["tf", null],
			["ac", null],
			["section", null],
			["jump", null],
			["ft", null],
			["simile", null],
			["barlineleft", null],
			["barlineright", null],
			["scale", null],
			["width", null],
			["sync", null],
			["accidentals", null],
			["spd", null],
			["sph", null],
			["spu", null],
			["db", null],
			["voicemode", null],
			["barnumberdisplay", null],
			["beaming", null]
		]);
		static metaDataSignatures = [
			AlphaTex1LanguageDefinitions.scoreMetaDataSignatures,
			AlphaTex1LanguageDefinitions.staffMetaDataSignatures,
			AlphaTex1LanguageDefinitions.structuralMetaDataSignatures,
			AlphaTex1LanguageDefinitions.barMetaDataSignatures
		];
		static durationChangeProperties = AlphaTex1LanguageDefinitions._props([["tu", [[[
			[16],
			0,
			[
				"3",
				"5",
				"6",
				"7",
				"9",
				"10",
				"12"
			]
		]], [[[16], 0], [[16], 0]]]]]);
		static beatProperties = AlphaTex1LanguageDefinitions._props([
			["f", null],
			["fo", null],
			["vs", null],
			["v", null],
			["vw", null],
			["s", null],
			["p", null],
			["tt", null],
			["d", null],
			["dd", null],
			["su", null],
			["sd", null],
			["cre", null],
			["dec", null],
			["spd", null],
			["sph", null],
			["spu", null],
			["spe", null],
			["slashed", null],
			["ds", null],
			["glpf", null],
			["glpt", null],
			["waho", null],
			["wahc", null],
			["legatoorigin", null],
			["timer", null],
			["tu", [[[
				[16],
				0,
				[
					"3",
					"5",
					"6",
					"7",
					"9",
					"10",
					"12"
				]
			]], [[[16], 0], [[16], 0]]]],
			["txt", [[[[17, 10], 0]]]],
			["lyrics", [[[[17], 0]], [[[16], 0], [[17], 0]]]],
			["tb", [
				[[[16], 5]],
				[[
					[10, 17],
					0,
					[
						"custom",
						"dive",
						"dip",
						"hold",
						"predive",
						"predivedive"
					]
				], [[16], 5]],
				[[
					[10, 17],
					0,
					[
						"default",
						"gradual",
						"fast"
					]
				], [[16], 5]],
				[
					[
						[10, 17],
						0,
						[
							"custom",
							"dive",
							"dip",
							"hold",
							"predive",
							"predivedive"
						]
					],
					[
						[10, 17],
						0,
						[
							"default",
							"gradual",
							"fast"
						]
					],
					[[16], 5]
				]
			]],
			["tbe", [
				[[[16], 5]],
				[[
					[10, 17],
					0,
					[
						"custom",
						"dive",
						"dip",
						"hold",
						"predive",
						"predivedive"
					]
				], [[16], 5]],
				[[
					[10, 17],
					0,
					[
						"default",
						"gradual",
						"fast"
					]
				], [[16], 5]],
				[
					[
						[10, 17],
						0,
						[
							"custom",
							"dive",
							"dip",
							"hold",
							"predive",
							"predivedive"
						]
					],
					[
						[10, 17],
						0,
						[
							"default",
							"gradual",
							"fast"
						]
					],
					[[16], 5]
				]
			]],
			["bu", [[[[16], 1]]]],
			["bd", [[[[16], 1]]]],
			["au", [[[[16], 1]]]],
			["ad", [[[[16], 1]]]],
			["ch", [[[[17, 10], 0]]]],
			["gr", [[[
				[10, 17],
				1,
				[
					"onbeat",
					"beforebeat",
					"bendgrace",
					"ob",
					"bb",
					"b"
				]
			]]]],
			["dy", [[[
				[10, 17],
				0,
				[
					"ppp",
					"pp",
					"p",
					"mp",
					"mf",
					"f",
					"ff",
					"fff",
					"pppp",
					"ppppp",
					"pppppp",
					"ffff",
					"fffff",
					"ffffff",
					"sf",
					"sfp",
					"sfpp",
					"fp",
					"rf",
					"rfz",
					"sfz",
					"sffz",
					"fz",
					"n",
					"pf",
					"sfzp"
				]
			]]]],
			["tempo", [[[[16], 0], [
				[10],
				1,
				["hide"]
			]], [
				[[16], 0],
				[[17], 0],
				[
					[10],
					1,
					["hide"]
				]
			]]],
			["volume", [[[[16], 0]]]],
			["balance", [[[[16], 0]]]],
			["tp", [[[[16], 0], [
				[10, 17],
				1,
				["default", "buzzroll"]
			]]]],
			["barre", [[[[16], 0], [
				[10, 17],
				1,
				["full", "half"]
			]]]],
			["rasg", [[[
				[10, 17],
				0,
				[
					"ii",
					"mi",
					"miitriplet",
					"miianapaest",
					"pmptriplet",
					"pmpanapaest",
					"peitriplet",
					"peianapaest",
					"paitriplet",
					"paianapaest",
					"amitriplet",
					"amianapaest",
					"ppp",
					"amii",
					"amip",
					"eami",
					"eamii",
					"peami"
				]
			]]]],
			["ot", [[[
				[10, 17],
				0,
				[
					"15ma",
					"8va",
					"regular",
					"8vb",
					"15mb",
					"15ma",
					"8va",
					"8vb",
					"15mb"
				]
			]]]],
			["instrument", [
				[[[16], 0]],
				[[[17, 10], 0]],
				[[
					[10],
					0,
					["percussion"]
				]]
			]],
			["bank", [[[[16], 0]]]],
			["fermata", [[[
				[10, 17],
				0,
				[
					"short",
					"medium",
					"long"
				]
			], [[16], 3]]]],
			["beam", [[[
				[10, 17],
				0,
				[
					"invert",
					"up",
					"down",
					"auto",
					"split",
					"merge",
					"splitsecondary"
				]
			]]]]
		]);
		static noteProperties = AlphaTex1LanguageDefinitions._props([
			["nh", null],
			["ah", [[[[16], 1]]]],
			["th", [[[[16], 1]]]],
			["ph", [[[[16], 1]]]],
			["sh", [[[[16], 1]]]],
			["fh", [[[[16], 1]]]],
			["v", null],
			["vw", null],
			["sl", null],
			["ss", null],
			["sib", null],
			["sia", null],
			["sou", null],
			["sod", null],
			["psu", null],
			["psd", null],
			["h", null],
			["lht", null],
			["g", null],
			["ac", null],
			["hac", null],
			["ten", null],
			["tr", [[[[16], 0], [
				[16],
				1,
				[
					"16",
					"32",
					"64"
				]
			]]]],
			["pm", null],
			["st", null],
			["lr", null],
			["x", null],
			["t", null],
			["turn", null],
			["iturn", null],
			["umordent", null],
			["lmordent", null],
			["string", null],
			["hide", null],
			["b", [
				[[[16], 5]],
				[[
					[10, 17],
					0,
					[
						"custom",
						"bend",
						"release",
						"bendrelease",
						"hold",
						"prebend",
						"prebendbend",
						"prebendrelease"
					]
				], [[16], 5]],
				[[
					[10, 17],
					0,
					[
						"default",
						"gradual",
						"fast"
					]
				], [[16], 5]],
				[
					[
						[10, 17],
						0,
						[
							"custom",
							"bend",
							"release",
							"bendrelease",
							"hold",
							"prebend",
							"prebendbend",
							"prebendrelease"
						]
					],
					[
						[10, 17],
						0,
						[
							"default",
							"gradual",
							"fast"
						]
					],
					[[16], 5]
				]
			]],
			["be", [
				[[[16], 5]],
				[[
					[10, 17],
					0,
					[
						"custom",
						"bend",
						"release",
						"bendrelease",
						"hold",
						"prebend",
						"prebendbend",
						"prebendrelease"
					]
				], [[16], 5]],
				[[
					[10, 17],
					0,
					[
						"default",
						"gradual",
						"fast"
					]
				], [[16], 5]],
				[
					[
						[10, 17],
						0,
						[
							"custom",
							"bend",
							"release",
							"bendrelease",
							"hold",
							"prebend",
							"prebendbend",
							"prebendrelease"
						]
					],
					[
						[10, 17],
						0,
						[
							"default",
							"gradual",
							"fast"
						]
					],
					[[16], 5]
				]
			]],
			["lf", [[[
				[16],
				0,
				[
					"1",
					"2",
					"3",
					"4",
					"5"
				]
			]]]],
			["rf", [[[
				[16],
				0,
				[
					"1",
					"2",
					"3",
					"4",
					"5"
				]
			]]]],
			["acc", [[[
				[10, 17],
				0,
				[
					"default",
					"forcenone",
					"forcenatural",
					"forcesharp",
					"forcedoublesharp",
					"forceflat",
					"forcedoubleflat",
					"d",
					"-",
					"n",
					"#",
					"##",
					"x",
					"b",
					"bb"
				]
			]]]],
			["slur", [[[[17], 0]], [[[10], 0]]]],
			["-", null]
		]);
	};
	//#endregion
	//#region src/importer/alphaTex/AlphaTexAst.ts
	/**
	* All node types for the alphaTex syntax tree.
	* @public
	*/
	var AlphaTexNodeType = /* @__PURE__ */ function(AlphaTexNodeType) {
		AlphaTexNodeType[AlphaTexNodeType["Dot"] = 0] = "Dot";
		AlphaTexNodeType[AlphaTexNodeType["Backslash"] = 1] = "Backslash";
		AlphaTexNodeType[AlphaTexNodeType["DoubleBackslash"] = 2] = "DoubleBackslash";
		AlphaTexNodeType[AlphaTexNodeType["Pipe"] = 3] = "Pipe";
		AlphaTexNodeType[AlphaTexNodeType["LBrace"] = 4] = "LBrace";
		AlphaTexNodeType[AlphaTexNodeType["RBrace"] = 5] = "RBrace";
		AlphaTexNodeType[AlphaTexNodeType["LParen"] = 6] = "LParen";
		AlphaTexNodeType[AlphaTexNodeType["RParen"] = 7] = "RParen";
		AlphaTexNodeType[AlphaTexNodeType["Colon"] = 8] = "Colon";
		AlphaTexNodeType[AlphaTexNodeType["Asterisk"] = 9] = "Asterisk";
		AlphaTexNodeType[AlphaTexNodeType["Ident"] = 10] = "Ident";
		AlphaTexNodeType[AlphaTexNodeType["Tag"] = 11] = "Tag";
		AlphaTexNodeType[AlphaTexNodeType["Meta"] = 12] = "Meta";
		AlphaTexNodeType[AlphaTexNodeType["Arguments"] = 13] = "Arguments";
		AlphaTexNodeType[AlphaTexNodeType["Props"] = 14] = "Props";
		AlphaTexNodeType[AlphaTexNodeType["Prop"] = 15] = "Prop";
		AlphaTexNodeType[AlphaTexNodeType["Number"] = 16] = "Number";
		AlphaTexNodeType[AlphaTexNodeType["String"] = 17] = "String";
		AlphaTexNodeType[AlphaTexNodeType["Score"] = 18] = "Score";
		AlphaTexNodeType[AlphaTexNodeType["Bar"] = 19] = "Bar";
		AlphaTexNodeType[AlphaTexNodeType["Beat"] = 20] = "Beat";
		AlphaTexNodeType[AlphaTexNodeType["Duration"] = 21] = "Duration";
		AlphaTexNodeType[AlphaTexNodeType["NoteList"] = 22] = "NoteList";
		AlphaTexNodeType[AlphaTexNodeType["Note"] = 23] = "Note";
		return AlphaTexNodeType;
	}({});
	//#endregion
	//#region src/importer/alphaTex/AlphaTexShared.ts
	/**
	* The different severity levels for diagnostics parsing alphaTex.
	* @public
	*/
	var AlphaTexDiagnosticsSeverity = /* @__PURE__ */ function(AlphaTexDiagnosticsSeverity) {
		AlphaTexDiagnosticsSeverity[AlphaTexDiagnosticsSeverity["Hint"] = 0] = "Hint";
		AlphaTexDiagnosticsSeverity[AlphaTexDiagnosticsSeverity["Warning"] = 1] = "Warning";
		AlphaTexDiagnosticsSeverity[AlphaTexDiagnosticsSeverity["Error"] = 2] = "Error";
		return AlphaTexDiagnosticsSeverity;
	}({});
	/**
	* @public
	*/
	var AlphaTexDiagnosticCode = /* @__PURE__ */ function(AlphaTexDiagnosticCode) {
		/**
		* Unexpected character at comment start, expected '//' or '/*' but found '/%s'.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT001"] = 1] = "AT001";
		/**
		* Missing identifier after meta data start.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT002"] = 2] = "AT002";
		/**
		* Unexpected end of file. Need 4 hex characters on a \uXXXX escape sequence.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT003"] = 3] = "AT003";
		/**
		* Invalid unicode value. Need 4 hex characters on a \uXXXX escape sequence.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT004"] = 4] = "AT004";
		/**
		* Unsupported escape sequence. Expected '\n', '\r', '\t', or '\uXXXX' but found '\%s'.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT005"] = 5] = "AT005";
		/**
		* Unexpected end of file. String not closed.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT006"] = 6] = "AT006";
		/**
		* Missing beat multiplier value after '*'.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT200"] = 200] = "AT200";
		/**
		* Missing duration value after ':'.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT201"] = 201] = "AT201";
		/**
		* Unexpected '%s' token. Expected one of following: %s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT202"] = 202] = "AT202";
		/**
		* Unexpected end of file.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT203"] = 203] = "AT203";
		/**
		* Unrecognized metadata '%s'.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT204"] = 204] = "AT204";
		/**
		* Unrecognized property '%s'.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT205"] = 205] = "AT205";
		/**
		* Unexpected end of file. Group not closed.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT206"] = 206] = "AT206";
		/**
		* Missing string for fretted note.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT207"] = 207] = "AT207";
		/**
		* Note string is out of range. Available range: 1-%s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT208"] = 208] = "AT208";
		/**
		* Unexpected %s arguments '%s', Signature: %s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT209"] = 209] = "AT209";
		/**
		* Missing arguments. Expected following arguments: %s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT210"] = 210] = "AT210";
		/**
		* Value is out of valid range. Allowed range: %s, Actual Value: %s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT211"] = 211] = "AT211";
		/**
		* Unrecogized property '%s', expected one of %s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT212"] = 212] = "AT212";
		/**
		* Invalid format for color
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT213"] = 213] = "AT213";
		/**
		* The '%s' effect needs %s arguments per item. With %s points, %s arguments are needed, only %s arguments found.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT214"] = 214] = "AT214";
		/**
		* Cannot use pitched note value '%s' on %s staff, please specify notes using the 'fret.string' syntax.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT215"] = 215] = "AT215";
		/**
		* Cannot use pitched note value '%s' on percussion staff, please specify percussion articulations with numbers or names.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT216"] = 216] = "AT216";
		/**
		* Unrecognized note value '%s'.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT217"] = 217] = "AT217";
		/**
		* Wrong note kind '%s' for staff with note kind '%s'. Do not mix incompatible staves and notes.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT218"] = 218] = "AT218";
		/**
		* Error parsing arguments: no overload matched arguments %s. Signatures: %s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT219"] = 219] = "AT219";
		/**
		* Error parsing arguments: unexpected additional arguments. Signatures: %s
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT220"] = 220] = "AT220";
		/**
		* Expected no arguments, but found some.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT300"] = 300] = "AT300";
		/**
		* Metadata arguments should be wrapped into parenthesis.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT301"] = 301] = "AT301";
		/**
		* Metadata arguments should be placed before metadata properties.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT302"] = 302] = "AT302";
		/**
		* Property arguments should be wrapped into parenthesis.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT303"] = 303] = "AT303";
		/**
		* The beat multiplier should be specified after the beat effects.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT304"] = 304] = "AT304";
		/**
		* This value should be rather specified via the properties.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT305"] = 305] = "AT305";
		/**
		* This staff metadata tag should be specified as staff property.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT306"] = 306] = "AT306";
		/**
		* The dots separating score metadata, score contents and the sync points can be removed.
		*/
		AlphaTexDiagnosticCode[AlphaTexDiagnosticCode["AT400"] = 400] = "AT400";
		return AlphaTexDiagnosticCode;
	}({});
	/**
	* @public
	*/
	var AlphaTexDiagnosticBag = class {
		_hasErrors = false;
		items = [];
		get errors() {
			return this.items.filter((i) => i.severity === 2);
		}
		get hasErrors() {
			return this._hasErrors;
		}
		push(diagnostic) {
			this.items.push(diagnostic);
			if (diagnostic.severity === 2) this._hasErrors = true;
		}
		[Symbol.iterator]() {
			return this.items[Symbol.iterator]();
		}
	};
	/**
	* @public
	*/
	var AlphaTexAccidentalMode = /* @__PURE__ */ function(AlphaTexAccidentalMode) {
		AlphaTexAccidentalMode[AlphaTexAccidentalMode["Auto"] = 0] = "Auto";
		AlphaTexAccidentalMode[AlphaTexAccidentalMode["Explicit"] = 1] = "Explicit";
		return AlphaTexAccidentalMode;
	}({});
	/**
	* @public
	*/
	var AlphaTexVoiceMode = /* @__PURE__ */ function(AlphaTexVoiceMode) {
		AlphaTexVoiceMode[AlphaTexVoiceMode["StaffWise"] = 0] = "StaffWise";
		AlphaTexVoiceMode[AlphaTexVoiceMode["BarWise"] = 1] = "BarWise";
		return AlphaTexVoiceMode;
	}({});
	/**
	* Lists the note kinds we can detect
	* @public
	*/
	var AlphaTexStaffNoteKind = /* @__PURE__ */ function(AlphaTexStaffNoteKind) {
		AlphaTexStaffNoteKind[AlphaTexStaffNoteKind["Pitched"] = 0] = "Pitched";
		AlphaTexStaffNoteKind[AlphaTexStaffNoteKind["Fretted"] = 1] = "Fretted";
		AlphaTexStaffNoteKind[AlphaTexStaffNoteKind["Articulation"] = 2] = "Articulation";
		return AlphaTexStaffNoteKind;
	}({});
	/**
	* Defines how the arguments of the meta data tag is parsed.
	* @public
	*/
	var ArgumentListParseTypesMode = /* @__PURE__ */ function(ArgumentListParseTypesMode) {
		/**
		* Indicates that the parameter of the given types is required.
		* If the token matches, it is added to the value list.
		* If the token does not match, an error diagnostic is added and parsing is stopped.
		*/
		ArgumentListParseTypesMode[ArgumentListParseTypesMode["Required"] = 0] = "Required";
		/**
		* Indicates that the parameter of the given types is optional.
		* If the token matches, it is added to the value list.
		* If the token does not match, the value list completes and parsing continues.
		*/
		ArgumentListParseTypesMode[ArgumentListParseTypesMode["Optional"] = 1] = "Optional";
		/**
		* Same as {@link Required} but the next argument is interpreted as a float.
		*/
		ArgumentListParseTypesMode[ArgumentListParseTypesMode["RequiredAsFloat"] = 2] = "RequiredAsFloat";
		/**
		* Same as {@link Optional} but the next argument is interpreted as a float.
		*/
		ArgumentListParseTypesMode[ArgumentListParseTypesMode["OptionalAsFloat"] = 3] = "OptionalAsFloat";
		/**
		* Indicates that multiple arguments of the same types should be parsed as a list
		* Think: rest-parameter that allows parameters to follow if the type doesn't match anymore.
		* If the token is a open parenthesis, it starts reading the specified types as value list. If an unexpected item is
		* encountered an error diagnostic is added.
		* If the token matches the expected type, a single value is read.
		* If the token is any other type, an error diagnostic is added and parsing is stopped.
		*/
		ArgumentListParseTypesMode[ArgumentListParseTypesMode["RequiredAsValueList"] = 4] = "RequiredAsValueList";
		/**
		* Indicates that multiple parameters of the same types should be parsed. (this is mainly for backwards compatibility with older alphaTex files)
		* If the token matches, it is added to the value list. Parsing stays on the current type.
		* If the token does not match, the value list completes and parsing continues.
		*/
		ArgumentListParseTypesMode[ArgumentListParseTypesMode["ValueListWithoutParenthesis"] = 5] = "ValueListWithoutParenthesis";
		return ArgumentListParseTypesMode;
	}({});
	//#endregion
	//#region src/io/TypeConversions.ts
	/**
	* @target web
	* @internal
	*/
	var TypeConversions = class TypeConversions {
		static _conversionBuffer = /* @__PURE__ */ new ArrayBuffer(8);
		static _conversionByteArray = new Uint8Array(TypeConversions._conversionBuffer);
		static _dataView = new DataView(TypeConversions._conversionBuffer);
		static float64ToBytes(v) {
			TypeConversions._dataView.setFloat64(0, v, true);
			return TypeConversions._conversionByteArray;
		}
		static bytesToInt64LE(bytes) {
			TypeConversions._conversionByteArray.set(bytes, 0);
			const int64 = TypeConversions._dataView.getBigInt64(0, true);
			if (int64 <= Number.MAX_SAFE_INTEGER && int64 >= Number.MIN_SAFE_INTEGER) return Number(int64);
			return Number.MAX_SAFE_INTEGER;
		}
		static bytesToFloat64LE(bytes) {
			TypeConversions._conversionByteArray.set(bytes, 0);
			return TypeConversions._dataView.getFloat64(0, true);
		}
		static bytesToFloat32LE(bytes) {
			TypeConversions._conversionByteArray.set(bytes, 0);
			return TypeConversions._dataView.getFloat32(0, true);
		}
		static float32BEToBytes(v) {
			TypeConversions._dataView.setFloat32(0, v, false);
			return TypeConversions._conversionByteArray.slice(0, 4);
		}
		static uint16ToInt16(v) {
			TypeConversions._dataView.setUint16(0, v, true);
			return TypeConversions._dataView.getInt16(0, true);
		}
		static int16ToUint32(v) {
			TypeConversions._dataView.setInt16(0, v, true);
			return TypeConversions._dataView.getUint32(0, true);
		}
		static int32ToUint16(v) {
			TypeConversions._dataView.setInt32(0, v, true);
			return TypeConversions._dataView.getUint16(0, true);
		}
		static int32ToInt16(v) {
			TypeConversions._dataView.setInt32(0, v, true);
			return TypeConversions._dataView.getInt16(0, true);
		}
		static int32ToUint32(v) {
			TypeConversions._dataView.setInt32(0, v, true);
			return TypeConversions._dataView.getUint32(0, true);
		}
		static uint8ToInt8(v) {
			TypeConversions._dataView.setUint8(0, v);
			return TypeConversions._dataView.getInt8(0);
		}
	};
	//#endregion
	//#region src/io/IOHelper.ts
	/**
	* @public
	*/
	var IOHelper = class IOHelper {
		static readInt32BE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			const ch3 = input.readByte();
			const ch4 = input.readByte();
			return ch1 << 24 | ch2 << 16 | ch3 << 8 | ch4;
		}
		static readFloat32BE(readable) {
			const bits = new Uint8Array(4);
			readable.read(bits, 0, bits.length);
			bits.reverse();
			return TypeConversions.bytesToFloat32LE(bits);
		}
		static readFloat64BE(readable) {
			const bits = new Uint8Array(8);
			readable.read(bits, 0, bits.length);
			bits.reverse();
			return TypeConversions.bytesToFloat64LE(bits);
		}
		static readInt32LE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			const ch3 = input.readByte();
			return input.readByte() << 24 | ch3 << 16 | ch2 << 8 | ch1;
		}
		static readInt64LE(input) {
			const b = new Uint8Array(8);
			input.read(b, 0, b.length);
			return TypeConversions.bytesToInt64LE(b);
		}
		static readUInt32LE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			const ch3 = input.readByte();
			return input.readByte() << 24 | ch3 << 16 | ch2 << 8 | ch1;
		}
		static decodeUInt32LE(data, index) {
			const ch1 = data[index];
			const ch2 = data[index + 1];
			const ch3 = data[index + 2];
			return data[index + 3] << 24 | ch3 << 16 | ch2 << 8 | ch1;
		}
		static readUInt16LE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			return TypeConversions.int32ToUint16(ch2 << 8 | ch1);
		}
		static readInt16LE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			return TypeConversions.int32ToInt16(ch2 << 8 | ch1);
		}
		static readUInt32BE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			const ch3 = input.readByte();
			const ch4 = input.readByte();
			return TypeConversions.int32ToUint32(ch1 << 24 | ch2 << 16 | ch3 << 8 | ch4);
		}
		static readUInt16BE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			return TypeConversions.int32ToInt16(ch1 << 8 | ch2);
		}
		static readInt16BE(input) {
			const ch1 = input.readByte();
			const ch2 = input.readByte();
			return TypeConversions.int32ToInt16(ch1 << 8 | ch2);
		}
		static readByteArray(input, length) {
			const v = new Uint8Array(length);
			input.read(v, 0, length);
			return v;
		}
		static read8BitChars(input, length) {
			const b = new Uint8Array(length);
			input.read(b, 0, b.length);
			return IOHelper.toString(b, "utf-8");
		}
		static read8BitString(input) {
			let s = "";
			let c = input.readByte();
			while (c !== 0) {
				s += String.fromCharCode(c);
				c = input.readByte();
			}
			return s;
		}
		static read8BitStringLength(input, length) {
			let s = "";
			let z = -1;
			for (let i = 0; i < length; i++) {
				const c = input.readByte();
				if (c === 0 && z === -1) z = i;
				s += String.fromCharCode(c);
			}
			const t = s;
			if (z >= 0) return t.substr(0, z);
			return t;
		}
		static readSInt8(input) {
			const v = input.readByte();
			return ((v & 255) >> 7) * -256 + (v & 255);
		}
		static readInt24(input, index) {
			let i = input[index] | input[index + 1] << 8 | input[index + 2] << 16;
			if ((i & 8388608) === 8388608) i = i | 255 << 24;
			return i;
		}
		static readInt16(input, index) {
			return TypeConversions.int32ToInt16(input[index] | input[index + 1] << 8);
		}
		static toString(data, encoding) {
			const detectedEncoding = IOHelper._detectEncoding(data);
			if (detectedEncoding) encoding = detectedEncoding;
			if (!encoding) encoding = "utf-8";
			return new TextDecoder(encoding).decode(data);
		}
		static _detectEncoding(data) {
			if (data.length > 2 && data[0] === 254 && data[1] === 255) return "utf-16be";
			if (data.length > 2 && data[0] === 255 && data[1] === 254) return "utf-16le";
			if (data.length > 4 && data[0] === 0 && data[1] === 0 && data[2] === 254 && data[3] === 255) return "utf-32be";
			if (data.length > 4 && data[0] === 255 && data[1] === 254 && data[2] === 0 && data[3] === 0) return "utf-32le";
			return null;
		}
		static stringToBytes(str) {
			return new TextEncoder().encode(str);
		}
		static writeInt32BE(o, v) {
			o.writeByte(v >> 24 & 255);
			o.writeByte(v >> 16 & 255);
			o.writeByte(v >> 8 & 255);
			o.writeByte(v >> 0 & 255);
		}
		static writeInt32LE(o, v) {
			o.writeByte(v >> 0 & 255);
			o.writeByte(v >> 8 & 255);
			o.writeByte(v >> 16 & 255);
			o.writeByte(v >> 24 & 255);
		}
		static writeUInt16LE(o, v) {
			o.writeByte(v >> 0 & 255);
			o.writeByte(v >> 8 & 255);
		}
		static writeInt16LE(o, v) {
			o.writeByte(v >> 0 & 255);
			o.writeByte(v >> 8 & 255);
		}
		static writeInt16BE(o, v) {
			o.writeByte(v >> 8 & 255);
			o.writeByte(v >> 0 & 255);
		}
		static writeFloat32BE(o, v) {
			const b = TypeConversions.float32BEToBytes(v);
			o.write(b, 0, b.length);
		}
		static *iterateCodepoints(input) {
			let i = 0;
			while (i < input.length) {
				let c = input.charCodeAt(i);
				if (IOHelper.isLeadingSurrogate(c) && i + 1 < input.length) {
					i++;
					c = (c - 55296) * 1024 + (input.charCodeAt(i) - 56320) + 65536;
				}
				i++;
				yield c;
			}
		}
		static isLeadingSurrogate(charCode) {
			return charCode >= 55296 && charCode <= 56319;
		}
		static isTrailingSurrogate(charCode) {
			return charCode >= 56320 && charCode <= 57343;
		}
	};
	//#endregion
	//#region src/importer/alphaTex/AlphaTexLexer.ts
	/**
	* @public
	*/
	var AlphaTexLexer = class AlphaTexLexer {
		static _eof = 0;
		_codepoints;
		_codepoint = AlphaTexLexer._eof;
		_offset = 0;
		_line = 1;
		_col = 1;
		fatalError = false;
		_tokenStart = {
			line: 0,
			col: 0,
			offset: 0
		};
		_leadingComments;
		_trailingCommentNode;
		_previousToken;
		_peekedToken;
		lexerDiagnostics = new AlphaTexDiagnosticBag();
		constructor(input) {
			this._codepoints = [...IOHelper.iterateCodepoints(input)];
			this._offset = 0;
			this._line = 1;
			this._col = 1;
			this._codepoint = this._codepoints.length > 0 ? this._codepoints[0] : AlphaTexLexer._eof;
		}
		peekToken() {
			if (this.fatalError) return;
			let peeked = this._peekedToken;
			if (peeked) return peeked;
			peeked = this._readToken();
			this._peekedToken = peeked;
			return peeked;
		}
		extendToFloat(peekedNode) {
			if (this._codepoint !== 46 || this._offset + 1 >= this._codepoints.length || !AlphaTexLexer._isDigit(this._codepoints[this._offset + 1])) return peekedNode;
			let offset = this._offset + 2;
			while (offset < this._codepoints.length && AlphaTexLexer._isDigit(this._codepoints[offset])) offset++;
			if (offset < this._codepoints.length && AlphaTexLexer._isIdentifierCharacter(this._codepoints[offset])) return peekedNode;
			const characters = offset - this._offset - 1;
			this._offset += characters;
			this._col += characters;
			this._nextCodepoint();
			peekedNode.end = this._currentLexerLocation();
			peekedNode.value = Number.parseFloat(String.fromCodePoint(...this._codepoints.slice(peekedNode.start.offset, peekedNode.end.offset)));
			return peekedNode;
		}
		advance() {
			this._previousToken = this._peekedToken;
			this._peekedToken = void 0;
		}
		_nextCodepoint() {
			const codePoints = this._codepoints;
			let offset = this._offset;
			if (offset < codePoints.length - 1) {
				if (codePoints[offset] === 10) {
					this._trailingCommentNode = void 0;
					++this._line;
					this._col = 1;
				} else ++this._col;
				++offset;
				const codepoint = codePoints[offset];
				this._codepoint = codepoint;
				this._offset = offset;
				return codepoint;
			} else if (this._codepoint !== AlphaTexLexer._eof) {
				this._codepoint = AlphaTexLexer._eof;
				++this._col;
				this._offset = codePoints.length;
			}
			return AlphaTexLexer._eof;
		}
		previousTokenEndLocation() {
			return this._previousToken?.end ?? this._currentLexerLocation();
		}
		currentTokenLocation() {
			return this._peekedToken?.start ?? this._currentLexerLocation();
		}
		_currentLexerLocation() {
			return {
				line: this._line,
				col: this._col,
				offset: this._offset
			};
		}
		_readToken() {
			this._leadingComments = void 0;
			while (this._codepoint !== AlphaTexLexer._eof && !this.fatalError) {
				this._tokenStart = this._currentLexerLocation();
				if (AlphaTexLexer._terminalTokens.has(this._codepoint)) {
					const token = AlphaTexLexer._terminalTokens.get(this._codepoint)(this);
					if (token) {
						this._trailingCommentNode = token;
						return token;
					}
				} else if (AlphaTexLexer._isIdentifierCharacter(this._codepoint)) {
					const identifier = this._numberOrIdentifier();
					this._trailingCommentNode = identifier;
					return identifier;
				} else this._codepoint = this._nextCodepoint();
			}
		}
		_comment() {
			this._codepoint = this._nextCodepoint();
			if (this._codepoint === 47) this._singleLineComment();
			else if (this._codepoint === 42) this._multiLineComment();
			else {
				this.lexerDiagnostics.push({
					code: AlphaTexDiagnosticCode.AT001,
					message: `Unexpected character at comment start, expected '//' or '/*' but found '/${String.fromCodePoint(this._codepoint)}'`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: this._tokenStart,
					end: this._currentLexerLocation()
				});
				this.fatalError = true;
			}
		}
		static _terminalTokens = new Map([
			[47, (l) => l._comment()],
			[34, (l) => l._string()],
			[39, (l) => l._string()],
			[45, (l) => l._numberOrIdentifier()],
			[46, (l) => l._token({ nodeType: AlphaTexNodeType.Dot })],
			[58, (l) => l._token({ nodeType: AlphaTexNodeType.Colon })],
			[40, (l) => l._token({ nodeType: AlphaTexNodeType.LParen })],
			[41, (l) => l._token({ nodeType: AlphaTexNodeType.RParen })],
			[123, (l) => l._token({ nodeType: AlphaTexNodeType.LBrace })],
			[125, (l) => l._token({ nodeType: AlphaTexNodeType.RBrace })],
			[124, (l) => l._token({ nodeType: AlphaTexNodeType.Pipe })],
			[42, (l) => l._token({ nodeType: AlphaTexNodeType.Asterisk })],
			[92, (l) => l._metaCommand()],
			[9, (l) => l._whitespace()],
			[10, (l) => l._whitespace()],
			[11, (l) => l._whitespace()],
			[13, (l) => l._whitespace()],
			[32, (l) => l._whitespace()]
		]);
		_metaCommand() {
			const prefixStart = this._currentLexerLocation();
			this._codepoint = this._nextCodepoint();
			let prefix;
			let prefixEnd;
			if (this._codepoint === 92) {
				this._codepoint = this._nextCodepoint();
				prefixEnd = this._currentLexerLocation();
				prefix = {
					nodeType: AlphaTexNodeType.DoubleBackslash,
					start: prefixStart,
					end: prefixEnd
				};
			} else {
				prefixEnd = this._currentLexerLocation();
				prefix = {
					nodeType: AlphaTexNodeType.Backslash,
					start: prefixStart,
					end: prefixEnd
				};
			}
			let text = "";
			while (AlphaTexLexer._isIdentifierCharacter(this._codepoint)) {
				text += String.fromCodePoint(this._codepoint);
				this._codepoint = this._nextCodepoint();
			}
			if (text.length === 0) {
				this.lexerDiagnostics.push({
					code: AlphaTexDiagnosticCode.AT002,
					message: "Missing identifier after meta data start",
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: this._tokenStart,
					end: this._currentLexerLocation()
				});
				return;
			}
			return {
				nodeType: AlphaTexNodeType.Tag,
				leadingComments: this._leadingComments,
				start: this._tokenStart,
				end: this._currentLexerLocation(),
				prefix,
				tag: {
					nodeType: AlphaTexNodeType.Ident,
					text,
					start: prefixEnd,
					end: this._currentLexerLocation()
				}
			};
		}
		_token(t) {
			t.leadingComments = this._leadingComments;
			t.start = this._tokenStart;
			this._codepoint = this._nextCodepoint();
			t.end = this._currentLexerLocation();
			return t;
		}
		_string() {
			const startChar = this._codepoint;
			this._codepoint = this._nextCodepoint();
			let s = "";
			let previousCodepoint = -1;
			while (this._codepoint !== startChar && this._codepoint !== AlphaTexLexer._eof) {
				let codepoint = -1;
				if (this._codepoint === 92) {
					this._codepoint = this._nextCodepoint();
					if (this._codepoint === 92) codepoint = 92;
					else if (this._codepoint === startChar) codepoint = startChar;
					else if (this._codepoint === 82 || this._codepoint === 114) codepoint = 13;
					else if (this._codepoint === 78 || this._codepoint === 110) codepoint = 10;
					else if (this._codepoint === 84 || this._codepoint === 116) codepoint = 9;
					else if (this._codepoint === 117) {
						let hex = "";
						for (let i = 0; i < 4; i++) {
							this._codepoint = this._nextCodepoint();
							if (this._codepoint === AlphaTexLexer._eof) {
								this.lexerDiagnostics.push({
									code: AlphaTexDiagnosticCode.AT003,
									message: "Unexpected end of file. Need 4 hex characters on a \\uXXXX escape sequence",
									severity: AlphaTexDiagnosticsSeverity.Error,
									start: this._tokenStart,
									end: this._currentLexerLocation()
								});
								this.fatalError = true;
								return;
							}
							hex += String.fromCodePoint(this._codepoint);
						}
						codepoint = Number.parseInt(hex, 16);
						if (Number.isNaN(codepoint)) {
							this.lexerDiagnostics.push({
								code: AlphaTexDiagnosticCode.AT004,
								message: "Invalid unicode value. Need 4 hex characters on a \\uXXXX escape sequence.",
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: this._tokenStart,
								end: this._currentLexerLocation()
							});
							this.fatalError = true;
							return;
						}
					} else {
						this.lexerDiagnostics.push({
							code: AlphaTexDiagnosticCode.AT005,
							message: `Unsupported escape sequence. Expected '\\n', '\\r', '\\t', or '\\uXXXX' but found '\\${String.fromCodePoint(this._codepoint)}'.`,
							severity: AlphaTexDiagnosticsSeverity.Error,
							start: this._tokenStart,
							end: this._currentLexerLocation()
						});
						this.fatalError = true;
						return;
					}
				} else codepoint = this._codepoint;
				if (IOHelper.isLeadingSurrogate(previousCodepoint) && IOHelper.isTrailingSurrogate(codepoint)) {
					codepoint = (previousCodepoint - 55296) * 1024 + (codepoint - 56320) + 65536;
					s += String.fromCodePoint(codepoint);
				} else if (IOHelper.isLeadingSurrogate(codepoint)) {} else {
					if (IOHelper.isLeadingSurrogate(previousCodepoint)) s += String.fromCodePoint(previousCodepoint);
					if (codepoint > 0) s += String.fromCodePoint(codepoint);
				}
				previousCodepoint = codepoint;
				this._codepoint = this._nextCodepoint();
			}
			if (this._codepoint === AlphaTexLexer._eof) {
				this.lexerDiagnostics.push({
					code: AlphaTexDiagnosticCode.AT006,
					message: `Unexpected end of file. String not closed.`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: this._tokenStart,
					end: this._currentLexerLocation()
				});
				this.fatalError = true;
				return;
			}
			const stringToken = {
				nodeType: AlphaTexNodeType.String,
				text: s,
				leadingComments: this._leadingComments,
				start: this._tokenStart,
				end: this._currentLexerLocation()
			};
			this._codepoint = this._nextCodepoint();
			return stringToken;
		}
		_multiLineComment() {
			const trailingCommentNode = this._trailingCommentNode;
			const comment = {
				start: this._tokenStart,
				end: this._currentLexerLocation(),
				text: "",
				multiLine: true
			};
			while (this._codepoint !== AlphaTexLexer._eof) if (this._codepoint === 42) {
				this._codepoint = this._nextCodepoint();
				if (this._codepoint === 47) {
					this._codepoint = this._nextCodepoint();
					break;
				} else {
					comment.text += `*${String.fromCodePoint(this._codepoint)}`;
					comment.end.line = this._line;
					comment.end.col = this._col;
					comment.end.offset = this._offset;
				}
			} else {
				this._codepoint = this._nextCodepoint();
				comment.text += String.fromCodePoint(this._codepoint);
				comment.end.line = this._line;
				comment.end.col = this._col;
				comment.end.offset = this._offset;
			}
			if (trailingCommentNode) {
				trailingCommentNode.trailingComments ??= [];
				trailingCommentNode.trailingComments.push(comment);
			} else {
				this._leadingComments ??= [];
				this._leadingComments.push(comment);
			}
		}
		_numberOrIdentifier() {
			let str = "";
			let isNumber = true;
			let codepoint = this._codepoint;
			if (codepoint === 45) {
				str += String.fromCodePoint(codepoint);
				codepoint = this._nextCodepoint();
				if (!AlphaTexLexer._isDigit(codepoint)) isNumber = false;
			}
			let keepReading = true;
			do
				if (isNumber) if (AlphaTexLexer._isDigit(codepoint)) {
					str += String.fromCodePoint(codepoint);
					codepoint = this._nextCodepoint();
					keepReading = true;
				} else if (AlphaTexLexer._isIdentifierCharacter(codepoint)) {
					isNumber = false;
					str += String.fromCodePoint(codepoint);
					codepoint = this._nextCodepoint();
					keepReading = true;
				} else keepReading = false;
				else if (AlphaTexLexer._isIdentifierCharacter(codepoint)) {
					str += String.fromCodePoint(codepoint);
					codepoint = this._nextCodepoint();
					keepReading = true;
				} else keepReading = false;
			while (keepReading);
			if (isNumber) return {
				nodeType: AlphaTexNodeType.Number,
				leadingComments: this._leadingComments,
				start: this._tokenStart,
				end: this._currentLexerLocation(),
				value: Number.parseInt(str, 10)
			};
			return {
				nodeType: AlphaTexNodeType.Ident,
				leadingComments: this._leadingComments,
				start: this._tokenStart,
				end: this._currentLexerLocation(),
				text: str
			};
		}
		_singleLineComment() {
			const trailingCommentNode = this._trailingCommentNode;
			const comment = {
				start: this._tokenStart,
				end: this._currentLexerLocation(),
				text: "",
				multiLine: false
			};
			let codepoint = this._codepoint;
			while (codepoint !== AlphaTexLexer._eof) {
				codepoint = this._nextCodepoint();
				if (codepoint !== 10 && codepoint !== AlphaTexLexer._eof) {
					comment.text += String.fromCodePoint(codepoint);
					comment.end.line = this._line;
					comment.end.col = this._col;
					comment.end.offset = this._offset;
				} else break;
			}
			if (trailingCommentNode) {
				trailingCommentNode.trailingComments ??= [];
				trailingCommentNode.trailingComments.push(comment);
			} else {
				this._leadingComments ??= [];
				this._leadingComments.push(comment);
			}
		}
		_whitespace() {
			let codepoint = this._codepoint;
			while (AlphaTexLexer._isWhiteSpace(codepoint)) {
				if (codepoint === 10) this._trailingCommentNode = void 0;
				codepoint = this._nextCodepoint();
			}
		}
		static _isDigit(ch) {
			return ch >= 48 && ch <= 57;
		}
		static _buildNonIdentifierChars() {
			const c = /* @__PURE__ */ new Set();
			for (const terminal of AlphaTexLexer._terminalTokens.keys()) c.add(terminal);
			c.delete(45);
			c.add(AlphaTexLexer._eof);
			return c;
		}
		static _nonIdentifierChars = AlphaTexLexer._buildNonIdentifierChars();
		static _isIdentifierCharacter(ch) {
			return !AlphaTexLexer._nonIdentifierChars.has(ch);
		}
		static _isWhiteSpace(ch) {
			return ch === 32 || ch === 10 || ch === 13 || ch === 9 || ch === 11;
		}
	};
	//#endregion
	//#region src/importer/alphaTex/AlphaTexParser.ts
	/**
	* The different modes of the alphaTex parser.
	* @public
	*/
	var AlphaTexParseMode = /* @__PURE__ */ function(AlphaTexParseMode) {
		/**
		* Optimizes the parser for only the model importing.
		* The model importing does not need all details from the AST allowing a more lightweight
		* parsing.
		*/
		AlphaTexParseMode[AlphaTexParseMode["ForModelImport"] = 0] = "ForModelImport";
		/**
		* Performs the full AST parsing with all details.
		* This mode is mainly used by the Language Server providing IDE support.
		* All AST information is parsed and filled.
		*/
		AlphaTexParseMode[AlphaTexParseMode["Full"] = 1] = "Full";
		return AlphaTexParseMode;
	}({});
	/**
	* A parser for translating a given alphaTex source into an AST for further use
	* in the alphaTex importer, editors etc.
	* @public
	*/
	var AlphaTexParser = class AlphaTexParser {
		lexer;
		_scoreNode;
		_metaDataReader = AlphaTex1MetaDataReader.instance;
		/**
		* The parsing mode.
		*/
		mode = 0;
		get lexerDiagnostics() {
			return this.lexer.lexerDiagnostics;
		}
		parserDiagnostics = new AlphaTexDiagnosticBag();
		addParserDiagnostic(diagnostics) {
			this.parserDiagnostics.push(diagnostics);
		}
		/**
		* @internal
		*/
		unexpectedToken(actual, expected, abort) {
			if (!actual) this.addParserDiagnostic({
				code: AlphaTexDiagnosticCode.AT203,
				start: this.lexer.currentTokenLocation(),
				end: this.lexer.currentTokenLocation(),
				severity: AlphaTexDiagnosticsSeverity.Error,
				message: "Unexpected end of file."
			});
			else this.addParserDiagnostic({
				code: AlphaTexDiagnosticCode.AT202,
				message: `Unexpected '${AlphaTexNodeType[actual.nodeType]}' token. Expected one of following: ${expected.map((v) => AlphaTexNodeType[v]).join(",")}`,
				severity: AlphaTexDiagnosticsSeverity.Error,
				start: actual.start,
				end: actual.end
			});
			if (abort) this.lexer.fatalError = true;
		}
		constructor(source) {
			this.lexer = new AlphaTexLexer(source);
		}
		read() {
			this._score();
			return this._scoreNode;
		}
		_score() {
			this._scoreNode = {
				nodeType: AlphaTexNodeType.Score,
				bars: [],
				start: this.lexer.currentTokenLocation()
			};
			try {
				this._bars();
			} finally {
				this._scoreNode.end = this.lexer.previousTokenEndLocation();
			}
		}
		_bars() {
			let token = this.lexer.peekToken();
			while (token) {
				this._bar();
				token = this.lexer.peekToken();
			}
		}
		_bar() {
			const bar = {
				nodeType: AlphaTexNodeType.Bar,
				metaData: [],
				beats: [],
				pipe: void 0,
				start: this.lexer.currentTokenLocation()
			};
			this._scoreNode.bars.push(bar);
			try {
				this._barMetaData(bar);
				this._barBeats(bar);
				const next = this.lexer.peekToken();
				if (next?.nodeType === AlphaTexNodeType.Pipe) {
					bar.pipe = next;
					this.lexer.advance();
				}
				if (bar.metaData.length > 0 || bar.beats.length > 0 || bar.pipe) bar.end = this.lexer.previousTokenEndLocation();
			} finally {
				bar.end = this.lexer.previousTokenEndLocation();
			}
		}
		_barMetaData(bar) {
			let token = this.lexer.peekToken();
			while (token && (token.nodeType === AlphaTexNodeType.Tag || token.nodeType === AlphaTexNodeType.Dot)) {
				if (token.nodeType === AlphaTexNodeType.Dot) {
					this.lexer.advance();
					this.addParserDiagnostic({
						code: AlphaTexDiagnosticCode.AT400,
						message: `The dots separating score metadata, score contents and the sync points can be removed.`,
						severity: AlphaTexDiagnosticsSeverity.Hint,
						start: token.start,
						end: token.end
					});
				} else this._metaData(bar.metaData);
				token = this.lexer.peekToken();
			}
		}
		_barBeats(bar) {
			let token = this.lexer.peekToken();
			while (token && token.nodeType !== AlphaTexNodeType.Pipe && token.nodeType !== AlphaTexNodeType.Dot && token.nodeType !== AlphaTexNodeType.Tag) {
				const beat = this._beat();
				if (beat) bar.beats.push(beat);
				token = this.lexer.peekToken();
			}
		}
		_beat() {
			const beat = {
				nodeType: AlphaTexNodeType.Beat,
				durationChange: void 0,
				notes: void 0,
				rest: void 0,
				beatEffects: void 0,
				beatMultiplier: void 0,
				beatMultiplierValue: void 0,
				start: this.lexer.peekToken()?.start
			};
			try {
				this._beatDurationChange(beat);
				this._beatContent(beat);
				if (!beat.notes && !beat.rest) return beat;
				this._beatDuration(beat);
				this._beatMultiplier(beat);
				beat.beatEffects = this._properties((property) => this._metaDataReader.readBeatPropertyArguments(this, property));
				if (beat.beatMultiplierValue !== void 0 && beat.beatEffects?.openBrace) this.addParserDiagnostic({
					code: AlphaTexDiagnosticCode.AT304,
					message: "The beat multiplier should be specified after the beat effects.",
					severity: AlphaTexDiagnosticsSeverity.Warning,
					start: beat.beatMultiplier.start,
					end: beat.beatMultiplierValue.end
				});
				this._beatMultiplier(beat);
			} finally {
				beat.end = this.lexer.previousTokenEndLocation();
			}
			return beat;
		}
		_beatDuration(beat) {
			const dot = this.lexer.peekToken();
			if (dot?.nodeType !== AlphaTexNodeType.Dot) return;
			beat.durationDot = dot;
			this.lexer.advance();
			const durationValue = this.lexer.peekToken();
			if (durationValue?.nodeType === AlphaTexNodeType.Number) {
				beat.durationValue = durationValue;
				this.lexer.advance();
				return;
			} else if (durationValue?.nodeType === AlphaTexNodeType.Tag) {
				beat.durationDot = void 0;
				return;
			} else if (!durationValue) return;
			else this.unexpectedToken(durationValue, [AlphaTexNodeType.Number], true);
		}
		_beatDurationChange(beat) {
			const colon = this.lexer.peekToken();
			if (colon?.nodeType !== AlphaTexNodeType.Colon) return;
			this.lexer.advance();
			const durationChange = {
				nodeType: AlphaTexNodeType.Duration,
				colon,
				value: void 0,
				properties: void 0,
				start: colon.start
			};
			beat.durationChange = durationChange;
			try {
				const durationValue = this.lexer.peekToken();
				if (!durationValue || durationValue.nodeType !== AlphaTexNodeType.Number) {
					this.addParserDiagnostic({
						code: AlphaTexDiagnosticCode.AT201,
						message: "Missing duration value after ':'.",
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: colon.start,
						end: colon.end
					});
					return;
				}
				this.lexer.advance();
				durationChange.value = durationValue;
				durationChange.properties = this._properties((property) => this._metaDataReader.readDurationChangePropertyArguments(this, property));
			} finally {
				durationChange.end = this.lexer.previousTokenEndLocation();
			}
		}
		_beatContent(beat) {
			const notes = this.lexer.peekToken();
			if (!notes) return;
			if (notes.nodeType === AlphaTexNodeType.Ident && notes.text === "r") {
				beat.rest = notes;
				this.lexer.advance();
			} else if (notes.nodeType === AlphaTexNodeType.LParen) beat.notes = this._noteList(notes);
			else {
				const note = this._note(notes);
				if (note) beat.notes = {
					nodeType: AlphaTexNodeType.NoteList,
					openParenthesis: void 0,
					notes: [note],
					closeParenthesis: void 0,
					start: note.start,
					end: note.end
				};
			}
		}
		_beatMultiplier(beat) {
			const multiplier = this.lexer.peekToken();
			if (!multiplier || multiplier.nodeType !== AlphaTexNodeType.Asterisk) return;
			this.lexer.advance();
			beat.beatMultiplier = multiplier;
			const multiplierValue = this.lexer.peekToken();
			if (!multiplierValue || multiplierValue.nodeType !== AlphaTexNodeType.Number) {
				this.addParserDiagnostic({
					code: AlphaTexDiagnosticCode.AT200,
					message: "Missing beat multiplier value after '*'.",
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: beat.beatMultiplier.start,
					end: beat.beatMultiplier.end
				});
				return;
			}
			beat.beatMultiplierValue = multiplierValue;
			this.lexer.advance();
		}
		_noteList(openParenthesis) {
			const noteList = {
				nodeType: AlphaTexNodeType.NoteList,
				openParenthesis: void 0,
				notes: [],
				closeParenthesis: void 0,
				start: this.lexer.currentTokenLocation()
			};
			try {
				noteList.openParenthesis = openParenthesis;
				this.lexer.advance();
				let token = this.lexer.peekToken();
				while (token && token.nodeType !== AlphaTexNodeType.RParen) {
					const note = this._note(token);
					if (note) noteList.notes.push(note);
					else break;
					token = this.lexer.peekToken();
				}
				const closeParenthesis = this.lexer.peekToken();
				if (closeParenthesis?.nodeType === AlphaTexNodeType.RParen) {
					noteList.closeParenthesis = closeParenthesis;
					this.lexer.advance();
				} else this.addParserDiagnostic({
					code: AlphaTexDiagnosticCode.AT206,
					message: "Unexpected end of file. Group not closed.",
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: closeParenthesis?.start ?? this.lexer.currentTokenLocation(),
					end: closeParenthesis?.end ?? this.lexer.currentTokenLocation()
				});
			} finally {
				noteList.end = this.lexer.previousTokenEndLocation();
			}
			return noteList;
		}
		_note(noteValue) {
			const note = {
				nodeType: AlphaTexNodeType.Note,
				noteValue: {
					nodeType: AlphaTexNodeType.Ident,
					text: ""
				},
				start: noteValue.start
			};
			try {
				let canHaveString = false;
				switch (noteValue.nodeType) {
					case AlphaTexNodeType.Number:
						note.noteValue = noteValue;
						this.lexer.advance();
						canHaveString = true;
						break;
					case AlphaTexNodeType.String:
						note.noteValue = noteValue;
						this.lexer.advance();
						switch (note.noteValue.text) {
							case "x":
							case "-":
								canHaveString = true;
								break;
						}
						break;
					case AlphaTexNodeType.Ident:
						note.noteValue = noteValue;
						this.lexer.advance();
						switch (note.noteValue.text) {
							case "x":
							case "-":
								canHaveString = true;
								break;
						}
						break;
					default:
						this.unexpectedToken(noteValue, [
							AlphaTexNodeType.Number,
							AlphaTexNodeType.String,
							AlphaTexNodeType.Ident
						], true);
						return;
				}
				if (canHaveString) {
					const dot = this.lexer.peekToken();
					if (dot?.nodeType === AlphaTexNodeType.Dot) {
						const noteStringDot = dot;
						this.lexer.advance();
						const noteString = this.lexer.peekToken();
						if (!noteString) {
							this.unexpectedToken(noteString, [AlphaTexNodeType.Number], true);
							return;
						}
						if (noteString.nodeType === AlphaTexNodeType.Tag) return note;
						else if (noteString.nodeType === AlphaTexNodeType.Number) {
							note.noteStringDot = noteStringDot;
							note.noteString = noteString;
							this.lexer.advance();
						} else {
							this.unexpectedToken(noteString, [AlphaTexNodeType.Number], true);
							return;
						}
					}
				}
				note.noteEffects = this._properties((property) => this._metaDataReader.readNotePropertyArguments(this, property));
			} finally {
				note.end = this.lexer.previousTokenEndLocation();
			}
			return note;
		}
		static _allowValuesAfterProperties = new Set(["chord"]);
		_metaData(metaDataList) {
			const tag = this.lexer.peekToken();
			if (!tag || tag.nodeType !== AlphaTexNodeType.Tag) return;
			const metaData = {
				nodeType: AlphaTexNodeType.Meta,
				tag,
				start: tag.start,
				properties: void 0,
				propertiesBeforeArguments: false
			};
			this.lexer.advance();
			metaDataList.push(metaData);
			try {
				const allowValuesAfterProperties = AlphaTexParser._allowValuesAfterProperties.has(metaData.tag.tag.text);
				const braceCandidate = this.lexer.peekToken();
				if (allowValuesAfterProperties && braceCandidate?.nodeType === AlphaTexNodeType.LBrace) {
					metaData.propertiesBeforeArguments = true;
					metaData.properties = this._properties((property) => this._metaDataReader.readMetaDataPropertyArguments(this, metaData.tag, property));
					metaData.arguments = this.argumentList();
					if (!metaData.arguments) {
						metaData.arguments = this._metaDataReader.readMetaDataArguments(this, metaData.tag);
						if (metaData.arguments && metaData.arguments.arguments.length > 1) {
							this.addParserDiagnostic({
								code: AlphaTexDiagnosticCode.AT301,
								message: `Metadata arguments should be wrapped into parenthesis.`,
								severity: AlphaTexDiagnosticsSeverity.Warning,
								start: metaData.arguments?.start ?? metaData.start,
								end: metaData.arguments?.end ?? metaData.end
							});
							this.addParserDiagnostic({
								code: AlphaTexDiagnosticCode.AT302,
								message: `Metadata arguments should be placed before metadata properties.`,
								severity: AlphaTexDiagnosticsSeverity.Warning,
								start: metaData.arguments?.start ?? metaData.start,
								end: metaData.arguments?.end ?? metaData.end
							});
						}
					}
				} else {
					if (this._metaDataReader.hasMetaDataArguments(metaData.tag)) {
						metaData.arguments = this.argumentList();
						if (!metaData.arguments) {
							metaData.arguments = this._metaDataReader.readMetaDataArguments(this, metaData.tag);
							if (metaData.arguments && metaData.arguments.arguments.length > 1) this.addParserDiagnostic({
								code: AlphaTexDiagnosticCode.AT301,
								message: `Metadata arguments should be wrapped into parenthesis.`,
								severity: AlphaTexDiagnosticsSeverity.Warning,
								start: metaData.arguments?.start ?? metaData.start,
								end: metaData.arguments?.end ?? metaData.end
							});
						}
					}
					metaData.properties = this._properties((property) => this._metaDataReader.readMetaDataPropertyArguments(this, metaData.tag, property));
				}
			} finally {
				metaData.end = this.lexer.previousTokenEndLocation();
			}
			return metaData;
		}
		_properties(readPropertyArgs) {
			const braceOpen = this.lexer.peekToken();
			if (!braceOpen || braceOpen.nodeType !== AlphaTexNodeType.LBrace) return;
			const properties = {
				nodeType: AlphaTexNodeType.Props,
				openBrace: braceOpen,
				properties: [],
				closeBrace: void 0,
				start: braceOpen.start
			};
			this.lexer.advance();
			try {
				let token = this.lexer.peekToken();
				while (token?.nodeType === AlphaTexNodeType.Ident) {
					properties.properties.push(this._property(token, readPropertyArgs));
					token = this.lexer.peekToken();
				}
				const braceClose = this.lexer.peekToken();
				if (braceClose?.nodeType === AlphaTexNodeType.RBrace) {
					properties.closeBrace = braceClose;
					this.lexer.advance();
				} else this.addParserDiagnostic({
					code: AlphaTexDiagnosticCode.AT206,
					message: "Unexpected end of file. Group not closed.",
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: this.lexer.currentTokenLocation(),
					end: this.lexer.currentTokenLocation()
				});
			} finally {
				properties.end = this.lexer.previousTokenEndLocation();
			}
			return properties;
		}
		_property(identifier, readPropertyArgs) {
			const property = {
				nodeType: AlphaTexNodeType.Prop,
				property: identifier,
				arguments: void 0
			};
			this.lexer.advance();
			property.start = property.property.start;
			try {
				property.arguments = this.argumentList();
				if (!property.arguments) {
					property.arguments = readPropertyArgs(property);
					if (property.arguments && property.arguments.arguments.length > 1) this.addParserDiagnostic({
						code: AlphaTexDiagnosticCode.AT303,
						message: "Property args should be wrapped into parenthesis.",
						severity: AlphaTexDiagnosticsSeverity.Warning,
						start: property.arguments.start,
						end: property.arguments.end
					});
				}
			} finally {
				property.end = this.lexer.previousTokenEndLocation();
			}
			return property;
		}
		argumentList() {
			const openParenthesis = this.lexer.peekToken();
			if (openParenthesis?.nodeType !== AlphaTexNodeType.LParen) return;
			const valueList = {
				nodeType: AlphaTexNodeType.Arguments,
				openParenthesis,
				arguments: [],
				closeParenthesis: void 0,
				start: openParenthesis.start
			};
			this.lexer.advance();
			try {
				let token = this.lexer.peekToken();
				while (token && token?.nodeType !== AlphaTexNodeType.RParen) {
					switch (token.nodeType) {
						case AlphaTexNodeType.Ident:
							valueList.arguments.push(token);
							this.lexer.advance();
							break;
						case AlphaTexNodeType.String:
							valueList.arguments.push(token);
							this.lexer.advance();
							break;
						case AlphaTexNodeType.Number:
							valueList.arguments.push(this.lexer.extendToFloat(token));
							this.lexer.advance();
							break;
						default:
							this.unexpectedToken(token, [
								AlphaTexNodeType.Ident,
								AlphaTexNodeType.String,
								AlphaTexNodeType.Number
							], false);
							this.lexer.advance();
							break;
					}
					token = this.lexer.peekToken();
				}
				const closeParenthesis = this.lexer.peekToken();
				if (closeParenthesis?.nodeType === AlphaTexNodeType.RParen) {
					valueList.closeParenthesis = closeParenthesis;
					this.lexer.advance();
				} else this.addParserDiagnostic({
					code: AlphaTexDiagnosticCode.AT206,
					message: "Unexpected end of file. Group not closed.",
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: this.lexer.currentTokenLocation(),
					end: this.lexer.currentTokenLocation()
				});
			} finally {
				valueList.end = this.lexer.previousTokenEndLocation();
			}
			return valueList;
		}
	};
	//#endregion
	//#region src/importer/alphaTex/ATNF.ts
	/**
	* AlphaTexNodeFactory (short name for less code)
	* @internal
	*/
	var Atnf = class Atnf {
		static ident(text) {
			return {
				nodeType: AlphaTexNodeType.Ident,
				text
			};
		}
		static string(text) {
			return {
				nodeType: AlphaTexNodeType.String,
				text
			};
		}
		static number(value) {
			return {
				nodeType: AlphaTexNodeType.Number,
				value
			};
		}
		static meta(tag, args, properties) {
			return {
				nodeType: AlphaTexNodeType.Meta,
				tag: {
					nodeType: AlphaTexNodeType.Tag,
					prefix: { nodeType: AlphaTexNodeType.Backslash },
					tag: {
						nodeType: AlphaTexNodeType.Ident,
						text: tag
					}
				},
				arguments: args,
				properties,
				propertiesBeforeArguments: false
			};
		}
		static identMeta(tag, value) {
			return Atnf.meta(tag, Atnf.identValue(value));
		}
		static numberMeta(tag, value) {
			return Atnf.meta(tag, Atnf.numberValue(value));
		}
		static args(args, parentheses = void 0) {
			const valueList = {
				nodeType: AlphaTexNodeType.Arguments,
				arguments: args.filter((v) => v !== void 0)
			};
			if (parentheses === void 0 ? valueList.arguments.length > 1 : parentheses) {
				valueList.openParenthesis = { nodeType: AlphaTexNodeType.LParen };
				valueList.closeParenthesis = { nodeType: AlphaTexNodeType.RParen };
			}
			if (valueList.arguments.length === 0) return;
			return valueList;
		}
		static stringValue(text) {
			return Atnf.args([Atnf.string(text)]);
		}
		static identValue(text) {
			return Atnf.args([Atnf.ident(text)]);
		}
		static numberValue(value) {
			return Atnf.args([Atnf.number(value)]);
		}
		static props(properties) {
			const node = {
				nodeType: AlphaTexNodeType.Props,
				properties: [],
				openBrace: { nodeType: AlphaTexNodeType.LBrace },
				closeBrace: { nodeType: AlphaTexNodeType.RBrace }
			};
			for (const p of properties) if (p) node.properties.push({
				nodeType: AlphaTexNodeType.Prop,
				property: Atnf.ident(p[0]),
				arguments: p[1]
			});
			return node;
		}
		static prop(properties, identifier, args) {
			properties.push({
				nodeType: AlphaTexNodeType.Prop,
				property: Atnf.ident(identifier),
				arguments: args
			});
		}
	};
	//#endregion
	//#region src/importer/alphaTex/AlphaTex1MetaDataReader.ts
	/**
	* @internal
	*/
	var AlphaTex1MetaDataReader = class AlphaTex1MetaDataReader {
		static instance = new AlphaTex1MetaDataReader();
		static _argumentTypes = new Set([
			AlphaTexNodeType.LParen,
			AlphaTexNodeType.String,
			AlphaTexNodeType.Ident,
			AlphaTexNodeType.Number
		]);
		hasMetaDataArguments(metaData) {
			const tag = metaData.tag.text.toLowerCase();
			for (const lookup of AlphaTex1LanguageDefinitions.metaDataSignatures) if (lookup.has(tag)) return lookup.get(tag) !== null;
			return true;
		}
		readMetaDataArguments(parser, metaData) {
			const tag = metaData.tag.text.toLowerCase();
			for (const lookup of AlphaTex1LanguageDefinitions.metaDataSignatures) if (lookup.has(tag)) {
				const types = lookup.get(tag);
				if (types) return this._readArguments(parser, types);
				else return;
			}
			parser.addParserDiagnostic({
				code: AlphaTexDiagnosticCode.AT204,
				message: `Unrecognized metadata '${metaData.tag.text}'.`,
				severity: AlphaTexDiagnosticsSeverity.Error,
				start: metaData.start,
				end: metaData.end
			});
			parser.lexer.fatalError = true;
		}
		readMetaDataPropertyArguments(parser, metaData, property) {
			const tag = metaData.tag.text.toLowerCase();
			if (!AlphaTex1LanguageDefinitions.metaDataProperties.has(tag)) return;
			const props = AlphaTex1LanguageDefinitions.metaDataProperties.get(tag);
			if (!props) return this._readPropertyArguments(parser, [], property);
			return this._readPropertyArguments(parser, [props], property);
		}
		readBeatPropertyArguments(parser, property) {
			return this._readPropertyArguments(parser, [AlphaTex1LanguageDefinitions.beatProperties], property);
		}
		readDurationChangePropertyArguments(parser, property) {
			return this._readPropertyArguments(parser, [AlphaTex1LanguageDefinitions.durationChangeProperties], property);
		}
		readNotePropertyArguments(parser, property) {
			return this._readPropertyArguments(parser, [AlphaTex1LanguageDefinitions.noteProperties, AlphaTex1LanguageDefinitions.beatProperties], property);
		}
		_readPropertyArguments(parser, lookups, property) {
			const tag = property.property.text.toLowerCase();
			const endOfProperty = new Set([AlphaTexNodeType.Ident, AlphaTexNodeType.RBrace]);
			for (const lookup of lookups) if (lookup.has(tag)) {
				const types = lookup.get(tag);
				if (types) return this._readArguments(parser, types, endOfProperty);
				else {
					this._skipRemainingArguments(parser, [], endOfProperty);
					return;
				}
			}
			let skip = parser.lexer.peekToken();
			while (skip && skip.nodeType !== AlphaTexNodeType.Ident && skip.nodeType !== AlphaTexNodeType.RBrace) {
				parser.lexer.advance();
				skip = parser.lexer.peekToken();
			}
			parser.addParserDiagnostic({
				code: AlphaTexDiagnosticCode.AT205,
				message: `Unrecognized property '${property.property.text}'.`,
				severity: AlphaTexDiagnosticsSeverity.Error,
				start: property.property.start,
				end: skip?.start ?? parser.lexer.currentTokenLocation()
			});
		}
		_readArguments(parser, signatures, endOfListTypes) {
			if (signatures.length === 1 && signatures[0].parameters.length === 0) return;
			const argValues = [];
			const valueListStart = parser.lexer.peekToken()?.start;
			const parseRemaining = endOfListTypes !== void 0;
			const candidates = new Map(signatures.map((v, i) => [i, {
				signature: v,
				parameterIndex: 0,
				parameterHasValues: false,
				parameterValueMatches: 0
			}]));
			const allCandidates = this._filterCandidates(parser, candidates, argValues, endOfListTypes);
			const error = this._validateArguments(parser, candidates, argValues, endOfListTypes, signatures, valueListStart);
			if (parseRemaining) this._skipRemainingArguments(parser, signatures, endOfListTypes);
			return this._createArgumentList(argValues, valueListStart, parser.lexer.previousTokenEndLocation(), error, allCandidates);
		}
		_validateArguments(parser, candidates, argValues, endOfListTypes, signatures, valueListStart) {
			const lastToken = parser.lexer.peekToken();
			let error = false;
			if (candidates.size !== 1 && lastToken === void 0) {
				parser.addParserDiagnostic({
					code: AlphaTexDiagnosticCode.AT203,
					start: parser.lexer.currentTokenLocation(),
					end: parser.lexer.currentTokenLocation(),
					severity: AlphaTexDiagnosticsSeverity.Error,
					message: "Unexpected end of file."
				});
				error = true;
			} else if (candidates.size === 0) {
				if (lastToken !== void 0 && argValues.length === 0) {
					if (endOfListTypes && !endOfListTypes.has(lastToken.nodeType)) {
						argValues.push(parser.lexer.peekToken());
						parser.lexer.advance();
					}
				}
				parser.addParserDiagnostic({
					code: AlphaTexDiagnosticCode.AT219,
					message: `Error parsing arguments: no overload matched arguments ${AlphaTex1MetaDataReader.generateSignaturesFromArguments(argValues)}. Signatures:\n${AlphaTex1MetaDataReader.generateSignatures(signatures)}`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: valueListStart,
					end: parser.lexer.previousTokenEndLocation()
				});
				error = true;
			}
			return error;
		}
		_createArgumentList(argValues, start, end, error, allCandidates) {
			if (argValues.length === 0) return;
			const valueList = Atnf.args(argValues, false);
			valueList.start = start;
			valueList.end = end;
			valueList.validated = !error;
			if (allCandidates) {
				if (allCandidates.length > 1) AlphaTex1MetaDataReader.sortCandidates(allCandidates);
				valueList.signatureCandidateIndices = allCandidates.map((c) => c[0]);
			}
			return valueList;
		}
		_filterCandidates(parser, candidates, argValues, endOfListTypes) {
			const parseFull = parser.mode === AlphaTexParseMode.Full;
			const trackValue = (value, overloadIndex) => {
				const candidate = candidates.get(overloadIndex);
				if (value.nodeType === AlphaTexNodeType.LParen) {
					const args = parser.argumentList();
					if (args) for (const v of args.arguments) {
						if (parseFull) {
							if (!v.parameterIndices) v.parameterIndices = /* @__PURE__ */ new Map();
							v.parameterIndices.set(overloadIndex, candidate.parameterIndex);
						}
						argValues.push(v);
					}
				} else {
					const valueNode = value;
					if (parseFull) {
						if (!valueNode.parameterIndices) valueNode.parameterIndices = /* @__PURE__ */ new Map();
						valueNode.parameterIndices.set(overloadIndex, candidate.parameterIndex);
					}
					if (argValues.length === 0 || argValues[argValues.length - 1] !== valueNode) {
						argValues.push(valueNode);
						parser.lexer.advance();
					}
				}
			};
			const extendToFloat = (value) => {
				parser.lexer.extendToFloat(value);
			};
			const argTypes = AlphaTex1MetaDataReader._argumentTypes;
			while (candidates.size > 1 || candidates.size > 0 && !AlphaTex1MetaDataReader._hasExactMatch(candidates)) {
				const value = parser.lexer.peekToken();
				if (!value || !argTypes.has(value.nodeType)) break;
				if (!AlphaTex1MetaDataReader.filterSignatureCandidates(candidates, value, endOfListTypes !== void 0 && endOfListTypes.has(value.nodeType), trackValue, extendToFloat)) break;
			}
			const allCandidates = parser.mode === AlphaTexParseMode.Full ? Array.from(candidates.entries()) : void 0;
			AlphaTex1MetaDataReader.filterIncompleteCandidates(candidates);
			return allCandidates;
		}
		static sortCandidates(allCandidates) {
			if (allCandidates.length < 2) return;
			allCandidates.sort((a, b) => {
				const aDistance = Math.abs(a[1].parameterIndex - a[1].signature.parameters.length);
				const bDistance = Math.abs(b[1].parameterIndex - b[1].signature.parameters.length);
				if (aDistance === bDistance) {
					const aMatches = a[1].parameterValueMatches;
					return b[1].parameterValueMatches - aMatches;
				}
				return aDistance - bDistance;
			});
		}
		_skipRemainingArguments(parser, signatures, endOfListTypes) {
			const unexpectedValuesStart = parser.lexer.currentTokenLocation();
			let remaining = parser.lexer.peekToken();
			let anyUnexpected = false;
			const argTypes = AlphaTex1MetaDataReader._argumentTypes;
			while (remaining && !endOfListTypes.has(remaining.nodeType)) if (argTypes.has(remaining.nodeType)) {
				parser.lexer.advance();
				anyUnexpected = true;
				remaining = parser.lexer.peekToken();
			} else remaining = void 0;
			if (anyUnexpected) parser.addParserDiagnostic({
				code: AlphaTexDiagnosticCode.AT220,
				message: `Error parsing arguments: unexpected additional arguments. Signatures:\n${AlphaTex1MetaDataReader.generateSignatures(signatures)}`,
				severity: AlphaTexDiagnosticsSeverity.Error,
				start: unexpectedValuesStart,
				end: parser.lexer.previousTokenEndLocation()
			});
		}
		static _hasExactMatch(candidates) {
			for (const v of candidates.values()) if (v.parameterIndex === v.signature.parameters.length) return true;
			return false;
		}
		static filterIncompleteCandidates(candidates) {
			const toRemove = /* @__PURE__ */ new Set();
			for (const [k, v] of candidates) for (let i = v.parameterIndex; i < v.signature.parameters.length; i++) switch (v.signature.parameters[i].parseMode) {
				case ArgumentListParseTypesMode.Required:
				case ArgumentListParseTypesMode.RequiredAsFloat:
					toRemove.add(k);
					break;
			}
			for (const v of toRemove) candidates.delete(v);
		}
		static generateSignaturesFromArguments(args) {
			if (!args) return "()";
			return `(${args.map((v) => AlphaTexNodeType[v.nodeType]).join(", ")})`;
		}
		static generateSignatures(signatures, ambiguousOverloads) {
			if (signatures.length === 0) return "()";
			return signatures.map((v, i) => AlphaTex1MetaDataReader._generateSignature(v, ambiguousOverloads !== void 0 && ambiguousOverloads.size > 1 && ambiguousOverloads.has(i))).join("\n");
		}
		static _generateSignature(signature, isAmbiguous) {
			const suffix = isAmbiguous ? " ~" : "";
			return `(${signature.parameters.map(AlphaTex1MetaDataReader._generateSignatureParameter).join(", ")})${suffix}`;
		}
		static _generateSignatureParameter(parameter, index) {
			const typeArray = Array.from(parameter.expectedTypes);
			let p = `v${index}`;
			switch (parameter.parseMode) {
				case ArgumentListParseTypesMode.Optional:
				case ArgumentListParseTypesMode.OptionalAsFloat:
					p += "?";
					break;
			}
			if (parameter.allowedValues && parameter.allowedValues.size < 5) {
				const valueArray = Array.from(parameter.allowedValues);
				switch (typeArray[0]) {
					case AlphaTexNodeType.String:
						p = valueArray.map((v) => `"${v}"`).join("|");
						break;
					default:
						p = valueArray.join("|");
						break;
				}
			} else p = Array.from(parameter.expectedTypes).map((t) => AlphaTexNodeType[t]).join("|");
			switch (parameter.parseMode) {
				case ArgumentListParseTypesMode.RequiredAsValueList:
				case ArgumentListParseTypesMode.ValueListWithoutParenthesis:
					p += "[]";
					break;
			}
			return p;
		}
		static filterSignatureCandidates(candidates, value, valueCanBeEndOfList, trackValue, extendToFloat) {
			const toRemove = /* @__PURE__ */ new Set();
			let foundMatchingOverload = false;
			for (const [overloadIndex, overload] of candidates) {
				let handled = false;
				while (!handled) {
					const expected = overload.parameterIndex < overload.signature.parameters.length ? overload.signature.parameters[overload.parameterIndex] : void 0;
					if (!expected) {
						if (!valueCanBeEndOfList) toRemove.add(overloadIndex);
						handled = true;
					} else if (overload.signature.isStrict && overload.parameterIndex > 0) {
						toRemove.add(overloadIndex);
						handled = true;
					} else if ((expected.expectedTypes.has(value.nodeType) || AlphaTex1MetaDataReader._isValueListMatch(value, expected)) && AlphaTex1MetaDataReader._checkArgumentMatch(value, expected, extendToFloat)) {
						handled = true;
						foundMatchingOverload = true;
						trackValue(value, overloadIndex);
						if (expected.allowedValues) overload.parameterValueMatches++;
						switch (expected.parseMode) {
							case ArgumentListParseTypesMode.ValueListWithoutParenthesis:
								overload.parameterHasValues = true;
								break;
							case ArgumentListParseTypesMode.RequiredAsValueList:
								overload.parameterIndex++;
								overload.parameterHasValues = false;
								break;
							default:
								overload.parameterIndex++;
								overload.parameterHasValues = false;
								break;
						}
					} else switch (expected.parseMode) {
						case ArgumentListParseTypesMode.ValueListWithoutParenthesis:
							overload.parameterIndex++;
							overload.parameterHasValues = false;
							break;
						case ArgumentListParseTypesMode.Required:
						case ArgumentListParseTypesMode.RequiredAsFloat:
							toRemove.add(overloadIndex);
							handled = true;
							break;
						case ArgumentListParseTypesMode.Optional:
						case ArgumentListParseTypesMode.OptionalAsFloat:
							overload.parameterIndex++;
							overload.parameterHasValues = false;
							break;
						case ArgumentListParseTypesMode.RequiredAsValueList:
							overload.parameterIndex++;
							overload.parameterHasValues = false;
							break;
					}
				}
			}
			if (foundMatchingOverload) for (const v of toRemove) candidates.delete(v);
			return foundMatchingOverload;
		}
		static _checkArgumentMatch(value, expected, extendToFloat) {
			switch (value.nodeType) {
				case AlphaTexNodeType.Ident:
					const ident = value;
					if (expected?.allowedValues) return expected.allowedValues.has(ident.text.toLowerCase());
					else if (expected?.reservedIdentifiers) return !expected.reservedIdentifiers.has(ident.text.toLowerCase());
					return true;
				case AlphaTexNodeType.String:
					const str = value;
					if (expected?.allowedValues) return expected.allowedValues.has(str.text.toLowerCase());
					return true;
				case AlphaTexNodeType.Number: switch (expected?.parseMode ?? ArgumentListParseTypesMode.Optional) {
					case ArgumentListParseTypesMode.RequiredAsFloat:
					case ArgumentListParseTypesMode.OptionalAsFloat:
						extendToFloat?.(value);
						return true;
					default: return true;
				}
				case AlphaTexNodeType.LParen: return true;
			}
			return false;
		}
		static _isValueListMatch(value, expected) {
			if (value.nodeType !== AlphaTexNodeType.LParen) return false;
			return expected.expectedTypes.has(AlphaTexNodeType.Arguments) || expected.parseMode === ArgumentListParseTypesMode.ValueListWithoutParenthesis || expected.parseMode === ArgumentListParseTypesMode.RequiredAsValueList;
		}
	};
	//#endregion
	//#region src/importer/alphaTex/IAlphaTexLanguageImportHandler.ts
	/**
	* @internal
	*/
	var ApplyNodeResult = /* @__PURE__ */ function(ApplyNodeResult) {
		ApplyNodeResult[ApplyNodeResult["Applied"] = 0] = "Applied";
		ApplyNodeResult[ApplyNodeResult["NotAppliedSemanticError"] = 1] = "NotAppliedSemanticError";
		ApplyNodeResult[ApplyNodeResult["NotAppliedUnrecognizedMarker"] = 2] = "NotAppliedUnrecognizedMarker";
		return ApplyNodeResult;
	}({});
	/**
	* @internal
	*/
	var ApplyStructuralMetaDataResult = /* @__PURE__ */ function(ApplyStructuralMetaDataResult) {
		ApplyStructuralMetaDataResult[ApplyStructuralMetaDataResult["AppliedNewTrack"] = 0] = "AppliedNewTrack";
		ApplyStructuralMetaDataResult[ApplyStructuralMetaDataResult["AppliedNewStaff"] = 1] = "AppliedNewStaff";
		ApplyStructuralMetaDataResult[ApplyStructuralMetaDataResult["AppliedNewVoice"] = 2] = "AppliedNewVoice";
		ApplyStructuralMetaDataResult[ApplyStructuralMetaDataResult["NotAppliedSemanticError"] = 3] = "NotAppliedSemanticError";
		ApplyStructuralMetaDataResult[ApplyStructuralMetaDataResult["NotAppliedUnrecognizedMarker"] = 4] = "NotAppliedUnrecognizedMarker";
		return ApplyStructuralMetaDataResult;
	}({});
	//#endregion
	//#region src/midi/GeneralMidi.ts
	/**
	* This public class provides names for all general midi instruments.
	* @internal
	*/
	var GeneralMidi = class GeneralMidi {
		static _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]
		]);
		static getValue(name) {
			if (!GeneralMidi._values) GeneralMidi._values = /* @__PURE__ */ new Map();
			name = name.toLowerCase().replaceAll(" ", "");
			return GeneralMidi._values.has(name) ? GeneralMidi._values.get(name) : 0;
		}
		static getName(input) {
			for (const [name, program] of GeneralMidi._values) if (program === input) return name;
			return input.toString();
		}
		static isPiano(program) {
			return program <= 7 || program >= 16 && program <= 23;
		}
		static isGuitar(program) {
			return program >= 24 && program <= 39 || program === 105 || program === 43;
		}
		static isBass(program) {
			return program >= 32 && program <= 39;
		}
		static bankToLsbMsb(bank) {
			return [bank & 127, bank >> 7 & 127];
		}
	};
	//#endregion
	//#region src/model/Chord.ts
	/**
	* A chord definition.
	* @json
	* @json_strict
	* @public
	*/
	var Chord = class {
		/**
		* Gets or sets the name of the chord
		*/
		name = "";
		/**
		* Indicates the first fret of the chord diagram.
		*/
		firstFret = 1;
		/**
		* Gets or sets the frets played on the individual strings for this chord.
		* - The order in this list goes from the highest string to the lowest string.
		* - -1 indicates that the string is not played.
		*/
		strings = [];
		/**
		* Gets or sets a list of frets where the finger should hold a barre
		*/
		barreFrets = [];
		/**
		* Gets or sets the staff the chord belongs to.
		* @json_ignore
		*/
		staff;
		/**
		* Gets or sets whether the chord name is shown above the chord diagram.
		*/
		showName = true;
		/**
		* Gets or sets whether the chord diagram is shown.
		*/
		showDiagram = true;
		/**
		* Gets or sets whether the fingering is shown below the chord diagram.
		*/
		showFingering = true;
		/**
		* Gets a unique id for this chord based on its properties.
		*/
		get uniqueId() {
			return [
				this.name,
				this.firstFret.toString(),
				this.strings.join(","),
				this.barreFrets.join(","),
				this.showDiagram.toString(),
				this.showFingering.toString(),
				this.showName.toString()
			].join("|");
		}
	};
	//#endregion
	//#region src/FormatError.ts
	/**
	* An invalid input format was detected (e.g. invalid setting values, file formats,...)
	* @public
	*/
	var FormatError = class extends AlphaTabError {
		constructor(message) {
			super(AlphaTabErrorType.Format, message);
		}
	};
	//#endregion
	//#region src/model/Color.ts
	/**
	* @json_immutable
	* @public
	*/
	var Color = class Color {
		static BlackRgb = "#000000";
		/**
		* Initializes a new instance of the {@link Color} class.
		* @param r The red component.
		* @param g The green component.
		* @param b The blue component.
		* @param a The alpha component.
		*/
		constructor(r, g, b, a = 255) {
			this.raw = (a & 255) << 24 | (r & 255) << 16 | (g & 255) << 8 | b & 255;
			this.updateRgba();
		}
		updateRgba() {
			if (this.a === 255) this.rgba = `#${ModelUtils.toHexString(this.r, 2)}${ModelUtils.toHexString(this.g, 2)}${ModelUtils.toHexString(this.b, 2)}`;
			else this.rgba = `rgba(${this.r},${this.g},${this.b},${this.a / 255})`;
		}
		/**
		* Gets or sets the raw RGBA value.
		*/
		raw = 0;
		get a() {
			return this.raw >> 24 & 255;
		}
		get r() {
			return this.raw >> 16 & 255;
		}
		get g() {
			return this.raw >> 8 & 255;
		}
		get b() {
			return this.raw & 255;
		}
		/**
		* Gets the RGBA hex string to use in CSS areas.
		*/
		rgba;
		static random(opacity = 100) {
			return new Color(Math.random() * 255 | 0, Math.random() * 255 | 0, Math.random() * 255 | 0, opacity);
		}
		static fromJson(v) {
			if (v instanceof Color) return v;
			switch (typeof v) {
				case "number": {
					const c = new Color(0, 0, 0, 0);
					c.raw = v;
					c.updateRgba();
					return c;
				}
				case "string": {
					const json = v;
					if (json.startsWith("#")) {
						if (json.length === 4) return new Color(Number.parseInt(json[1], 16) * 17, Number.parseInt(json[2], 16) * 17, Number.parseInt(json[3], 16) * 17);
						if (json.length === 5) return new Color(Number.parseInt(json[1], 16) * 17, Number.parseInt(json[2], 16) * 17, Number.parseInt(json[3], 16) * 17, Number.parseInt(json[4], 16) * 17);
						if (json.length === 7) return new Color(Number.parseInt(json.substring(1, 3), 16), Number.parseInt(json.substring(3, 5), 16), Number.parseInt(json.substring(5, 7), 16));
						if (json.length === 9) return new Color(Number.parseInt(json.substring(1, 3), 16), Number.parseInt(json.substring(3, 5), 16), Number.parseInt(json.substring(5, 7), 16), Number.parseInt(json.substring(7, 9), 16));
					} else if (json.startsWith("rgba") || json.startsWith("rgb")) {
						const start = json.indexOf("(");
						const end = json.lastIndexOf(")");
						if (start === -1 || end === -1) throw new FormatError("No values specified for rgb/rgba function");
						const numbers = json.substring(start + 1, end).split(",");
						if (numbers.length === 3) return new Color(Number.parseInt(numbers[0], 10), Number.parseInt(numbers[1], 10), Number.parseInt(numbers[2], 10));
						if (numbers.length === 4) return new Color(Number.parseInt(numbers[0], 10), Number.parseInt(numbers[1], 10), Number.parseInt(numbers[2], 10), Number.parseFloat(numbers[3]) * 255);
					}
					return null;
				}
			}
			throw new FormatError("Unsupported format for color");
		}
		static toJson(obj) {
			return obj === null ? null : obj.raw;
		}
	};
	//#endregion
	//#region src/model/Fermata.ts
	/**
	* Lists all types of fermatas
	* @public
	*/
	var FermataType = /* @__PURE__ */ function(FermataType) {
		/**
		* A short fermata (triangle symbol)
		*/
		FermataType[FermataType["Short"] = 0] = "Short";
		/**
		* A medium fermata (round symbol)
		*/
		FermataType[FermataType["Medium"] = 1] = "Medium";
		/**
		* A long fermata (rectangular symbol)
		*/
		FermataType[FermataType["Long"] = 2] = "Long";
		return FermataType;
	}({});
	/**
	* Represents a fermata.
	* @json
	* @json_strict
	* @public
	*/
	var Fermata = class {
		/**
		* Gets or sets the type of fermata.
		*/
		type = 0;
		/**
		* Gets or sets the actual length of the fermata.
		*/
		length = 0;
	};
	//#endregion
	//#region src/model/Lyrics.ts
	/**
	* Represents the lyrics of a song.
	* @public
	*/
	var Lyrics = class Lyrics {
		static _charCodeLF = 10;
		static _charCodeTab = 9;
		static _charCodeCR = 13;
		static _charCodeSpace = 32;
		static _charCodeBrackedClose = 93;
		static _charCodeBrackedOpen = 91;
		static _charCodeDash = 45;
		/**
		* Gets or sets he start bar on which the lyrics should begin.
		*/
		startBar = 0;
		/**
		* Gets or sets the raw lyrics text in Guitar Pro format.
		* (spaces split word syllables, plus merge syllables, [..] are comments)
		*/
		text = "";
		/**
		* Gets or sets the prepared chunks of the lyrics to apply to beats.
		*/
		chunks;
		finish(skipEmptyEntries = false) {
			this.chunks = [];
			this._parse(this.text, 0, this.chunks, skipEmptyEntries);
		}
		_parse(str, p, _chunks, skipEmptyEntries) {
			if (!str) return;
			let state = 1;
			let next = 1;
			let skipSpace = false;
			let start = 0;
			while (p < str.length) {
				const c = str.charCodeAt(p);
				switch (state) {
					case 0:
						switch (c) {
							case Lyrics._charCodeLF:
							case Lyrics._charCodeCR:
							case Lyrics._charCodeTab: break;
							case Lyrics._charCodeSpace:
								if (!skipSpace) {
									state = next;
									continue;
								}
								break;
							default:
								skipSpace = false;
								state = next;
								continue;
						}
						break;
					case 1:
						switch (c) {
							case Lyrics._charCodeBrackedOpen:
								state = 3;
								break;
							default:
								start = p;
								state = 2;
								continue;
						}
						break;
					case 3:
						switch (c) {
							case Lyrics._charCodeBrackedClose:
								state = 1;
								break;
						}
						break;
					case 2:
						switch (c) {
							case Lyrics._charCodeDash:
								state = 4;
								break;
							case Lyrics._charCodeCR:
							case Lyrics._charCodeLF:
							case Lyrics._charCodeSpace:
								const txt = str.substr(start, p - start);
								this._addChunk(txt, skipEmptyEntries);
								state = 0;
								next = 1;
								break;
						}
						break;
					case 4:
						switch (c) {
							case Lyrics._charCodeDash: break;
							default:
								const txt = str.substr(start, p - start);
								this._addChunk(txt, skipEmptyEntries);
								skipSpace = true;
								state = 0;
								next = 1;
								continue;
						}
						break;
				}
				p += 1;
			}
			if (state === 2) {
				if (p !== start) this._addChunk(str.substr(start, p - start), skipEmptyEntries);
			}
		}
		_addChunk(txt, skipEmptyEntries) {
			txt = this._prepareChunk(txt);
			if (!skipEmptyEntries || txt.length > 0 && txt !== "-") this.chunks.push(txt);
		}
		_prepareChunk(txt) {
			const chunk = txt.split("+").join(" ");
			let endLength = chunk.length;
			while (endLength > 0 && chunk.charAt(endLength - 1) === "_") endLength--;
			return endLength !== chunk.length ? chunk.substr(0, endLength) : chunk;
		}
	};
	//#endregion
	//#region src/model/Section.ts
	/**
	* This public class is used to describe the beginning of a
	* section within a song. It acts like a marker.
	* @json
	* @json_strict
	* @public
	*/
	var Section = class {
		/**
		* Gets or sets the marker ID for this section.
		*/
		marker = "";
		/**
		* Gets or sets the descriptional text of this section.
		*/
		text = "";
	};
	//#endregion
	//#region src/model/Tuning.ts
	/**
	* This public class represents a predefined string tuning.
	* @json
	* @json_strict
	* @public
	*/
	var Tuning = class Tuning {
		static _sevenStrings = [];
		static _sixStrings = [];
		static _fiveStrings = [];
		static _fourStrings = [];
		static _defaultTunings = /* @__PURE__ */ new Map();
		static noteNames = [
			"C",
			"Db",
			"D",
			"Eb",
			"E",
			"F",
			"Gb",
			"G",
			"Ab",
			"A",
			"Bb",
			"B"
		];
		static getTextForTuning(tuning, includeOctave) {
			const parts = Tuning.getTextPartsForTuning(tuning);
			return includeOctave ? parts.join("") : parts[0];
		}
		static getTextPartsForTuning(tuning, octaveShift = -1) {
			const octave = tuning / 12 | 0;
			const note = tuning % 12;
			return [Tuning.noteNames[note], (octave + octaveShift).toString()];
		}
		/**
		* Gets the default tuning for the given string count.
		* @param stringCount The string count.
		* @returns The tuning for the given string count or null if the string count is not defined.
		*/
		static getDefaultTuningFor(stringCount) {
			if (Tuning._defaultTunings.has(stringCount)) {
				const d = Tuning._defaultTunings.get(stringCount);
				return new Tuning(d.name, d.tunings, d.isStandard);
			}
			return null;
		}
		/**
		* Gets a list of all tuning presets for a given stirng count.
		* @param stringCount The string count.
		* @returns The list of known tunings for the given string count or an empty list if the string count is not defined.
		*/
		static getPresetsFor(stringCount) {
			switch (stringCount) {
				case 7: return Tuning._sevenStrings;
				case 6: return Tuning._sixStrings;
				case 5: return Tuning._fiveStrings;
				case 4: return Tuning._fourStrings;
			}
			return [];
		}
		static initialize() {
			Tuning._defaultTunings.set(7, new Tuning("Guitar 7 strings", [
				64,
				59,
				55,
				50,
				45,
				40,
				35
			], true));
			Tuning._sevenStrings.push(Tuning._defaultTunings.get(7));
			Tuning._defaultTunings.set(6, new Tuning("Guitar Standard Tuning", [
				64,
				59,
				55,
				50,
				45,
				40
			], true));
			Tuning._sixStrings.push(Tuning._defaultTunings.get(6));
			Tuning._sixStrings.push(new Tuning("Guitar Tune down ½ step", [
				63,
				58,
				54,
				49,
				44,
				39
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Tune down 1 step", [
				62,
				57,
				53,
				48,
				43,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Tune down 2 step", [
				60,
				55,
				51,
				46,
				41,
				36
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Dropped D Tuning", [
				64,
				59,
				55,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Dropped D Tuning variant", [
				64,
				57,
				55,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Double Dropped D Tuning", [
				62,
				59,
				55,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Dropped E Tuning", [
				66,
				61,
				57,
				52,
				47,
				40
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Dropped C Tuning", [
				62,
				57,
				53,
				48,
				43,
				36
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open C Tuning", [
				64,
				60,
				55,
				48,
				43,
				36
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Cm Tuning", [
				63,
				60,
				55,
				48,
				43,
				36
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open C6 Tuning", [
				64,
				57,
				55,
				48,
				43,
				36
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Cmaj7 Tuning", [
				64,
				59,
				55,
				52,
				43,
				36
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open D Tuning", [
				62,
				57,
				54,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Dm Tuning", [
				62,
				57,
				53,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open D5 Tuning", [
				62,
				57,
				50,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open D6 Tuning", [
				62,
				59,
				54,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Dsus4 Tuning", [
				62,
				57,
				55,
				50,
				45,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open E Tuning", [
				64,
				59,
				56,
				52,
				47,
				40
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Em Tuning", [
				64,
				59,
				55,
				52,
				47,
				40
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Esus11 Tuning", [
				64,
				59,
				55,
				52,
				45,
				40
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open F Tuning", [
				65,
				60,
				53,
				48,
				45,
				41
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open G Tuning", [
				62,
				59,
				55,
				50,
				43,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Gm Tuning", [
				62,
				58,
				55,
				50,
				43,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open G6 Tuning", [
				64,
				59,
				55,
				50,
				43,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Gsus4 Tuning", [
				62,
				60,
				55,
				50,
				43,
				38
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open A Tuning", [
				64,
				61,
				57,
				52,
				45,
				40
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Open Am Tuning", [
				64,
				60,
				57,
				52,
				45,
				40
			], false));
			Tuning._sixStrings.push(new Tuning("Guitar Nashville Tuning", [
				64,
				59,
				67,
				62,
				57,
				52
			], false));
			Tuning._sixStrings.push(new Tuning("Bass 6 Strings Tuning", [
				48,
				43,
				38,
				33,
				28,
				23
			], false));
			Tuning._sixStrings.push(new Tuning("Lute or Vihuela Tuning", [
				64,
				59,
				54,
				50,
				45,
				40
			], false));
			Tuning._defaultTunings.set(5, new Tuning("Bass 5 Strings Tuning", [
				43,
				38,
				33,
				28,
				23
			], true));
			Tuning._fiveStrings.push(Tuning._defaultTunings.get(5));
			Tuning._fiveStrings.push(new Tuning("Banjo Dropped C Tuning", [
				62,
				59,
				55,
				48,
				67
			], false));
			Tuning._fiveStrings.push(new Tuning("Banjo Open D Tuning", [
				62,
				57,
				54,
				50,
				69
			], false));
			Tuning._fiveStrings.push(new Tuning("Banjo Open G Tuning", [
				62,
				59,
				55,
				50,
				67
			], false));
			Tuning._fiveStrings.push(new Tuning("Banjo G Minor Tuning", [
				62,
				58,
				55,
				50,
				67
			], false));
			Tuning._fiveStrings.push(new Tuning("Banjo G Modal Tuning", [
				62,
				57,
				55,
				50,
				67
			], false));
			Tuning._defaultTunings.set(4, new Tuning("Bass Standard Tuning", [
				43,
				38,
				33,
				28
			], true));
			Tuning._fourStrings.push(Tuning._defaultTunings.get(4));
			Tuning._fourStrings.push(new Tuning("Bass Tune down ½ step", [
				42,
				37,
				32,
				27
			], false));
			Tuning._fourStrings.push(new Tuning("Bass Tune down 1 step", [
				41,
				36,
				31,
				26
			], false));
			Tuning._fourStrings.push(new Tuning("Bass Tune down 2 step", [
				39,
				34,
				29,
				24
			], false));
			Tuning._fourStrings.push(new Tuning("Bass Dropped D Tuning", [
				43,
				38,
				33,
				26
			], false));
			Tuning._fourStrings.push(new Tuning("Ukulele C Tuning", [
				45,
				40,
				36,
				43
			], false));
			Tuning._fourStrings.push(new Tuning("Ukulele G Tuning", [
				52,
				47,
				43,
				38
			], false));
			Tuning._fourStrings.push(new Tuning("Mandolin Standard Tuning", [
				64,
				57,
				50,
				43
			], false));
			Tuning._fourStrings.push(new Tuning("Mandolin or Violin Tuning", [
				76,
				69,
				62,
				55
			], false));
			Tuning._fourStrings.push(new Tuning("Viola Tuning", [
				69,
				62,
				55,
				48
			], false));
			Tuning._fourStrings.push(new Tuning("Cello Tuning", [
				57,
				50,
				43,
				36
			], false));
		}
		/**
		* Tries to find a known tuning by a given list of tuning values.
		* @param strings The values defining the tuning.
		* @returns The known tuning.
		*/
		static findTuning(strings) {
			const tunings = Tuning.getPresetsFor(strings.length);
			for (let t = 0, tc = tunings.length; t < tc; t++) {
				const tuning = tunings[t];
				let equals = true;
				for (let i = 0, j = strings.length; i < j; i++) if (strings[i] !== tuning.tunings[i]) {
					equals = false;
					break;
				}
				if (equals) return new Tuning(tuning.name, tuning.tunings, tuning.isStandard);
			}
			return null;
		}
		/**
		* Gets or sets whether this is the standard tuning for this number of strings.
		*/
		isStandard;
		/**
		* Gets or sets the name of the tuning.
		*/
		name;
		/**
		* Gets or sets the values for each string of the instrument.
		*/
		tunings;
		/**
		* Initializes a new instance of the {@link Tuning} class.
		* @param name The name.
		* @param tuning The tuning.
		* @param isStandard if set to`true`[is standard].
		*/
		constructor(name = "", tuning = null, isStandard = false) {
			this.isStandard = isStandard;
			this.name = name;
			this.tunings = tuning ?? [];
		}
		reset() {
			this.isStandard = false;
			this.name = "";
			this.tunings = [];
		}
		/**
		* Tries to detect the name and standard flag of the tuning from a known tuning list based
		* on the string values.
		*/
		finish() {
			const knownTuning = Tuning.findTuning(this.tunings);
			if (knownTuning) {
				if (this.name.length === 0) this.name = knownTuning.name;
				this.isStandard = knownTuning.isStandard;
			}
		}
	};
	Tuning.initialize();
	//#endregion
	//#region src/model/Staff.ts
	/**
	* This class describes a single staff within a track. There are instruments like pianos
	* where a single track can contain multiple staves.
	* @json
	* @json_strict
	* @public
	*/
	var Staff = class Staff {
		static DefaultStandardNotationLineCount = 5;
		/**
		* Gets or sets the zero-based index of this staff within the track.
		* @json_ignore
		*/
		index = 0;
		/**
		* Gets or sets the reference to the track this staff belongs to.
		* @json_ignore
		*/
		track;
		/**
		* Gets or sets a list of all bars contained in this staff.
		* @json_add addBar
		*/
		bars = [];
		/**
		* Gets or sets a list of all chords defined for this staff. {@link Beat.chordId} refers to entries in this lookup.
		* @json_add addChord
		*/
		chords = null;
		/**
		* Gets or sets the fret on which a capo is set.
		*/
		capo = 0;
		/**
		* Gets or sets the number of semitones this track should be
		* transposed. This applies to rendering and playback.
		*/
		transpositionPitch = 0;
		/**
		* Gets or sets the number of semitones this track should be
		* transposed. This applies only to rendering.
		*/
		displayTranspositionPitch = 0;
		/**
		* Get or set the guitar tuning of the guitar. This tuning also indicates the number of strings shown in the
		* guitar tablature. Unlike the {@link Note.string} property this array directly represents
		* the order of the tracks shown in the tablature. The first item is the most top tablature line.
		*/
		stringTuning = new Tuning("", [], false);
		/**
		* Get or set the values of the related guitar tuning.
		*/
		get tuning() {
			return this.stringTuning.tunings;
		}
		/**
		* Gets or sets the name of the tuning.
		*/
		get tuningName() {
			return this.stringTuning.name;
		}
		get isStringed() {
			return this.stringTuning.tunings.length > 0;
		}
		/**
		* Gets or sets whether the slash notation is shown.
		*/
		showSlash = false;
		/**
		* Gets or sets whether the numbered notation is shown.
		*/
		showNumbered = false;
		/**
		* Gets or sets whether the tabs are shown.
		*/
		showTablature = true;
		/**
		* Gets or sets whether the standard notation is shown.
		*/
		showStandardNotation = true;
		/**
		* Gets or sets whether the staff contains percussion notation
		*/
		isPercussion = false;
		/**
		* The number of lines shown for the standard notation.
		* For some percussion instruments this number might vary.
		*/
		standardNotationLineCount = Staff.DefaultStandardNotationLineCount;
		_filledVoices = new Set([0]);
		/**
		* The indexes of the non-empty voices in this staff..
		* @json_ignore
		*/
		get filledVoices() {
			return this._filledVoices;
		}
		finish(settings, sharedDataBag = null) {
			if (this.isPercussion) {
				this.stringTuning.tunings = [];
				this.showTablature = false;
				this.displayTranspositionPitch = 0;
			}
			this.stringTuning.finish();
			if (this.stringTuning.tunings.length === 0) this.showTablature = false;
			for (let i = 0, j = this.bars.length; i < j; i++) {
				this.bars[i].finish(settings, sharedDataBag);
				for (const v of this.bars[i].filledVoices) this._filledVoices.add(v);
			}
		}
		addChord(chordId, chord) {
			chord.staff = this;
			let chordMap = this.chords;
			if (chordMap === null) {
				chordMap = /* @__PURE__ */ new Map();
				this.chords = chordMap;
			}
			chordMap.set(chordId, chord);
		}
		hasChord(chordId) {
			return this.chords?.has(chordId) ?? false;
		}
		getChord(chordId) {
			return this.chords?.get(chordId) ?? null;
		}
		addBar(bar) {
			const bars = this.bars;
			bar.staff = this;
			bar.index = bars.length;
			if (bars.length > 0) {
				bar.previousBar = bars[bars.length - 1];
				bar.previousBar.nextBar = bar;
			}
			bars.push(bar);
		}
	};
	//#endregion
	//#region src/model/PlaybackInformation.ts
	/**
	* This public class stores the midi specific information of a track needed
	* for playback.
	* @json
	* @json_strict
	* @public
	*/
	var PlaybackInformation = class {
		/**
		* Gets or sets the volume (0-16)
		*/
		volume = 15;
		/**
		* Gets or sets the balance (0-16; 8=center)
		*/
		balance = 8;
		/**
		* Gets or sets the midi port to use.
		*/
		port = 1;
		/**
		* Gets or sets the midi program to use.
		*/
		program = 0;
		/**
		* The midi bank to use. 
		*/
		bank = 0;
		/**
		* Gets or sets the primary channel for all normal midi events.
		*/
		primaryChannel = 0;
		/**
		* Gets or sets the secondary channel for special midi events.
		*/
		secondaryChannel = 0;
		/**
		* Gets or sets whether the track is muted.
		*/
		isMute = false;
		/**
		* Gets or sets whether the track is playing alone.
		*/
		isSolo = false;
	};
	//#endregion
	//#region src/model/Track.ts
	/**
	* Lists all graphical sub elements within a {@link Track} which can be styled via {@link Track.style}
	* @public
	*/
	var TrackSubElement = /* @__PURE__ */ function(TrackSubElement) {
		/**
		* The track names shown before the staves.
		*/
		TrackSubElement[TrackSubElement["TrackName"] = 0] = "TrackName";
		/**
		* The braces and brackets grouping the staves.
		* If a bracket spans multiple tracks, the color of the first track counts.
		*/
		TrackSubElement[TrackSubElement["BracesAndBrackets"] = 1] = "BracesAndBrackets";
		/**
		* The system separator.
		*/
		TrackSubElement[TrackSubElement["SystemSeparator"] = 2] = "SystemSeparator";
		/**
		* The tuning of the strings.
		*/
		TrackSubElement[TrackSubElement["StringTuning"] = 3] = "StringTuning";
		return TrackSubElement;
	}({});
	/**
	* Defines the custom styles for tracks.
	* @json
	* @json_strict
	* @public
	*/
	var TrackStyle = class extends ElementStyle {};
	/**
	* This public class describes a single track or instrument of score.
	* It is primarily a list of staves containing individual music notation kinds.
	* @json
	* @json_strict
	* @public
	*/
	var Track = class Track {
		static _shortNameMaxLength = 10;
		/**
		* Gets or sets the zero-based index of this track.
		* @json_ignore
		*/
		index = 0;
		/**
		* Gets or sets the reference this track belongs to.
		* @json_ignore
		*/
		score;
		/**
		* Gets or sets the list of staves that are defined for this track.
		* @json_add addStaff
		*/
		staves = [];
		/**
		* Gets or sets the playback information for this track.
		*/
		playbackInfo = new PlaybackInformation();
		/**
		* Gets or sets the display color defined for this track.
		*/
		color = new Color(200, 0, 0, 255);
		/**
		* Gets or sets the long name of this track.
		*/
		name = "";
		/**
		* Gets or sets whether this track should be visible in the UI.
		* This information is purely informational and might not be provided by all input formats.
		* In formats like Guitar Pro this flag indicates whether on the default "multi-track" layout
		* tracks should be visible or not.
		*/
		isVisibleOnMultiTrack = true;
		/**
		* Gets or sets the short name of this track.
		*/
		shortName = "";
		/**
		* Defines how many bars are placed into the systems (rows) when displaying
		* the track unless a value is set in the systemsLayout.
		*/
		defaultSystemsLayout = 3;
		/**
		* Defines how many bars are placed into the systems (rows) when displaying
		* the track.
		*/
		systemsLayout = [];
		/**
		* Defines on which bars specifically a line break is forced.
		* @json_add addLineBreaks
		*/
		lineBreaks;
		/**
		* Gets whether this track is a percussion track.
		*/
		get isPercussion() {
			return this.staves.some((s) => s.isPercussion);
		}
		/**
		* Adds a new line break.
		* @param index  The index of the bar before which a line break should happen.
		*/
		addLineBreaks(index) {
			if (!this.lineBreaks) this.lineBreaks = /* @__PURE__ */ new Set();
			this.lineBreaks.add(index);
		}
		/**
		* Gets or sets a mapping on which staff lines particular percussion instruments
		* should be shown.
		*/
		percussionArticulations = [];
		/**
		* The style customizations for this item.
		*/
		style;
		ensureStaveCount(staveCount) {
			while (this.staves.length < staveCount) this.addStaff(new Staff());
		}
		addStaff(staff) {
			staff.index = this.staves.length;
			staff.track = this;
			this.staves.push(staff);
		}
		finish(settings, sharedDataBag = null) {
			if (!this.shortName) {
				this.shortName = this.name;
				if (this.shortName.length > Track._shortNameMaxLength) this.shortName = this.shortName.substr(0, Track._shortNameMaxLength);
			}
			for (const s of this.staves) {
				s.finish(settings, sharedDataBag);
				if (s.isPercussion) this.playbackInfo.program = 0;
			}
		}
		applyLyrics(lyrics) {
			for (const lyric of lyrics) lyric.finish();
			const staff = this.staves[0];
			for (let li = 0; li < lyrics.length; li++) {
				const lyric = lyrics[li];
				if (lyric.startBar >= 0 && lyric.startBar < staff.bars.length) {
					let beat = staff.bars[lyric.startBar].voices[0].beats[0];
					for (let ci = 0; ci < lyric.chunks.length && beat; ci++) {
						while (beat && (beat.isEmpty || beat.isRest)) beat = beat.nextBeat;
						if (beat) {
							if (!beat.lyrics) {
								beat.lyrics = new Array(lyrics.length);
								beat.lyrics.fill("");
							}
							beat.lyrics[li] = lyric.chunks[ci];
							beat = beat.nextBeat;
						}
					}
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/utils/BeamDirection.ts
	/**
	* @public
	*/
	var BeamDirection = /* @__PURE__ */ function(BeamDirection) {
		BeamDirection[BeamDirection["Up"] = 0] = "Up";
		BeamDirection[BeamDirection["Down"] = 1] = "Down";
		return BeamDirection;
	}({});
	//#endregion
	//#region src/importer/alphaTex/AlphaTex1LanguageHandler.ts
	/**
	* @internal
	*/
	var AlphaTex1LanguageHandler = class AlphaTex1LanguageHandler {
		static instance = new AlphaTex1LanguageHandler();
		static _timeSignatureDenominators = new Set([
			1,
			2,
			4,
			8,
			16,
			32,
			64,
			128
		]);
		applyScoreMetaData(importer, score, metaData) {
			const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.scoreMetaDataSignatures], metaData, metaData.tag.tag.text.toLowerCase(), metaData.arguments);
			if (result !== void 0) return result;
			switch (metaData.tag.tag.text.toLowerCase()) {
				case "title":
					score.title = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.Title, metaData);
					return ApplyNodeResult.Applied;
				case "subtitle":
					score.subTitle = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.SubTitle, metaData);
					return ApplyNodeResult.Applied;
				case "artist":
					score.artist = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.Artist, metaData);
					return ApplyNodeResult.Applied;
				case "album":
					score.album = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.Album, metaData);
					return ApplyNodeResult.Applied;
				case "words":
					score.words = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.Words, metaData);
					return ApplyNodeResult.Applied;
				case "music":
					score.music = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.Music, metaData);
					return ApplyNodeResult.Applied;
				case "copyright":
					score.copyright = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.Copyright, metaData);
					return ApplyNodeResult.Applied;
				case "instructions":
					score.instructions = metaData.arguments.arguments[0].text;
					return ApplyNodeResult.Applied;
				case "notices":
					score.notices = metaData.arguments.arguments[0].text;
					return ApplyNodeResult.Applied;
				case "tab":
					score.tab = metaData.arguments.arguments[0].text;
					this._headerFooterStyle(importer, score, ScoreSubElement.Transcriber, metaData);
					return ApplyNodeResult.Applied;
				case "copyright2":
					this._headerFooterStyle(importer, score, ScoreSubElement.CopyrightSecondLine, metaData, 0);
					return ApplyNodeResult.Applied;
				case "wordsandmusic":
					this._headerFooterStyle(importer, score, ScoreSubElement.WordsAndMusic, metaData, 0);
					return ApplyNodeResult.Applied;
				case "defaultsystemslayout":
					score.defaultSystemsLayout = metaData.arguments.arguments[0].value;
					return ApplyNodeResult.Applied;
				case "systemslayout":
					for (const v of metaData.arguments.arguments) score.systemsLayout.push(v.value);
					return ApplyNodeResult.Applied;
				case "hidedynamics":
					score.stylesheet.hideDynamics = true;
					return ApplyNodeResult.Applied;
				case "showdynamics":
					score.stylesheet.hideDynamics = false;
					return ApplyNodeResult.Applied;
				case "extendbarlines":
					score.stylesheet.extendBarLines = true;
					return ApplyNodeResult.Applied;
				case "bracketextendmode":
					const bracketExtendMode = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "bracket extend mode", AlphaTex1EnumMappings.bracketExtendMode);
					if (bracketExtendMode === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.bracketExtendMode = bracketExtendMode;
					return ApplyNodeResult.Applied;
				case "usesystemsignseparator":
					score.stylesheet.useSystemSignSeparator = true;
					return ApplyNodeResult.Applied;
				case "multibarrest":
					score.stylesheet.multiTrackMultiBarRest = true;
					return ApplyNodeResult.Applied;
				case "singletracktracknamepolicy":
					const singleTrackTrackNamePolicy = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "track name policy", AlphaTex1EnumMappings.trackNamePolicy);
					if (singleTrackTrackNamePolicy === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.singleTrackTrackNamePolicy = singleTrackTrackNamePolicy;
					return ApplyNodeResult.Applied;
				case "multitracktracknamepolicy":
					const multiTrackTrackNamePolicy = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "track name policy", AlphaTex1EnumMappings.trackNamePolicy);
					if (multiTrackTrackNamePolicy === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.multiTrackTrackNamePolicy = multiTrackTrackNamePolicy;
					return ApplyNodeResult.Applied;
				case "firstsystemtracknamemode":
					const firstSystemTrackNameMode = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "track name mode", AlphaTex1EnumMappings.trackNameMode);
					if (firstSystemTrackNameMode === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.firstSystemTrackNameMode = firstSystemTrackNameMode;
					return ApplyNodeResult.Applied;
				case "othersystemstracknamemode":
					const otherSystemsTrackNameMode = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "track name mode", AlphaTex1EnumMappings.trackNameMode);
					if (otherSystemsTrackNameMode === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.otherSystemsTrackNameMode = otherSystemsTrackNameMode;
					return ApplyNodeResult.Applied;
				case "firstsystemtracknameorientation":
					const firstSystemTrackNameOrientation = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "track name orientation", AlphaTex1EnumMappings.trackNameOrientation);
					if (firstSystemTrackNameOrientation === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.firstSystemTrackNameOrientation = firstSystemTrackNameOrientation;
					return ApplyNodeResult.Applied;
				case "othersystemstracknameorientation":
					const otherSystemsTrackNameOrientation = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "track name orientation", AlphaTex1EnumMappings.trackNameOrientation);
					if (otherSystemsTrackNameOrientation === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.otherSystemsTrackNameOrientation = otherSystemsTrackNameOrientation;
					return ApplyNodeResult.Applied;
				case "chorddiagramsinscore":
					score.stylesheet.globalDisplayChordDiagramsInScore = metaData.arguments ? AlphaTex1LanguageHandler._booleanLikeValue(metaData.arguments.arguments, 0) : true;
					return ApplyNodeResult.Applied;
				case "hideemptystaves":
					score.stylesheet.hideEmptyStaves = true;
					return ApplyNodeResult.Applied;
				case "hideemptystavesinfirstsystem":
					score.stylesheet.hideEmptyStavesInFirstSystem = true;
					return ApplyNodeResult.Applied;
				case "showsinglestaffbrackets":
					score.stylesheet.showSingleStaffBrackets = true;
					return ApplyNodeResult.Applied;
				case "defaultbarnumberdisplay":
					const barNumberDisplay = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "bar number display", AlphaTex1EnumMappings.barNumberDisplay);
					if (barNumberDisplay === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					score.stylesheet.barNumberDisplay = barNumberDisplay;
					return ApplyNodeResult.Applied;
				default: return ApplyNodeResult.NotAppliedUnrecognizedMarker;
			}
		}
		_checkArgumentTypes(importer, lookupList, parent, tag, args) {
			const lookup = lookupList.find((l) => l.has(tag));
			if (!lookup) return ApplyNodeResult.NotAppliedUnrecognizedMarker;
			const types = lookup.get(tag);
			if (!types) {
				if (args && args.arguments.length > 0) importer.addSemanticDiagnostic({
					code: AlphaTexDiagnosticCode.AT300,
					message: `Expected no arguments, but found some.`,
					start: args.start,
					end: args.end,
					severity: AlphaTexDiagnosticsSeverity.Warning
				});
				return;
			}
			if (!this._validateArgumentTypes(importer, types, parent, args)) return ApplyNodeResult.NotAppliedSemanticError;
		}
		applyStaffMetaData(importer, staff, metaData) {
			const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.staffMetaDataSignatures], metaData, metaData.tag.tag.text.toLowerCase(), metaData.arguments);
			if (result !== void 0) return result;
			switch (metaData.tag.tag.text.toLowerCase()) {
				case "capo":
					staff.capo = metaData.arguments.arguments[0].value;
					return ApplyNodeResult.Applied;
				case "tuning":
					const tuning = [];
					let hideTuning = false;
					let tuningName = "";
					for (let i = 0; i < metaData.arguments.arguments.length; i++) {
						const v = metaData.arguments.arguments[i];
						const text = v.text;
						switch (text) {
							case "piano":
							case "none":
							case "voice":
								importer.applyStaffNoteKind(staff, AlphaTexStaffNoteKind.Pitched);
								i = metaData.arguments.arguments.length;
								break;
							case "hide":
								hideTuning = true;
								importer.addSemanticDiagnostic({
									code: AlphaTexDiagnosticCode.AT305,
									message: `This value should be rather specified via the properties.`,
									start: v.start,
									end: v.end,
									severity: AlphaTexDiagnosticsSeverity.Warning
								});
								break;
							default:
								const t = ModelUtils.parseTuning(text);
								if (t) tuning.push(t.realValue);
								else if (i === metaData.arguments.arguments.length - 1 && tuning.length > 0) {
									tuningName = text;
									importer.addSemanticDiagnostic({
										code: AlphaTexDiagnosticCode.AT305,
										message: `This value should be rather specified via the properties.`,
										start: v.start,
										end: v.end,
										severity: AlphaTexDiagnosticsSeverity.Warning
									});
								} else {
									const tuningLetters = Array.from(ModelUtils.tuningLetters).join(",");
									const accidentalModes = Array.from(ModelUtils.accidentalModeMapping.keys()).join(",");
									importer.addSemanticDiagnostic({
										code: AlphaTexDiagnosticCode.AT209,
										message: `Unexpected tuning value '${text}', expected: <note><accidental><octave> where <note>=oneOf(${tuningLetters}) <accidental>=oneOf(${accidentalModes}), <octave>=number`,
										start: v.start,
										end: v.end,
										severity: AlphaTexDiagnosticsSeverity.Error
									});
								}
								break;
						}
					}
					importer.state.staffHasExplicitTuning.add(staff);
					importer.state.staffTuningApplied.delete(staff);
					staff.stringTuning = new Tuning();
					staff.stringTuning.tunings = tuning;
					staff.stringTuning.name = tuningName;
					this._tuningProperties(importer, staff, staff.stringTuning, metaData);
					if (hideTuning) {
						if (!staff.track.score.stylesheet.perTrackDisplayTuning) staff.track.score.stylesheet.perTrackDisplayTuning = /* @__PURE__ */ new Map();
						staff.track.score.stylesheet.perTrackDisplayTuning.set(staff.track.index, false);
					}
					return ApplyNodeResult.Applied;
				case "instrument":
					importer.state.staffTuningApplied.delete(staff);
					this._readTrackInstrument(importer, staff.track, metaData.arguments);
					return ApplyNodeResult.Applied;
				case "bank":
					staff.track.playbackInfo.bank = metaData.arguments.arguments[0].value;
					return ApplyNodeResult.Applied;
				case "lyrics":
					const lyrics = new Lyrics();
					lyrics.startBar = 0;
					lyrics.text = "";
					if (metaData.arguments.arguments.length === 2) {
						lyrics.startBar = metaData.arguments.arguments[0].value;
						lyrics.text = metaData.arguments.arguments[1].text;
					} else lyrics.text = metaData.arguments.arguments[0].text;
					importer.state.lyrics.get(staff.track.index).push(lyrics);
					return ApplyNodeResult.Applied;
				case "chord":
					const chord = new Chord();
					this._chordProperties(importer, chord, metaData);
					chord.name = metaData.arguments.arguments[0].text;
					for (let i = 1; i < metaData.arguments.arguments.length; i++) {
						const v = metaData.arguments.arguments[i];
						if (v.nodeType === AlphaTexNodeType.Number) chord.strings.push(v.value);
						else if (v.nodeType === AlphaTexNodeType.Ident) {
							const txt = v.text;
							if (txt === "x") chord.strings.push(-1);
							else importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT209,
								message: `Unexpected chord value '${txt}', expected: 'x'`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: v.start,
								end: v.end
							});
						}
					}
					staff.addChord(AlphaTex1LanguageHandler._getChordId(staff, chord.name), chord);
					return ApplyNodeResult.Applied;
				case "articulation":
					const percussionArticulationNames = importer.state.percussionArticulationNames;
					const articulationName = metaData.arguments.arguments[0].text;
					if (articulationName === "defaults") {
						for (const [defaultName, defaultValue] of PercussionMapper.instrumentArticulationNames) {
							percussionArticulationNames.set(defaultName.toLowerCase(), defaultValue);
							percussionArticulationNames.set(ModelUtils.toArticulationId(defaultName), defaultValue);
						}
						return ApplyNodeResult.Applied;
					}
					if (metaData.arguments.arguments.length === 2) {
						const number = metaData.arguments.arguments[1].value;
						const articulation = PercussionMapper.getArticulationById(number);
						if (articulation) {
							percussionArticulationNames.set(articulationName.toLowerCase(), articulation.uniqueId);
							return ApplyNodeResult.Applied;
						} else {
							const articulations = Array.from(PercussionMapper.instrumentArticulationIds()).map((n) => `${n}`).join(",");
							importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT209,
								message: `Unexpected articulation value '${number}', expected: ${articulations}`,
								start: metaData.arguments.arguments[1].start,
								end: metaData.arguments.arguments[1].end,
								severity: AlphaTexDiagnosticsSeverity.Error
							});
							return ApplyNodeResult.NotAppliedSemanticError;
						}
					}
					return ApplyNodeResult.Applied;
				case "accidentals": return AlphaTex1LanguageHandler._handleAccidentalMode(importer, metaData.arguments);
				case "displaytranspose":
					staff.displayTranspositionPitch = metaData.arguments.arguments[0].value * -1;
					importer.state.staffHasExplicitDisplayTransposition.add(staff);
					return ApplyNodeResult.Applied;
				case "transpose":
					staff.transpositionPitch = metaData.arguments.arguments[0].value * -1;
					return ApplyNodeResult.Applied;
				default: return ApplyNodeResult.NotAppliedUnrecognizedMarker;
			}
		}
		applyBarMetaData(importer, bar, metaData) {
			const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.barMetaDataSignatures], metaData, metaData.tag.tag.text.toLowerCase(), metaData.arguments);
			if (result !== void 0) return result;
			switch (metaData.tag.tag.text.toLowerCase()) {
				case "sync":
					const syncPoint = this._buildSyncPoint(metaData);
					importer.state.syncPoints.push(syncPoint);
					return ApplyNodeResult.Applied;
				case "tempo":
					let ti = 0;
					const tempo = metaData.arguments.arguments[ti++].value;
					let tempoLabel = "";
					let isVisible = true;
					let ratioPosition = 0;
					while (ti < metaData.arguments.arguments.length) {
						switch (metaData.arguments.arguments[ti].nodeType) {
							case AlphaTexNodeType.Ident:
							case AlphaTexNodeType.String:
								const txt = metaData.arguments.arguments[ti].text;
								if (txt === "hide") isVisible = false;
								else tempoLabel = txt;
								break;
							case AlphaTexNodeType.Number:
								ratioPosition = metaData.arguments.arguments[ti].value;
								break;
						}
						ti++;
					}
					let tempoAutomation = bar.masterBar.tempoAutomations.find((a) => a.ratioPosition === ratioPosition);
					if (!tempoAutomation) {
						tempoAutomation = new Automation();
						bar.masterBar.tempoAutomations.push(tempoAutomation);
					}
					tempoAutomation.isLinear = false;
					tempoAutomation.type = AutomationType.Tempo;
					tempoAutomation.value = tempo;
					tempoAutomation.text = tempoLabel;
					tempoAutomation.ratioPosition = ratioPosition;
					tempoAutomation.isVisible = isVisible;
					return ApplyNodeResult.Applied;
				case "rc":
					bar.masterBar.repeatCount = metaData.arguments.arguments[0].value;
					return ApplyNodeResult.Applied;
				case "ae":
					for (const e of metaData.arguments.arguments) if (e.nodeType === AlphaTexNodeType.Number) {
						const num = e.value;
						if (num < 1 || num > 31) {
							importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT211,
								message: `Value is out of valid range. Allowed range: %s, Actual Value: %s`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: e.start,
								end: e.end
							});
							return ApplyNodeResult.NotAppliedSemanticError;
						} else bar.masterBar.alternateEndings |= 1 << num - 1;
					} else importer.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT202,
						message: `Unexpected '${AlphaTexNodeType[e.nodeType]}' token. Expected one of following: ${AlphaTexNodeType[AlphaTexNodeType.Number]}`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: e.start,
						end: e.end
					});
					return ApplyNodeResult.Applied;
				case "ts":
					switch (metaData.arguments.arguments[0].nodeType) {
						case AlphaTexNodeType.Number:
							bar.masterBar.timeSignatureNumerator = metaData.arguments.arguments[0].value | 0;
							if (bar.masterBar.timeSignatureNumerator < 1 || bar.masterBar.timeSignatureNumerator > 32) importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT211,
								message: `Value is out of valid range. Allowed range: 1-32, Actual Value: ${bar.masterBar.timeSignatureNumerator}`,
								start: metaData.arguments.arguments[0].start,
								end: metaData.arguments.arguments[0].end,
								severity: AlphaTexDiagnosticsSeverity.Error
							});
							bar.masterBar.timeSignatureDenominator = metaData.arguments.arguments[1].value | 0;
							if (!AlphaTex1LanguageHandler._timeSignatureDenominators.has(bar.masterBar.timeSignatureDenominator)) {
								const valueList = Array.from(AlphaTex1LanguageHandler._timeSignatureDenominators).join(", ");
								importer.addSemanticDiagnostic({
									code: AlphaTexDiagnosticCode.AT211,
									message: `Value is out of valid range. Allowed range: ${valueList}, Actual Value: ${bar.masterBar.timeSignatureDenominator}`,
									start: metaData.arguments.arguments[0].start,
									end: metaData.arguments.arguments[0].end,
									severity: AlphaTexDiagnosticsSeverity.Error
								});
							}
							break;
						case AlphaTexNodeType.Ident:
						case AlphaTexNodeType.String:
							const tsValue = metaData.arguments.arguments[0].text;
							if (tsValue.toLowerCase() === "common") {
								bar.masterBar.timeSignatureCommon = true;
								bar.masterBar.timeSignatureNumerator = 4;
								bar.masterBar.timeSignatureDenominator = 4;
							} else {
								importer.addSemanticDiagnostic({
									code: AlphaTexDiagnosticCode.AT209,
									message: `Unexpected time signature value '${tsValue}', expected: common or two numbers`,
									severity: AlphaTexDiagnosticsSeverity.Error,
									start: metaData.arguments.arguments[0].start,
									end: metaData.arguments.arguments[0].end
								});
								return ApplyNodeResult.NotAppliedSemanticError;
							}
							break;
					}
					return ApplyNodeResult.Applied;
				case "beaming": return this._parseBeamingRule(importer, metaData, bar.masterBar);
				case "ks":
					const keySignature = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "key signature", AlphaTex1EnumMappings.keySignature);
					if (keySignature === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					const keySignatureType = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "key signature type", AlphaTex1EnumMappings.keySignatureType);
					if (keySignatureType === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					bar.keySignature = keySignature;
					bar.keySignatureType = keySignatureType;
					return ApplyNodeResult.Applied;
				case "clef":
					switch (metaData.arguments.arguments[0].nodeType) {
						case AlphaTexNodeType.Ident:
						case AlphaTexNodeType.String:
							const clef = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "clef", AlphaTex1EnumMappings.clef);
							if (clef === void 0) return ApplyNodeResult.NotAppliedSemanticError;
							bar.clef = clef;
							break;
						case AlphaTexNodeType.Number:
							const clefValue = metaData.arguments.arguments[0].value;
							switch (clefValue) {
								case 0:
									bar.clef = Clef.Neutral;
									break;
								case 43:
									bar.clef = Clef.G2;
									break;
								case 65:
									bar.clef = Clef.F4;
									break;
								case 48:
									bar.clef = Clef.C3;
									break;
								case 60:
									bar.clef = Clef.C4;
									break;
								default:
									importer.addSemanticDiagnostic({
										code: AlphaTexDiagnosticCode.AT209,
										message: `Unexpected clef value '${clefValue}', expected: ${Array.from(AlphaTex1EnumMappings.clef.keys()).join(",")}`,
										severity: AlphaTexDiagnosticsSeverity.Error,
										start: metaData.arguments.arguments[0].start,
										end: metaData.arguments.arguments[0].end
									});
									return ApplyNodeResult.NotAppliedSemanticError;
							}
							break;
					}
					return ApplyNodeResult.Applied;
				case "section":
					const section = new Section();
					if (metaData.arguments.arguments.length === 1) section.text = metaData.arguments.arguments[0].text;
					else {
						section.marker = metaData.arguments.arguments[0].text;
						section.text = metaData.arguments.arguments[1].text;
					}
					bar.masterBar.section = section;
					return ApplyNodeResult.Applied;
				case "tf":
					switch (metaData.arguments.arguments[0].nodeType) {
						case AlphaTexNodeType.Ident:
						case AlphaTexNodeType.String:
							const tripletFeel = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "triplet feel", AlphaTex1EnumMappings.tripletFeel);
							if (tripletFeel === void 0) return ApplyNodeResult.NotAppliedSemanticError;
							bar.masterBar.tripletFeel = tripletFeel;
							break;
						case AlphaTexNodeType.Number:
							const tripletFeelValue = metaData.arguments.arguments[0].value;
							switch (tripletFeelValue) {
								case 0:
									bar.masterBar.tripletFeel = TripletFeel.NoTripletFeel;
									break;
								case 1:
									bar.masterBar.tripletFeel = TripletFeel.Triplet16th;
									break;
								case 2:
									bar.masterBar.tripletFeel = TripletFeel.Triplet8th;
									break;
								case 3:
									bar.masterBar.tripletFeel = TripletFeel.Dotted16th;
									break;
								case 4:
									bar.masterBar.tripletFeel = TripletFeel.Dotted8th;
									break;
								case 5:
									bar.masterBar.tripletFeel = TripletFeel.Scottish16th;
									break;
								case 6:
									bar.masterBar.tripletFeel = TripletFeel.Scottish8th;
									break;
								default:
									importer.addSemanticDiagnostic({
										code: AlphaTexDiagnosticCode.AT209,
										message: `Unexpected triplet feel value '${tripletFeelValue}', expected: ${Array.from(AlphaTex1EnumMappings.tripletFeel.keys()).join(",")}`,
										severity: AlphaTexDiagnosticsSeverity.Error,
										start: metaData.arguments.arguments[0].start,
										end: metaData.arguments.arguments[0].end
									});
									return ApplyNodeResult.NotAppliedSemanticError;
							}
							break;
					}
					return ApplyNodeResult.Applied;
				case "barlineleft":
					const barLineLeft = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "bar line", AlphaTex1EnumMappings.barLineStyle);
					if (barLineLeft === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					bar.barLineLeft = barLineLeft;
					return ApplyNodeResult.Applied;
				case "barlineright":
					const barLineRight = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "bar line", AlphaTex1EnumMappings.barLineStyle);
					if (barLineRight === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					bar.barLineRight = barLineRight;
					return ApplyNodeResult.Applied;
				case "accidentals": return AlphaTex1LanguageHandler._handleAccidentalMode(importer, metaData.arguments);
				case "voicemode": return AlphaTex1LanguageHandler._handleVoiceMode(importer, metaData.arguments);
				case "jump":
					const direction = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "direction", AlphaTex1EnumMappings.direction);
					if (direction === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					bar.masterBar.addDirection(direction);
					return ApplyNodeResult.Applied;
				case "ottava":
					const ottava = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "clef ottava", AlphaTex1EnumMappings.ottavia);
					if (ottava === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					bar.clefOttava = ottava;
					return ApplyNodeResult.Applied;
				case "simile":
					const simile = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "simile mark", AlphaTex1EnumMappings.simileMark);
					if (simile === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					bar.simileMark = simile;
					return ApplyNodeResult.Applied;
				case "width":
					bar.masterBar.displayWidth = metaData.arguments.arguments[0].value;
					bar.displayWidth = bar.masterBar.displayWidth;
					return ApplyNodeResult.Applied;
				case "scale":
					bar.masterBar.displayScale = metaData.arguments.arguments[0].value;
					bar.displayScale = bar.masterBar.displayScale;
					return ApplyNodeResult.Applied;
				case "spd":
					const sustainPedalDown = new SustainPedalMarker();
					sustainPedalDown.pedalType = SustainPedalMarkerType.Down;
					sustainPedalDown.ratioPosition = metaData.arguments.arguments[0].value;
					bar.sustainPedals.push(sustainPedalDown);
					return ApplyNodeResult.Applied;
				case "spu":
					const sustainPedalUp = new SustainPedalMarker();
					sustainPedalUp.pedalType = SustainPedalMarkerType.Up;
					sustainPedalUp.ratioPosition = metaData.arguments.arguments[0].value;
					bar.sustainPedals.push(sustainPedalUp);
					return ApplyNodeResult.Applied;
				case "sph":
					const sustainPedalHold = new SustainPedalMarker();
					sustainPedalHold.pedalType = SustainPedalMarkerType.Hold;
					sustainPedalHold.ratioPosition = metaData.arguments.arguments[0].value;
					bar.sustainPedals.push(sustainPedalHold);
					return ApplyNodeResult.Applied;
				case "ft":
					bar.masterBar.isFreeTime = true;
					return ApplyNodeResult.Applied;
				case "ro":
					bar.masterBar.isRepeatStart = true;
					return ApplyNodeResult.Applied;
				case "ac":
					bar.masterBar.isAnacrusis = true;
					return ApplyNodeResult.Applied;
				case "db":
					bar.masterBar.isDoubleBar = true;
					bar.barLineRight = BarLineStyle.LightLight;
					return ApplyNodeResult.Applied;
				case "barnumberdisplay":
					const barNumberDisplay = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "bar number display", AlphaTex1EnumMappings.barNumberDisplay);
					if (barNumberDisplay === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					bar.barNumberDisplay = barNumberDisplay;
					return ApplyNodeResult.Applied;
				default: return ApplyNodeResult.NotAppliedUnrecognizedMarker;
			}
		}
		_parseBeamingRule(importer, metaData, masterBar) {
			let duration = Duration.Eighth;
			const groupSizes = [];
			const durationValue = metaData.arguments.arguments[0].value;
			switch (durationValue) {
				case 4:
					duration = Duration.QuadrupleWhole;
					break;
				case 8:
					duration = Duration.Eighth;
					break;
				case 16:
					duration = Duration.Sixteenth;
					break;
				case 32:
					duration = Duration.ThirtySecond;
					break;
				default:
					importer.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT209,
						message: `Value is out of valid range. Allowed range: 4,8,16 or 32, Actual Value: ${durationValue}`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: metaData.arguments.arguments[0].start,
						end: metaData.arguments.arguments[0].end
					});
					return ApplyNodeResult.NotAppliedSemanticError;
			}
			for (let i = 1; i < metaData.arguments.arguments.length; i++) {
				if (metaData.arguments.arguments[i].value < 1) {
					importer.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT209,
						message: `Value is out of valid range. Allowed range: >0, Actual Value: ${durationValue}`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: metaData.arguments.arguments[i].start,
						end: metaData.arguments.arguments[i].end
					});
					return ApplyNodeResult.NotAppliedSemanticError;
				}
				groupSizes.push(metaData.arguments.arguments[i].value);
			}
			if (!masterBar.beamingRules) masterBar.beamingRules = new BeamingRules();
			masterBar.beamingRules.groups.set(duration, groupSizes);
			return ApplyNodeResult.Applied;
		}
		static _handleAccidentalMode(importer, args) {
			const accidentalMode = AlphaTex1LanguageHandler._parseEnumValue(importer, args, "accidental mode", AlphaTex1EnumMappings.alphaTexAccidentalMode);
			if (accidentalMode === void 0) return ApplyNodeResult.NotAppliedSemanticError;
			importer.state.accidentalMode = accidentalMode;
			return ApplyNodeResult.Applied;
		}
		static _handleVoiceMode(importer, args) {
			const voiceMode = AlphaTex1LanguageHandler._parseEnumValue(importer, args, "voice mode", AlphaTex1EnumMappings.alphaTexVoiceMode);
			if (voiceMode === void 0) return ApplyNodeResult.NotAppliedSemanticError;
			importer.state.voiceMode = voiceMode;
			return ApplyNodeResult.Applied;
		}
		static _getChordId(currentStaff, chordName) {
			return chordName.toLowerCase() + currentStaff.index + currentStaff.track.index;
		}
		_buildSyncPoint(metaData) {
			const barIndex = metaData.arguments.arguments[0].value;
			const barOccurence = metaData.arguments.arguments[1].value;
			const millisecondOffset = metaData.arguments.arguments[2].value;
			let barPosition = 0;
			if (metaData.arguments.arguments.length > 3) barPosition = metaData.arguments.arguments[3].value;
			return {
				barIndex,
				barOccurence,
				barPosition,
				millisecondOffset
			};
		}
		_validateArgumentTypes(importer, signatures, parent, args) {
			if (!args) {
				if (signatures.some((c) => c.parameters.length === 0 || !c.parameters.some((v) => v.parseMode === ArgumentListParseTypesMode.Required || v.parseMode === ArgumentListParseTypesMode.RequiredAsFloat || v.parseMode === ArgumentListParseTypesMode.RequiredAsValueList))) return true;
				importer.addSemanticDiagnostic({
					code: AlphaTexDiagnosticCode.AT219,
					message: `Error parsing arguments: no overload matched arguments ${AlphaTex1MetaDataReader.generateSignaturesFromArguments(void 0)}. Signatures: ${AlphaTex1MetaDataReader.generateSignatures(signatures)}`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: parent.start,
					end: parent.end
				});
				return false;
			}
			if (args.validated) return true;
			let error = false;
			const candidates = new Map(signatures.map((v, i) => [i, {
				signature: v,
				parameterIndex: 0,
				parameterValueMatches: 0,
				parameterHasValues: false
			}]));
			const parseFull = importer.parseMode === AlphaTexParseMode.Full;
			const trackValue = parseFull ? (value, overloadIndex) => {
				const overload = candidates.get(overloadIndex);
				const valueNode = value;
				if (!valueNode.parameterIndices) valueNode.parameterIndices = /* @__PURE__ */ new Map();
				valueNode.parameterIndices.set(overloadIndex, overload.parameterIndex);
			} : (_value, _overloadIndex) => {};
			for (const value of args.arguments) {
				AlphaTex1MetaDataReader.filterSignatureCandidates(candidates, value, false, trackValue);
				if (candidates.size === 0) break;
			}
			const allCandidates = parseFull ? Array.from(candidates.entries()) : void 0;
			AlphaTex1MetaDataReader.filterIncompleteCandidates(candidates);
			if (candidates.size === 0) {
				importer.addSemanticDiagnostic({
					code: AlphaTexDiagnosticCode.AT219,
					message: `Error parsing arguments: no overload matched arguments ${AlphaTex1MetaDataReader.generateSignaturesFromArguments(args.arguments)}. Signatures:\n${AlphaTex1MetaDataReader.generateSignatures(signatures)}`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: args.start,
					end: args.end
				});
				error = true;
			}
			if (allCandidates) {
				AlphaTex1MetaDataReader.sortCandidates(allCandidates);
				args.signatureCandidateIndices = allCandidates.map((c) => c[0]);
			}
			return !error;
		}
		_headerFooterStyle(importer, score, element, metaData, startIndex = 1) {
			const remaining = metaData.arguments.arguments.length - startIndex;
			if (remaining < 1) return;
			const style = ModelUtils.getOrCreateHeaderFooterStyle(score, element);
			if (style.isVisible === void 0) style.isVisible = true;
			const value = metaData.arguments.arguments[startIndex].text;
			if (value) style.template = value;
			else style.isVisible = false;
			if (remaining < 2) return;
			const textAlign = AlphaTex1LanguageHandler._parseEnumValue(importer, metaData.arguments, "textAlign", AlphaTex1EnumMappings.textAlign, startIndex + 1);
			if (textAlign === void 0) return;
			style.textAlign = textAlign;
		}
		_readTrackInstrument(importer, track, args) {
			switch (args.arguments[0].nodeType) {
				case AlphaTexNodeType.Number:
					const instrument = args.arguments[0].value;
					if (instrument >= 0 && instrument <= 127) track.playbackInfo.program = instrument;
					else importer.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT211,
						message: `Value is out of valid range. Allowed range: 0-127, Actual Value: ${instrument}`,
						start: args.arguments[0].start,
						end: args.arguments[0].end,
						severity: AlphaTexDiagnosticsSeverity.Error
					});
					break;
				case AlphaTexNodeType.Ident:
				case AlphaTexNodeType.String:
					const instrumentName = args.arguments[0].text.toLowerCase();
					if (instrumentName === "percussion") {
						for (const staff of track.staves) importer.applyStaffNoteKind(staff, AlphaTexStaffNoteKind.Articulation);
						track.playbackInfo.primaryChannel = SynthConstants.PercussionChannel;
						track.playbackInfo.secondaryChannel = SynthConstants.PercussionChannel;
					} else track.playbackInfo.program = GeneralMidi.getValue(instrumentName);
					break;
			}
		}
		_chordProperties(importer, chord, metaData) {
			if (!metaData.properties) return;
			for (const p of metaData.properties.properties) {
				if (!this._checkProperty(importer, [AlphaTex1LanguageDefinitions.metaDataProperties.get("chord")], p)) continue;
				switch (p.property.text.toLowerCase()) {
					case "firstfret":
						chord.firstFret = p.arguments.arguments[0].value;
						break;
					case "showdiagram":
						chord.showDiagram = AlphaTex1LanguageHandler._booleanLikeValue(p.arguments.arguments, 0);
						break;
					case "showfingering":
						chord.showFingering = AlphaTex1LanguageHandler._booleanLikeValue(p.arguments.arguments, 0);
						break;
					case "showname":
						chord.showName = AlphaTex1LanguageHandler._booleanLikeValue(p.arguments.arguments, 0);
						break;
					case "barre":
						chord.barreFrets = p.arguments.arguments.map((v) => v.value);
						break;
				}
			}
		}
		_tuningProperties(importer, staff, tuning, metaData) {
			if (!metaData.properties) return;
			for (const p of metaData.properties.properties) {
				if (!this._checkProperty(importer, [AlphaTex1LanguageDefinitions.metaDataProperties.get("tuning")], p)) continue;
				switch (p.property.text.toLowerCase()) {
					case "hide":
						if (!staff.track.score.stylesheet.perTrackDisplayTuning) staff.track.score.stylesheet.perTrackDisplayTuning = /* @__PURE__ */ new Map();
						staff.track.score.stylesheet.perTrackDisplayTuning.set(staff.track.index, false);
						break;
					case "label":
						tuning.name = p.arguments.arguments[0].text;
						break;
				}
			}
		}
		static _booleanLikeValue(args, i) {
			if (i >= args.length) return true;
			const v = args[i];
			switch (v.nodeType) {
				case AlphaTexNodeType.String:
				case AlphaTexNodeType.Ident: return v.text !== "false";
				case AlphaTexNodeType.Number: return v.value !== 0;
				default: return false;
			}
		}
		applyStructuralMetaData(importer, metaData) {
			const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.structuralMetaDataSignatures], metaData, metaData.tag.tag.text.toLowerCase(), metaData.arguments);
			if (result !== void 0) switch (result) {
				case ApplyNodeResult.NotAppliedSemanticError: return ApplyStructuralMetaDataResult.NotAppliedSemanticError;
				case ApplyNodeResult.NotAppliedUnrecognizedMarker: return ApplyStructuralMetaDataResult.NotAppliedUnrecognizedMarker;
			}
			switch (metaData.tag.tag.text.toLowerCase()) {
				case "staff":
					const staff = importer.startNewStaff();
					this._staffProperties(importer, staff, metaData);
					return ApplyStructuralMetaDataResult.AppliedNewStaff;
				case "track":
					const track = importer.startNewTrack();
					if (metaData.arguments && metaData.arguments.arguments.length > 0) {
						track.name = metaData.arguments.arguments[0].text;
						if (metaData.arguments.arguments.length > 1) track.shortName = metaData.arguments.arguments[1].text;
					}
					this._trackProperties(importer, track, metaData);
					return ApplyStructuralMetaDataResult.AppliedNewTrack;
				case "voice":
					importer.startNewVoice();
					return ApplyStructuralMetaDataResult.AppliedNewVoice;
				default: return ApplyStructuralMetaDataResult.NotAppliedUnrecognizedMarker;
			}
		}
		_checkProperty(importer, lookupList, p) {
			const result = this._checkArgumentTypes(importer, lookupList, p, p.property.text.toLowerCase(), p.arguments);
			if (result !== void 0) switch (result) {
				case ApplyNodeResult.Applied:
				case ApplyNodeResult.NotAppliedSemanticError: return false;
				case ApplyNodeResult.NotAppliedUnrecognizedMarker:
					const knownProps = lookupList.flatMap((l) => Array.from(l.keys()));
					importer.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT212,
						message: `Unrecogized property '${p.property.text}', expected one of ${knownProps}`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: p.start,
						end: p.end
					});
					return false;
			}
			return true;
		}
		_staffProperties(importer, staff, metaData) {
			if (!metaData.properties) return;
			let showStandardNotation = false;
			let showTabs = false;
			let showSlash = false;
			let showNumbered = false;
			for (const p of metaData.properties.properties) {
				if (!this._checkProperty(importer, [AlphaTex1LanguageDefinitions.metaDataProperties.get("staff")], p)) continue;
				switch (p.property.text.toLowerCase()) {
					case "score":
						showStandardNotation = true;
						if (p.arguments && p.arguments.arguments.length > 0) staff.standardNotationLineCount = p.arguments.arguments[0].value;
						break;
					case "tabs":
						showTabs = true;
						break;
					case "slash":
						showSlash = true;
						break;
					case "numbered":
						showNumbered = true;
						break;
				}
			}
			if (showStandardNotation || showTabs || showSlash || showNumbered) {
				staff.showStandardNotation = showStandardNotation;
				staff.showTablature = showTabs;
				staff.showSlash = showSlash;
				staff.showNumbered = showNumbered;
			}
		}
		_trackProperties(importer, track, metaData) {
			if (!metaData.properties) return;
			for (const p of metaData.properties.properties) {
				if (!this._checkProperty(importer, [AlphaTex1LanguageDefinitions.metaDataProperties.get("track")], p)) continue;
				switch (p.property.text.toLowerCase()) {
					case "color":
						try {
							track.color = Color.fromJson(p.arguments.arguments[0].text);
						} catch {
							importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT213,
								message: `Invalid format for color`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: p.arguments.arguments[0].start,
								end: p.arguments.arguments[0].end
							});
						}
						break;
					case "defaultsystemslayout":
						track.defaultSystemsLayout = p.arguments.arguments[0].value;
						break;
					case "systemslayout":
						track.systemsLayout = p.arguments.arguments.map((v) => v.value);
						break;
					case "volume":
						track.playbackInfo.volume = p.arguments.arguments[0].value;
						break;
					case "balance":
						track.playbackInfo.balance = p.arguments.arguments[0].value;
						break;
					case "mute":
						track.playbackInfo.isMute = true;
						break;
					case "solo":
						track.playbackInfo.isSolo = true;
						break;
					case "multibarrest":
						if (!track.score.stylesheet.perTrackMultiBarRest) track.score.stylesheet.perTrackMultiBarRest = /* @__PURE__ */ new Set();
						track.score.stylesheet.perTrackMultiBarRest.add(track.index);
						break;
					case "instrument":
						this._readTrackInstrument(importer, track, p.arguments);
						break;
					case "bank":
						track.playbackInfo.bank = p.arguments.arguments[0].value;
						break;
				}
			}
		}
		applyBeatDurationProperty(importer, p) {
			const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.durationChangeProperties], p, p.property.text.toLowerCase(), p.arguments);
			if (result !== void 0) return result;
			switch (p.property.text.toLowerCase()) {
				case "tu":
					if (p.arguments.arguments.length === 2) {
						importer.state.currentTupletNumerator = p.arguments.arguments[0].value;
						importer.state.currentTupletDenominator = p.arguments.arguments[1].value;
					} else {
						const numerator = p.arguments.arguments[0].value;
						importer.state.currentTupletNumerator = numerator;
						const denominator = AlphaTex1LanguageHandler._getTupletDenominator(numerator);
						if (denominator < 0) {
							importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT209,
								message: `Unexpected default tuplet value '${numerator}', expected: 3, 5, 6, 7, 9, 10, 11 or 12`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: p.arguments.arguments[0].start,
								end: p.arguments.arguments[0].end
							});
							importer.state.currentTupletNumerator = -1;
							importer.state.currentTupletDenominator = -1;
						} else importer.state.currentTupletDenominator = denominator;
					}
					return ApplyNodeResult.Applied;
			}
			return ApplyNodeResult.NotAppliedUnrecognizedMarker;
		}
		static _getTupletDenominator(numerator) {
			switch (numerator) {
				case 3: return 2;
				case 5: return 4;
				case 6: return 4;
				case 7: return 4;
				case 9: return 8;
				case 10: return 8;
				case 11: return 8;
				case 12: return 8;
				default: return -1;
			}
		}
		_allKnownBarMetaDataTags = void 0;
		get allKnownMetaDataTags() {
			if (!this._allKnownBarMetaDataTags) {
				this._allKnownBarMetaDataTags = /* @__PURE__ */ new Set();
				const lists = [
					AlphaTex1LanguageDefinitions.scoreMetaDataSignatures.keys(),
					AlphaTex1LanguageDefinitions.structuralMetaDataSignatures.keys(),
					AlphaTex1LanguageDefinitions.staffMetaDataSignatures.keys(),
					AlphaTex1LanguageDefinitions.barMetaDataSignatures.keys()
				];
				for (const l of lists) for (const v of l) this._allKnownBarMetaDataTags.add(v);
			}
			return this._allKnownBarMetaDataTags;
		}
		_knownScoreMetaDataTags = void 0;
		get knownScoreMetaDataTags() {
			if (!this._knownScoreMetaDataTags) this._knownScoreMetaDataTags = new Set(AlphaTex1LanguageDefinitions.scoreMetaDataSignatures.keys());
			return this._knownScoreMetaDataTags;
		}
		_knownStructuralMetaDataTags = void 0;
		get knownStructuralMetaDataTags() {
			if (!this._knownStructuralMetaDataTags) this._knownStructuralMetaDataTags = new Set(AlphaTex1LanguageDefinitions.structuralMetaDataSignatures.keys());
			return this._knownStructuralMetaDataTags;
		}
		_knownBarMetaDataTags = void 0;
		get knownBarMetaDataTags() {
			if (!this._knownBarMetaDataTags) this._knownBarMetaDataTags = new Set(AlphaTex1LanguageDefinitions.barMetaDataSignatures.keys());
			return this._knownBarMetaDataTags;
		}
		_knownStaffMetaDataTags = void 0;
		get knownStaffMetaDataTags() {
			if (!this._knownStaffMetaDataTags) this._knownStaffMetaDataTags = new Set(AlphaTex1LanguageDefinitions.staffMetaDataSignatures.keys());
			return this._knownStaffMetaDataTags;
		}
		_knownBeatDurationProperties = void 0;
		get knownBeatDurationProperties() {
			if (!this._knownBeatDurationProperties) this._knownBeatDurationProperties = new Set(AlphaTex1LanguageDefinitions.durationChangeProperties.keys());
			return this._knownBeatDurationProperties;
		}
		_knownBeatProperties = void 0;
		get knownBeatProperties() {
			if (!this._knownBeatProperties) this._knownBeatProperties = new Set(AlphaTex1LanguageDefinitions.beatProperties.keys());
			return this._knownBeatProperties;
		}
		_knownNoteProperties = void 0;
		get knownNoteProperties() {
			if (!this._knownNoteProperties) this._knownNoteProperties = new Set(AlphaTex1LanguageDefinitions.noteProperties.keys());
			return this._knownNoteProperties;
		}
		applyBeatProperty(importer, beat, p) {
			const tag = p.property.text.toLowerCase();
			const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.beatProperties], p, tag, p.arguments);
			if (result !== void 0) return result;
			switch (tag) {
				case "f":
					beat.fade = FadeType.FadeIn;
					return ApplyNodeResult.Applied;
				case "fo":
					beat.fade = FadeType.FadeOut;
					return ApplyNodeResult.Applied;
				case "vs":
					beat.fade = FadeType.VolumeSwell;
					return ApplyNodeResult.Applied;
				case "v":
					beat.vibrato = VibratoType.Slight;
					return ApplyNodeResult.Applied;
				case "vw":
					beat.vibrato = VibratoType.Wide;
					return ApplyNodeResult.Applied;
				case "s":
					beat.slap = true;
					return ApplyNodeResult.Applied;
				case "p":
					beat.pop = true;
					return ApplyNodeResult.Applied;
				case "tt":
					beat.tap = true;
					return ApplyNodeResult.Applied;
				case "txt":
					beat.text = p.arguments.arguments[0].text;
					return ApplyNodeResult.Applied;
				case "lyrics":
					let lyricsLine = 0;
					let lyricsText = "";
					if (p.arguments.arguments.length === 2) {
						lyricsLine = p.arguments.arguments[0].value;
						lyricsText = p.arguments.arguments[1].text;
					} else lyricsText = p.arguments.arguments[0].text;
					if (!beat.lyrics) beat.lyrics = [];
					while (beat.lyrics.length <= lyricsLine) beat.lyrics.push("");
					beat.lyrics[lyricsLine] = lyricsText;
					return ApplyNodeResult.Applied;
				case "dd":
					beat.dots = 2;
					return ApplyNodeResult.Applied;
				case "d":
					beat.dots = 1;
					return ApplyNodeResult.Applied;
				case "su":
					beat.pickStroke = PickStroke.Up;
					return ApplyNodeResult.Applied;
				case "sd":
					beat.pickStroke = PickStroke.Down;
					return ApplyNodeResult.Applied;
				case "tu":
					if (p.arguments.arguments.length === 2) {
						beat.tupletNumerator = p.arguments.arguments[0].value;
						beat.tupletDenominator = p.arguments.arguments[1].value;
					} else {
						const numerator = p.arguments.arguments[0].value;
						beat.tupletNumerator = numerator;
						const denominator = AlphaTex1LanguageHandler._getTupletDenominator(numerator);
						if (denominator < 0) {
							importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT209,
								message: `Unexpected default tuplet value '${numerator}', expected: 3, 5, 6, 7, 9, 10, 11 or 12`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: p.arguments.arguments[0].start,
								end: p.arguments.arguments[0].end
							});
							beat.tupletNumerator = -1;
							beat.tupletDenominator = -1;
							return ApplyNodeResult.NotAppliedSemanticError;
						} else beat.tupletDenominator = denominator;
					}
					return ApplyNodeResult.Applied;
				case "tb":
				case "tbe":
					let tbi = 0;
					let typeAndStyle = true;
					let typeSet = false;
					while (typeAndStyle) switch (p.arguments.arguments[tbi].nodeType) {
						case AlphaTexNodeType.Ident:
						case AlphaTexNodeType.String:
							const txt = p.arguments.arguments[tbi].text.toLowerCase();
							if (AlphaTex1EnumMappings.whammyType.has(txt)) {
								beat.whammyBarType = AlphaTex1EnumMappings.whammyType.get(txt);
								typeSet = true;
								tbi++;
							} else if (AlphaTex1EnumMappings.bendStyle.has(txt)) {
								beat.whammyStyle = AlphaTex1EnumMappings.bendStyle.get(txt);
								tbi++;
							} else {
								if (typeSet) AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "whammy style", AlphaTex1EnumMappings.bendStyle, tbi);
								else AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "whammy type", AlphaTex1EnumMappings.whammyType, tbi);
								return ApplyNodeResult.NotAppliedSemanticError;
							}
							break;
						default:
							typeAndStyle = false;
							break;
					}
					const points = this._getBendPoints(importer, p, tbi, tag === "tbe");
					if (points) for (const point of points) beat.addWhammyBarPoint(point);
					return ApplyNodeResult.Applied;
				case "bu":
					AlphaTex1LanguageHandler._applyBrush(beat, p, BrushType.BrushUp, .25);
					return ApplyNodeResult.Applied;
				case "bd":
					AlphaTex1LanguageHandler._applyBrush(beat, p, BrushType.BrushDown, .25);
					return ApplyNodeResult.Applied;
				case "au":
					AlphaTex1LanguageHandler._applyBrush(beat, p, BrushType.ArpeggioUp, 1);
					return ApplyNodeResult.Applied;
				case "ad":
					AlphaTex1LanguageHandler._applyBrush(beat, p, BrushType.ArpeggioDown, 1);
					return ApplyNodeResult.Applied;
				case "ch":
					const chordName = p.arguments.arguments[0].text;
					const chordId = AlphaTex1LanguageHandler._getChordId(beat.voice.bar.staff, chordName);
					if (!beat.voice.bar.staff.hasChord(chordId)) {
						const chord = new Chord();
						chord.showDiagram = false;
						chord.name = chordName;
						beat.voice.bar.staff.addChord(chordId, chord);
					}
					beat.chordId = chordId;
					return ApplyNodeResult.Applied;
				case "gr":
					if (p.arguments && p.arguments.arguments.length > 0) {
						const graceType = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "whammy style", AlphaTex1EnumMappings.graceType);
						if (graceType === void 0) return ApplyNodeResult.NotAppliedSemanticError;
						beat.graceType = graceType;
					} else beat.graceType = GraceType.BeforeBeat;
					return ApplyNodeResult.Applied;
				case "dy":
					const dyn = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "dynamic", AlphaTex1EnumMappings.dynamicValue);
					if (dyn === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					beat.dynamics = dyn;
					importer.state.currentDynamics = dyn;
					return ApplyNodeResult.Applied;
				case "cre":
					beat.crescendo = CrescendoType.Crescendo;
					return ApplyNodeResult.Applied;
				case "dec":
					beat.crescendo = CrescendoType.Decrescendo;
					return ApplyNodeResult.Applied;
				case "tempo":
					const tempo = p.arguments.arguments[0].value;
					let tempoLabel = "";
					let isVisible = true;
					if (p.arguments.arguments.length > 2) {
						tempoLabel = p.arguments.arguments[1].text;
						const hideText = p.arguments.arguments[2].text;
						if (hideText === "hide") isVisible = false;
						else {
							importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT209,
								message: `Unexpected third tempo property value '${hideText}', expected: 'hide'`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: p.arguments.arguments[2].start,
								end: p.arguments.arguments[2].end
							});
							return ApplyNodeResult.NotAppliedSemanticError;
						}
					} else if (p.arguments.arguments.length > 1) {
						tempoLabel = p.arguments.arguments[1].text;
						if (tempoLabel === "hide") {
							isVisible = false;
							tempoLabel = "";
						}
					}
					const tempoAutomation = new Automation();
					tempoAutomation.isLinear = false;
					tempoAutomation.type = AutomationType.Tempo;
					tempoAutomation.value = tempo;
					tempoAutomation.text = tempoLabel;
					tempoAutomation.isVisible = isVisible;
					beat.automations.push(tempoAutomation);
					beat.voice.bar.masterBar.tempoAutomations.push(tempoAutomation);
					return ApplyNodeResult.Applied;
				case "volume":
					const volumeAutomation = new Automation();
					volumeAutomation.isLinear = true;
					volumeAutomation.type = AutomationType.Volume;
					volumeAutomation.value = p.arguments.arguments[0].value;
					beat.automations.push(volumeAutomation);
					return ApplyNodeResult.Applied;
				case "balance":
					const balanceAutomation = new Automation();
					balanceAutomation.isLinear = true;
					balanceAutomation.type = AutomationType.Balance;
					balanceAutomation.value = ModelUtils.clamp(p.arguments.arguments[0].value, 0, 16);
					beat.automations.push(balanceAutomation);
					return ApplyNodeResult.Applied;
				case "tp":
					const tremolo = new TremoloPickingEffect();
					beat.tremoloPicking = tremolo;
					if (p.arguments && p.arguments.arguments.length > 0) {
						if (p.arguments.arguments.length > 0) {
							const tremoloMarks = p.arguments.arguments[0].value;
							if (tremoloMarks >= TremoloPickingEffect.minMarks && tremoloMarks <= TremoloPickingEffect.maxMarks) tremolo.marks = tremoloMarks;
							else switch (tremoloMarks) {
								case 8:
									tremolo.marks = 1;
									break;
								case 16:
									tremolo.marks = 2;
									break;
								case 32:
									tremolo.marks = 3;
									break;
								default:
									importer.addSemanticDiagnostic({
										code: AlphaTexDiagnosticCode.AT209,
										message: `Unexpected tremolo marks value '${tremoloMarks}, expected: ${TremoloPickingEffect.minMarks}-${TremoloPickingEffect.maxMarks}, or legacy: 8, 16 or 32`,
										severity: AlphaTexDiagnosticsSeverity.Error,
										start: p.arguments.arguments[0].start,
										end: p.arguments.arguments[0].end
									});
									return ApplyNodeResult.NotAppliedSemanticError;
							}
						}
						if (p.arguments.arguments.length > 1) {
							const tremoloStyle = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "tremolo picking style", AlphaTex1EnumMappings.tremoloPickingStyle, 1);
							if (tremoloStyle === void 0) return ApplyNodeResult.NotAppliedSemanticError;
							tremolo.style = tremoloStyle;
						}
					}
					return ApplyNodeResult.Applied;
				case "spd":
					AlphaTex1LanguageHandler._applySustainPedal(importer, beat, SustainPedalMarkerType.Down);
					return ApplyNodeResult.Applied;
				case "sph":
					AlphaTex1LanguageHandler._applySustainPedal(importer, beat, SustainPedalMarkerType.Hold);
					return ApplyNodeResult.Applied;
				case "spu":
					AlphaTex1LanguageHandler._applySustainPedal(importer, beat, SustainPedalMarkerType.Up);
					return ApplyNodeResult.Applied;
				case "spe":
					AlphaTex1LanguageHandler._applySustainPedal(importer, beat, SustainPedalMarkerType.Up, true);
					return ApplyNodeResult.Applied;
				case "slashed":
					beat.slashed = true;
					return ApplyNodeResult.Applied;
				case "ds":
					beat.deadSlapped = true;
					if (beat.notes.length === 1 && beat.notes[0].isDead) beat.removeNote(beat.notes[0]);
					return ApplyNodeResult.Applied;
				case "glpf":
					beat.golpe = GolpeType.Finger;
					return ApplyNodeResult.Applied;
				case "glpt":
					beat.golpe = GolpeType.Thumb;
					return ApplyNodeResult.Applied;
				case "waho":
					beat.wahPedal = WahPedal.Open;
					return ApplyNodeResult.Applied;
				case "wahc":
					beat.wahPedal = WahPedal.Closed;
					return ApplyNodeResult.Applied;
				case "barre":
					beat.barreFret = p.arguments.arguments[0].value;
					beat.barreShape = BarreShape.Full;
					if (p.arguments.arguments.length > 1) {
						const barreShape = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "barre shape", AlphaTex1EnumMappings.barreShape, 1);
						if (barreShape === void 0) return ApplyNodeResult.NotAppliedSemanticError;
						beat.barreShape = barreShape;
					}
					return ApplyNodeResult.Applied;
				case "rasg":
					const rasg = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "rasgueado pattern", AlphaTex1EnumMappings.rasgueado);
					if (rasg === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					beat.rasgueado = rasg;
					return ApplyNodeResult.Applied;
				case "ot":
					const ottava = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "ottava", AlphaTex1EnumMappings.ottavia);
					if (ottava === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					beat.ottava = ottava;
					return ApplyNodeResult.Applied;
				case "legatoorigin":
					beat.isLegatoOrigin = true;
					return ApplyNodeResult.Applied;
				case "instrument":
					let program = 0;
					switch (p.arguments.arguments[0].nodeType) {
						case AlphaTexNodeType.Ident:
						case AlphaTexNodeType.String:
							program = GeneralMidi.getValue(p.arguments.arguments[0].text);
							break;
						case AlphaTexNodeType.Number:
							program = p.arguments.arguments[0].value;
							break;
					}
					const instrumentAutomation = new Automation();
					instrumentAutomation.isLinear = false;
					instrumentAutomation.type = AutomationType.Instrument;
					instrumentAutomation.value = program;
					beat.automations.push(instrumentAutomation);
					return ApplyNodeResult.Applied;
				case "bank":
					const bankAutomation = new Automation();
					bankAutomation.isLinear = false;
					bankAutomation.type = AutomationType.Bank;
					bankAutomation.value = p.arguments.arguments[0].value;
					beat.automations.push(bankAutomation);
					return ApplyNodeResult.Applied;
				case "fermata":
					const fermataType = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "fermata", AlphaTex1EnumMappings.fermataType);
					if (fermataType === void 0) return ApplyNodeResult.NotAppliedSemanticError;
					const fermata = new Fermata();
					fermata.type = fermataType;
					if (p.arguments.arguments.length > 1) fermata.length = p.arguments.arguments[1].value;
					beat.fermata = fermata;
					return ApplyNodeResult.Applied;
				case "beam":
					const beamMode = p.arguments.arguments[0].text;
					switch (beamMode.toLowerCase()) {
						case "invert":
							beat.invertBeamDirection = true;
							break;
						case "up":
							beat.preferredBeamDirection = BeamDirection.Up;
							break;
						case "down":
							beat.preferredBeamDirection = BeamDirection.Down;
							break;
						case "auto":
							beat.beamingMode = BeatBeamingMode.Auto;
							break;
						case "split":
							beat.beamingMode = BeatBeamingMode.ForceSplitToNext;
							break;
						case "merge":
							beat.beamingMode = BeatBeamingMode.ForceMergeWithNext;
							break;
						case "splitsecondary":
							beat.beamingMode = BeatBeamingMode.ForceSplitOnSecondaryToNext;
							break;
						default:
							importer.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT209,
								message: `Unexpected beam value '${beamMode}', expected: ${[
									"invert",
									"up",
									"down",
									"auto",
									"split",
									"merge",
									"splitsecondary"
								].join(",")}`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: p.arguments.arguments[0].start,
								end: p.arguments.arguments[0].end
							});
							return ApplyNodeResult.NotAppliedSemanticError;
					}
					return ApplyNodeResult.Applied;
				case "timer":
					beat.showTimer = true;
					return ApplyNodeResult.Applied;
			}
			return ApplyNodeResult.NotAppliedUnrecognizedMarker;
		}
		static _applySustainPedal(importer, beat, pedalType, end = false) {
			const sustainPedal = new SustainPedalMarker();
			sustainPedal.pedalType = pedalType;
			if (end) sustainPedal.ratioPosition = 1;
			else sustainPedal.ratioPosition = .001 * beat.voice.bar.sustainPedals.length;
			importer.state.sustainPedalToBeat.set(sustainPedal, beat);
			beat.voice.bar.sustainPedals.push(sustainPedal);
		}
		static _applyBrush(beat, p, brushType, durationFactor) {
			beat.brushType = brushType;
			if (p.arguments && p.arguments.arguments.length > 0) beat.brushDuration = p.arguments.arguments[0].value;
			else {
				beat.updateDurations();
				beat.brushDuration = beat.playbackDuration * durationFactor / beat.notes.length;
			}
		}
		applyNoteProperty(importer, note, p) {
			const tag = p.property.text.toLowerCase();
			const result = this._checkArgumentTypes(importer, [AlphaTex1LanguageDefinitions.noteProperties], p, tag, p.arguments);
			if (result !== void 0) return result;
			switch (tag) {
				case "b":
				case "be":
					let tbi = 0;
					let typeAndStyle = true;
					let typeSet = false;
					while (typeAndStyle) switch (p.arguments.arguments[tbi].nodeType) {
						case AlphaTexNodeType.Ident:
						case AlphaTexNodeType.String:
							const txt = p.arguments.arguments[tbi].text.toLowerCase();
							if (AlphaTex1EnumMappings.bendType.has(txt)) {
								note.bendType = AlphaTex1EnumMappings.bendType.get(txt);
								typeSet = true;
								tbi++;
							} else if (AlphaTex1EnumMappings.bendStyle.has(txt)) {
								note.bendStyle = AlphaTex1EnumMappings.bendStyle.get(txt);
								tbi++;
							} else {
								if (typeSet) AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "bend style", AlphaTex1EnumMappings.bendStyle, tbi);
								else AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, "bend type", AlphaTex1EnumMappings.bendType, tbi);
								return ApplyNodeResult.NotAppliedSemanticError;
							}
							break;
						default:
							typeAndStyle = false;
							break;
					}
					const points = this._getBendPoints(importer, p, tbi, tag === "be");
					if (points) for (const point of points) note.addBendPoint(point);
					return ApplyNodeResult.Applied;
				case "nh":
					note.harmonicType = HarmonicType.Natural;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(note.fret);
					return ApplyNodeResult.Applied;
				case "ah":
					note.harmonicType = HarmonicType.Artificial;
					note.harmonicValue = AlphaTex1LanguageHandler._harmonicValue(p.arguments, note.harmonicValue);
					return ApplyNodeResult.Applied;
				case "th":
					note.harmonicType = HarmonicType.Tap;
					note.harmonicValue = AlphaTex1LanguageHandler._harmonicValue(p.arguments, note.harmonicValue);
					return ApplyNodeResult.Applied;
				case "ph":
					note.harmonicType = HarmonicType.Pinch;
					note.harmonicValue = AlphaTex1LanguageHandler._harmonicValue(p.arguments, note.harmonicValue);
					return ApplyNodeResult.Applied;
				case "sh":
					note.harmonicType = HarmonicType.Semi;
					note.harmonicValue = AlphaTex1LanguageHandler._harmonicValue(p.arguments, note.harmonicValue);
					return ApplyNodeResult.Applied;
				case "fh":
					note.harmonicType = HarmonicType.Feedback;
					note.harmonicValue = AlphaTex1LanguageHandler._harmonicValue(p.arguments, note.harmonicValue);
					return ApplyNodeResult.Applied;
				case "tr":
					const trillFret = p.arguments.arguments[0].value;
					let trillDuration = Duration.Sixteenth;
					if (p.arguments.arguments.length > 1) {
						const trillDurationValue = p.arguments.arguments[1].value;
						switch (trillDurationValue) {
							case 16:
								trillDuration = Duration.Sixteenth;
								break;
							case 32:
								trillDuration = Duration.ThirtySecond;
								break;
							case 64:
								trillDuration = Duration.SixtyFourth;
								break;
							default:
								importer.addSemanticDiagnostic({
									code: AlphaTexDiagnosticCode.AT209,
									message: `Unexpected trill duration value '${trillDurationValue}', expected: 16, 32 or 64`,
									severity: AlphaTexDiagnosticsSeverity.Error,
									start: p.arguments.arguments[1].start,
									end: p.arguments.arguments[1].end
								});
								return ApplyNodeResult.NotAppliedSemanticError;
						}
					}
					note.trillValue = trillFret + note.stringTuning;
					note.trillSpeed = trillDuration;
					return ApplyNodeResult.Applied;
				case "v":
					note.vibrato = VibratoType.Slight;
					return ApplyNodeResult.Applied;
				case "vw":
					note.vibrato = VibratoType.Wide;
					return ApplyNodeResult.Applied;
				case "sl":
					note.slideOutType = SlideOutType.Legato;
					return ApplyNodeResult.Applied;
				case "ss":
					note.slideOutType = SlideOutType.Shift;
					return ApplyNodeResult.Applied;
				case "sib":
					note.slideInType = SlideInType.IntoFromBelow;
					return ApplyNodeResult.Applied;
				case "sia":
					note.slideInType = SlideInType.IntoFromAbove;
					return ApplyNodeResult.Applied;
				case "sou":
					note.slideOutType = SlideOutType.OutUp;
					return ApplyNodeResult.Applied;
				case "sod":
					note.slideOutType = SlideOutType.OutDown;
					return ApplyNodeResult.Applied;
				case "psd":
					note.slideOutType = SlideOutType.PickSlideDown;
					return ApplyNodeResult.Applied;
				case "psu":
					note.slideOutType = SlideOutType.PickSlideUp;
					return ApplyNodeResult.Applied;
				case "h":
					note.isHammerPullOrigin = true;
					return ApplyNodeResult.Applied;
				case "lht":
					note.isLeftHandTapped = true;
					return ApplyNodeResult.Applied;
				case "g":
					note.isGhost = true;
					return ApplyNodeResult.Applied;
				case "ac":
					note.accentuated = AccentuationType.Normal;
					return ApplyNodeResult.Applied;
				case "hac":
					note.accentuated = AccentuationType.Heavy;
					return ApplyNodeResult.Applied;
				case "ten":
					note.accentuated = AccentuationType.Tenuto;
					return ApplyNodeResult.Applied;
				case "pm":
					note.isPalmMute = true;
					return ApplyNodeResult.Applied;
				case "st":
					note.isStaccato = true;
					return ApplyNodeResult.Applied;
				case "lr":
					note.isLetRing = true;
					return ApplyNodeResult.Applied;
				case "x":
					note.isDead = true;
					return ApplyNodeResult.Applied;
				case "-":
				case "t":
					note.isTieDestination = true;
					return ApplyNodeResult.Applied;
				case "lf":
					let leftFinger = Fingers.Thumb;
					if (p.arguments && p.arguments.arguments.length > 0) {
						const customFinger = AlphaTex1LanguageHandler._toFinger(importer, p.arguments);
						if (customFinger === void 0) return ApplyNodeResult.NotAppliedSemanticError;
						leftFinger = customFinger;
					}
					note.leftHandFinger = leftFinger;
					return ApplyNodeResult.Applied;
				case "rf":
					let rightFinger = Fingers.Thumb;
					if (p.arguments && p.arguments.arguments.length > 0) {
						const customFinger = AlphaTex1LanguageHandler._toFinger(importer, p.arguments);
						if (customFinger === void 0) return ApplyNodeResult.NotAppliedSemanticError;
						rightFinger = customFinger;
					}
					note.rightHandFinger = rightFinger;
					return ApplyNodeResult.Applied;
				case "acc":
					note.accidentalMode = ModelUtils.parseAccidentalMode(p.arguments.arguments[0].text);
					return ApplyNodeResult.Applied;
				case "turn":
					note.ornament = NoteOrnament.Turn;
					return ApplyNodeResult.Applied;
				case "iturn":
					note.ornament = NoteOrnament.InvertedTurn;
					return ApplyNodeResult.Applied;
				case "umordent":
					note.ornament = NoteOrnament.UpperMordent;
					return ApplyNodeResult.Applied;
				case "lmordent":
					note.ornament = NoteOrnament.LowerMordent;
					return ApplyNodeResult.Applied;
				case "string":
					note.showStringNumber = true;
					return ApplyNodeResult.Applied;
				case "hide":
					note.isVisible = false;
					return ApplyNodeResult.Applied;
				case "slur":
					const slurId = p.arguments.arguments[0].text;
					if (importer.state.slurs.has(slurId)) {
						const slurOrigin = importer.state.slurs.get(slurId);
						slurOrigin.slurDestination = note;
						note.slurOrigin = slurOrigin;
						note.isSlurDestination = true;
					} else importer.state.slurs.set(slurId, note);
					return ApplyNodeResult.Applied;
				default: return this.applyBeatProperty(importer, note.beat, p);
			}
			return ApplyNodeResult.NotAppliedUnrecognizedMarker;
		}
		static _toFinger(importer, args) {
			const value = args.arguments[0].value;
			switch (value) {
				case 1: return Fingers.Thumb;
				case 2: return Fingers.IndexFinger;
				case 3: return Fingers.MiddleFinger;
				case 4: return Fingers.AnnularFinger;
				case 5: return Fingers.LittleFinger;
				default:
					importer.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT211,
						message: `Value is out of valid range. Allowed range: 1-5, Actual Value: ${value}`,
						start: args.arguments[0].start,
						end: args.arguments[0].end,
						severity: AlphaTexDiagnosticsSeverity.Error
					});
					return;
			}
		}
		static _harmonicValue(args, harmonicValue) {
			if (args) harmonicValue = args.arguments[0].value;
			return harmonicValue;
		}
		_getBendPoints(importer, p, argStartIndex, exact) {
			let args = p.arguments.arguments;
			let remainingArgs = args.length - argStartIndex;
			let errorNode = p.arguments;
			if (remainingArgs > 0 && args[argStartIndex].nodeType === AlphaTexNodeType.Arguments) {
				args = args[argStartIndex].arguments;
				argStartIndex = 0;
				remainingArgs = args.length;
				errorNode = args[argStartIndex];
			}
			const argsPerItem = exact ? 2 : 1;
			if (remainingArgs % argsPerItem !== 0) {
				const pointCount = Math.ceil(remainingArgs / argsPerItem);
				const neededArgs = pointCount * argsPerItem;
				importer.addSemanticDiagnostic({
					code: AlphaTexDiagnosticCode.AT214,
					message: `The '${p.property.text}' effect needs ${argsPerItem} arguments per item. With ${pointCount} points, ${neededArgs} arguments are needed, only ${remainingArgs} arguments found.`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: errorNode.end,
					end: errorNode.end
				});
				return;
			}
			const points = [];
			let vi = argStartIndex;
			while (vi < args.length) {
				let offset = 0;
				let value = 0;
				if (exact) {
					offset = args[vi++].value;
					value = args[vi++].value;
				} else {
					offset = 0;
					value = args[vi++].value;
				}
				points.push(new BendPoint(offset, value));
			}
			if (points.length > 0) {
				if (points.length > 60) points.splice(60, points.length - 60);
				if (exact) points.sort((a, b) => {
					return a.offset - b.offset;
				});
				else {
					const count = points.length;
					const step = BendPoint.MaxPosition / (count - 1) | 0;
					let i = 0;
					while (i < count) {
						points[i].offset = Math.min(BendPoint.MaxPosition, i * step);
						i++;
					}
				}
				return points;
			} else return;
		}
		static _parseEnumValue(importer, p, name, lookup, valueIndex = 0) {
			if (valueIndex >= p.arguments.length) return;
			const txt = p.arguments[valueIndex].text;
			if (lookup.has(txt.toLowerCase())) return lookup.get(txt.toLowerCase());
			else {
				importer.addSemanticDiagnostic({
					code: AlphaTexDiagnosticCode.AT209,
					message: `Unexpected ${name} value '${txt}', expected: ${Array.from(lookup.keys()).join(",")}`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: p.arguments[valueIndex].start,
					end: p.arguments[valueIndex].end
				});
				return;
			}
		}
		static _defaultScore = new Score();
		static _defaultTrack = new Track();
		buildScoreMetaDataNodes(score) {
			const nodes = [];
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "album", score, score.album, ScoreSubElement.Album);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "artist", score, score.artist, ScoreSubElement.Artist);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "copyright", score, score.copyright, ScoreSubElement.Copyright);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "copyright2", score, void 0, ScoreSubElement.CopyrightSecondLine);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "wordsandmusic", score, void 0, ScoreSubElement.WordsAndMusic, true);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "instructions", score, score.instructions, void 0);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "music", score, score.music, ScoreSubElement.Music);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "notices", score, score.notices, void 0);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "subtitle", score, score.subTitle, ScoreSubElement.SubTitle);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "title", score, score.title, ScoreSubElement.Title);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "words", score, score.words, ScoreSubElement.Words);
			AlphaTex1LanguageHandler._buildScoreInfoMeta(nodes, "tab", score, score.tab, ScoreSubElement.Transcriber);
			if (score.defaultSystemsLayout !== AlphaTex1LanguageHandler._defaultScore.defaultSystemsLayout) nodes.push(Atnf.numberMeta("defaultSystemsLayout", score.defaultSystemsLayout));
			if (score.systemsLayout.length > 0) nodes.push(Atnf.meta("systemsLayout", Atnf.args(score.systemsLayout.map((l) => Atnf.number(l)))));
			AlphaTex1LanguageHandler._buildStyleSheetMetaData(nodes, score.stylesheet);
			if (nodes.length > 0) nodes[0].leadingComments = [{
				text: "Score Metadata",
				multiLine: false
			}];
			return nodes;
		}
		static _buildStyleSheetMetaData(nodes, stylesheet) {
			const firstStyleSheet = nodes.length;
			if (stylesheet.hideDynamics) nodes.push(Atnf.meta("hideDynamics"));
			if (stylesheet.bracketExtendMode !== AlphaTex1LanguageHandler._defaultScore.stylesheet.bracketExtendMode) nodes.push(Atnf.identMeta("bracketExtendMode", AlphaTex1EnumMappings.bracketExtendModeReversed.get(stylesheet.bracketExtendMode)));
			if (stylesheet.useSystemSignSeparator) nodes.push(Atnf.meta("useSystemSignSeparator"));
			if (stylesheet.multiTrackMultiBarRest) nodes.push(Atnf.meta("multiBarRest"));
			if (stylesheet.singleTrackTrackNamePolicy !== AlphaTex1LanguageHandler._defaultScore.stylesheet.singleTrackTrackNamePolicy) nodes.push(Atnf.identMeta("singleTrackTrackNamePolicy", AlphaTex1EnumMappings.trackNamePolicyReversed.get(stylesheet.singleTrackTrackNamePolicy)));
			if (stylesheet.multiTrackTrackNamePolicy !== AlphaTex1LanguageHandler._defaultScore.stylesheet.multiTrackTrackNamePolicy) nodes.push(Atnf.identMeta("multiTrackTrackNamePolicy", AlphaTex1EnumMappings.trackNamePolicyReversed.get(stylesheet.multiTrackTrackNamePolicy)));
			if (stylesheet.firstSystemTrackNameMode !== AlphaTex1LanguageHandler._defaultScore.stylesheet.firstSystemTrackNameMode) nodes.push(Atnf.identMeta("firstSystemTrackNameMode", AlphaTex1EnumMappings.trackNameModeReversed.get(stylesheet.firstSystemTrackNameMode)));
			if (stylesheet.otherSystemsTrackNameMode !== AlphaTex1LanguageHandler._defaultScore.stylesheet.otherSystemsTrackNameMode) nodes.push(Atnf.identMeta("otherSystemsTrackNameMode", AlphaTex1EnumMappings.trackNameModeReversed.get(stylesheet.otherSystemsTrackNameMode)));
			if (stylesheet.firstSystemTrackNameOrientation !== AlphaTex1LanguageHandler._defaultScore.stylesheet.firstSystemTrackNameOrientation) nodes.push(Atnf.identMeta("firstSystemTrackNameOrientation", AlphaTex1EnumMappings.trackNameOrientationReversed.get(stylesheet.firstSystemTrackNameOrientation)));
			if (stylesheet.otherSystemsTrackNameOrientation !== AlphaTex1LanguageHandler._defaultScore.stylesheet.otherSystemsTrackNameOrientation) nodes.push(Atnf.identMeta("otherSystemsTrackNameOrientation", AlphaTex1EnumMappings.trackNameOrientationReversed.get(stylesheet.otherSystemsTrackNameOrientation)));
			if (stylesheet.extendBarLines) nodes.push(Atnf.meta("extendBarLines"));
			if (stylesheet.globalDisplayChordDiagramsInScore) nodes.push(Atnf.meta("chordDiagramsInScore"));
			if (stylesheet.hideEmptyStaves) nodes.push(Atnf.meta("hideEmptyStaves"));
			if (stylesheet.hideEmptyStavesInFirstSystem) nodes.push(Atnf.meta("hideEmptyStavesInFirstSystem"));
			if (stylesheet.showSingleStaffBrackets) nodes.push(Atnf.meta("showSingleStaffBrackets"));
			if (stylesheet.barNumberDisplay !== BarNumberDisplay.AllBars) nodes.push(Atnf.identMeta("defaultBarNumberDisplay", BarNumberDisplay[stylesheet.barNumberDisplay]));
			if (firstStyleSheet < nodes.length) nodes[firstStyleSheet].leadingComments = [{
				multiLine: false,
				text: "Score Stylesheet"
			}];
		}
		static _buildScoreInfoMeta(nodes, tag, score, value, element, writeIfEmpty = false) {
			if (value !== void 0 && value.length === 0 && !writeIfEmpty) return;
			const args = [];
			if (value !== void 0) args.push(Atnf.string(value));
			if (element !== void 0) {
				const style = score.style && score.style.headerAndFooter.has(element) ? score.style.headerAndFooter.get(element) : void 0;
				const defaultStyle = ScoreStyle.defaultHeaderAndFooter.has(element) ? ScoreStyle.defaultHeaderAndFooter.get(element) : void 0;
				if (style && (!defaultStyle || !HeaderFooterStyle.equals(defaultStyle, style))) {
					args.push(Atnf.string(style.isVisible === false ? "" : style.template));
					args.push(Atnf.ident(AlphaTex1EnumMappings.textAlignReversed.get(style.textAlign)));
				}
			}
			if (value === void 0 && args.length === 0) return;
			else if (value !== void 0 && value.length === 0 && args.length === 1) return;
			nodes.push(Atnf.meta(tag, Atnf.args(args)));
		}
		buildSyncPointNodes(score) {
			const nodes = [];
			const flatSyncPoints = score.exportFlatSyncPoints();
			for (const p of flatSyncPoints) nodes.push(Atnf.meta("sync", Atnf.args([
				Atnf.number(p.barIndex),
				Atnf.number(p.barOccurence),
				Atnf.number(p.millisecondOffset),
				p.barPosition > 0 ? Atnf.number(p.barPosition) : void 0
			])));
			return nodes;
		}
		buildBarMetaDataNodes(staff, bar, voice, isMultiVoice) {
			const nodes = [];
			AlphaTex1LanguageHandler._buildStructuralMetaDataNodes(bar, staff, nodes, isMultiVoice, voice);
			if (!bar) return nodes;
			if (voice === 0) {
				if (staff.index === 0 && staff.track.index === 0) AlphaTex1LanguageHandler._buildMasterBarMetaDataNodes(nodes, bar.masterBar);
			}
			const firstBarMetaIndex = nodes.length;
			if (voice === 0 && bar.index === 0 && staff.index === 0 && staff.track.index === 0) nodes.push(Atnf.identMeta("accidentals", "auto"));
			if (bar.index === 0 || bar.clef !== bar.previousBar?.clef) nodes.push(Atnf.identMeta("clef", AlphaTex1EnumMappings.clefReversed.get(bar.clef)));
			if (bar.index === 0 && bar.clefOttava !== Ottavia.Regular || bar.clefOttava !== bar.previousBar?.clefOttava) nodes.push(Atnf.identMeta("ottava", AlphaTex1EnumMappings.ottaviaReversed.get(bar.clefOttava)));
			if (bar.index === 0 && bar.simileMark !== SimileMark.None || bar.simileMark !== bar.previousBar?.simileMark) nodes.push(Atnf.identMeta("simile", AlphaTex1EnumMappings.simileMarkReversed.get(bar.simileMark)));
			if (bar.displayScale !== 1) nodes.push(Atnf.numberMeta("scale", bar.displayScale));
			if (bar.displayWidth > 0) nodes.push(Atnf.numberMeta("width", bar.displayWidth));
			for (const sp of bar.sustainPedals) {
				let pedalType = "";
				switch (sp.pedalType) {
					case SustainPedalMarkerType.Down:
						pedalType = "spd";
						break;
					case SustainPedalMarkerType.Hold:
						pedalType = "sph";
						break;
					case SustainPedalMarkerType.Up:
						pedalType = "spu";
						break;
				}
				if (pedalType) nodes.push(Atnf.numberMeta(pedalType, sp.ratioPosition));
			}
			if (bar.barLineLeft !== BarLineStyle.Automatic) nodes.push(Atnf.identMeta("barLineLeft", AlphaTex1EnumMappings.barLineStyleReversed.get(bar.barLineLeft)));
			if (bar.barLineRight !== BarLineStyle.Automatic) nodes.push(Atnf.identMeta("barLineRight", AlphaTex1EnumMappings.barLineStyleReversed.get(bar.barLineRight)));
			if (bar.index === 0 || bar.keySignature !== bar.previousBar.keySignature || bar.keySignatureType !== bar.previousBar.keySignatureType) {
				let ks = "";
				if (bar.keySignatureType === KeySignatureType.Minor) ks = AlphaTex1EnumMappings.keySignaturesMinorReversed.get(bar.keySignature);
				else ks = AlphaTex1EnumMappings.keySignaturesMajorReversed.get(bar.keySignature);
				nodes.push(Atnf.identMeta("ks", ks));
			}
			if (firstBarMetaIndex < nodes.length) nodes[firstBarMetaIndex].leadingComments = [{
				multiLine: false,
				text: `Bar ${bar.index + 1} Metadata`
			}];
			if (bar.barNumberDisplay !== void 0) nodes.push(Atnf.identMeta("barNumberDisplay", BarNumberDisplay[bar.barNumberDisplay]));
			return nodes;
		}
		static _buildStaffMetaDataNodes(nodes, staff) {
			const firstStaffMetaIndex = nodes.length;
			if (staff.capo !== 0) nodes.push(Atnf.numberMeta("capo", staff.capo));
			if (staff.isPercussion) nodes.push(Atnf.identMeta("articulation", "defaults"));
			else if (staff.isStringed) {
				const tuning = Atnf.meta("tuning", Atnf.args(staff.stringTuning.tunings.map((t) => Atnf.ident(Tuning.getTextForTuning(t, true)))));
				nodes.push(tuning);
				if (staff.track.score.stylesheet.perTrackDisplayTuning && staff.track.score.stylesheet.perTrackDisplayTuning.has(staff.track.index)) tuning.properties = Atnf.props([["hide", void 0]]);
				if (staff.stringTuning.name.length > 0) {
					tuning.properties ??= Atnf.props([]);
					Atnf.prop(tuning.properties.properties, "label", Atnf.stringValue(staff.stringTuning.name));
				}
			}
			if (staff.transpositionPitch !== 0) nodes.push(Atnf.numberMeta("transpose", -staff.transpositionPitch));
			const defaultTransposition = ModelUtils.displayTranspositionPitches.has(staff.track.playbackInfo.program) ? ModelUtils.displayTranspositionPitches.get(staff.track.playbackInfo.program) : 0;
			if (staff.displayTranspositionPitch !== defaultTransposition) nodes.push(Atnf.numberMeta("displaytranspose", -staff.displayTranspositionPitch));
			if (staff.chords != null) for (const [_, chord] of staff.chords) nodes.push(AlphaTex1LanguageHandler._buildChordNode(chord));
			if (firstStaffMetaIndex < nodes.length) nodes[firstStaffMetaIndex].leadingComments = [{
				multiLine: false,
				text: `Staff ${staff.index + 1} Metadata`
			}];
		}
		static _buildChordNode(chord) {
			const chordNode = Atnf.meta("chord", Atnf.args([Atnf.string(chord.name)], true), Atnf.props([
				chord.firstFret >= 0 ? ["firstfret", Atnf.numberValue(chord.firstFret)] : void 0,
				["showdiagram", Atnf.identValue(chord.showDiagram ? "true" : "false")],
				["showfingering", Atnf.identValue(chord.showFingering ? "true" : "false")],
				["showname", Atnf.identValue(chord.showName ? "true" : "false")],
				chord.barreFrets.length > 0 ? ["barre", Atnf.args(chord.barreFrets.map((f) => Atnf.number(f)))] : void 0
			]));
			for (let i = 0; i < chord.staff.tuning.length; i++) if (i < chord.strings.length && chord.strings[i] >= 0) chordNode.arguments.arguments.push(Atnf.number(chord.strings[i]));
			else chordNode.arguments.arguments.push(Atnf.ident("x"));
			return chordNode;
		}
		static _buildMasterBarMetaDataNodes(nodes, masterBar) {
			const firstMetaIndex = nodes.length;
			if (masterBar.alternateEndings !== 0) nodes.push(Atnf.meta("ae", Atnf.args(ModelUtils.getAlternateEndingsList(masterBar.alternateEndings).map((i) => Atnf.number(i + 1)))));
			if (masterBar.isRepeatStart) nodes.push(Atnf.meta("ro"));
			if (masterBar.isRepeatEnd) nodes.push(Atnf.numberMeta("rc", masterBar.repeatCount));
			if (masterBar.index === 0 || masterBar.timeSignatureCommon !== masterBar.previousMasterBar?.timeSignatureCommon || masterBar.timeSignatureNumerator !== masterBar.previousMasterBar.timeSignatureNumerator || masterBar.timeSignatureDenominator !== masterBar.previousMasterBar.timeSignatureDenominator) if (masterBar.timeSignatureCommon) nodes.push(Atnf.identMeta("ts", "common"));
			else nodes.push(Atnf.meta("ts", Atnf.args([Atnf.number(masterBar.timeSignatureNumerator), Atnf.number(masterBar.timeSignatureDenominator)])));
			if (masterBar.beamingRules) for (const [k, v] of masterBar.beamingRules.groups) {
				const args = Atnf.args([Atnf.number(k)], true);
				for (const i of v) args.arguments.push(Atnf.number(i));
				nodes.push(Atnf.meta("beaming", args));
			}
			if (masterBar.index > 0 && masterBar.tripletFeel !== masterBar.previousMasterBar?.tripletFeel || masterBar.index === 0 && masterBar.tripletFeel !== TripletFeel.NoTripletFeel) nodes.push(Atnf.identMeta("tf", AlphaTex1EnumMappings.tripletFeelReversed.get(masterBar.tripletFeel)));
			if (masterBar.isFreeTime) nodes.push(Atnf.meta("ft"));
			if (masterBar.section != null) nodes.push(Atnf.meta("section", Atnf.args([Atnf.string(masterBar.section.marker), Atnf.string(masterBar.section.text)])));
			if (masterBar.isAnacrusis) nodes.push(Atnf.meta("ac"));
			if (masterBar.displayScale !== 1) nodes.push(Atnf.numberMeta("scale", masterBar.displayScale));
			if (masterBar.displayWidth > 0) nodes.push(Atnf.numberMeta("width", masterBar.displayWidth));
			if (masterBar.directions) for (const d of masterBar.directions) nodes.push(Atnf.identMeta("jump", AlphaTex1EnumMappings.directionReversed.get(d)));
			for (const a of masterBar.tempoAutomations) {
				const tempo = Atnf.meta("tempo", Atnf.args([
					Atnf.number(a.value),
					a.text ? Atnf.string(a.text) : void 0,
					a.ratioPosition > 0 ? Atnf.number(a.ratioPosition) : void 0,
					!a.isVisible ? Atnf.ident("hide") : void 0
				]));
				if (tempo.arguments.arguments.length === 1) {
					tempo.arguments.openParenthesis = void 0;
					tempo.arguments.closeParenthesis = void 0;
				}
				nodes.push(tempo);
			}
			if (firstMetaIndex < nodes.length) nodes[firstMetaIndex].leadingComments = [{
				multiLine: false,
				text: `Masterbar ${masterBar.index + 1} Metadata`
			}];
		}
		static _buildStructuralMetaDataNodes(bar, staff, nodes, isMultiVoice, voice) {
			if (bar === void 0 || bar.index === 0) {
				if (voice === 0) {
					if (staff.index === 0) nodes.push(AlphaTex1LanguageHandler._buildNewTrackNode(staff.track));
					nodes.push(AlphaTex1LanguageHandler._buildNewStaffNode(staff));
					AlphaTex1LanguageHandler._buildStaffMetaDataNodes(nodes, staff);
				}
				if (isMultiVoice) {
					const voiceNode = Atnf.meta("voice");
					voiceNode.trailingComments = [{
						multiLine: true,
						text: `Voice ${voice + 1}`
					}];
					nodes.push(voiceNode);
				}
			}
		}
		static _buildNewStaffNode(staff) {
			const node = Atnf.meta("staff", void 0, Atnf.props([
				staff.showStandardNotation ? ["score", Atnf.args([staff.standardNotationLineCount !== Staff.DefaultStandardNotationLineCount ? Atnf.number(staff.standardNotationLineCount) : void 0])] : void 0,
				staff.showTablature ? ["tabs", void 0] : void 0,
				staff.showSlash ? ["slash", void 0] : void 0,
				staff.showNumbered ? ["numbered", void 0] : void 0
			]));
			if (node.properties && node.properties.properties.length > 0) node.properties.properties[0].leadingComments = [{
				multiLine: false,
				text: "Staff Properties"
			}];
			return node;
		}
		static _buildNewTrackNode(track) {
			const node = Atnf.meta("track", Atnf.args([Atnf.string(track.name), track.shortName.length > 0 ? Atnf.string(track.shortName) : void 0]), Atnf.props([
				track.color.rgba !== AlphaTex1LanguageHandler._defaultTrack.color.rgba ? ["color", Atnf.stringValue(track.color.rgba)] : void 0,
				track.defaultSystemsLayout !== AlphaTex1LanguageHandler._defaultTrack.defaultSystemsLayout ? ["defaultSystemsLayout", Atnf.numberValue(track.defaultSystemsLayout)] : void 0,
				track.systemsLayout.length ? ["systemsLayout", Atnf.args(track.systemsLayout.map((d) => Atnf.number(d)))] : void 0,
				["volume", Atnf.numberValue(track.playbackInfo.volume)],
				["balance", Atnf.numberValue(track.playbackInfo.balance)],
				track.playbackInfo.isMute ? ["mute", void 0] : void 0,
				track.playbackInfo.isSolo ? ["solo", void 0] : void 0,
				track.score.stylesheet.perTrackMultiBarRest && track.score.stylesheet.perTrackMultiBarRest.has(track.index) ? ["multiBarRest", void 0] : void 0,
				["instrument", Atnf.identValue(track.isPercussion ? "percussion" : GeneralMidi.getName(track.playbackInfo.program))],
				track.playbackInfo.bank > 0 ? ["bank", Atnf.numberValue(track.playbackInfo.bank)] : void 0
			]));
			if (node.properties && node.properties.properties.length > 0) node.properties.properties[0].leadingComments = [{
				multiLine: false,
				text: "Track Properties"
			}];
			return node;
		}
		buildNoteEffects(note) {
			const properties = [];
			if (note.hasBend) {
				const beValue = Atnf.args([Atnf.ident(AlphaTex1EnumMappings.bendTypeReversed.get(note.bendType)), note.bendStyle !== BendStyle.Default ? Atnf.ident(AlphaTex1EnumMappings.bendStyleReversed.get(note.bendStyle)) : void 0], true);
				for (const p of note.bendPoints) {
					beValue.arguments.push(Atnf.number(p.offset));
					beValue.arguments.push(Atnf.number(p.value));
				}
				Atnf.prop(properties, "be", beValue);
			}
			let harmonicType = "";
			switch (note.harmonicType) {
				case HarmonicType.Natural:
					Atnf.prop(properties, "nh");
					break;
				case HarmonicType.Artificial:
					harmonicType = "ah";
					break;
				case HarmonicType.Pinch:
					harmonicType = "ph";
					break;
				case HarmonicType.Tap:
					harmonicType = "th";
					break;
				case HarmonicType.Semi:
					harmonicType = "sh";
					break;
				case HarmonicType.Feedback:
					harmonicType = "fh";
					break;
			}
			if (harmonicType) Atnf.prop(properties, harmonicType, Atnf.numberValue(note.harmonicValue));
			if (note.showStringNumber) Atnf.prop(properties, "string");
			if (note.isTrill) Atnf.prop(properties, "tr", Atnf.args([Atnf.number(note.trillFret), Atnf.number(note.trillSpeed)]));
			switch (note.vibrato) {
				case VibratoType.Slight:
					Atnf.prop(properties, "v");
					break;
				case VibratoType.Wide:
					Atnf.prop(properties, "vw");
					break;
			}
			switch (note.slideInType) {
				case SlideInType.IntoFromBelow:
					Atnf.prop(properties, "sib");
					break;
				case SlideInType.IntoFromAbove:
					Atnf.prop(properties, "sia");
					break;
			}
			switch (note.slideOutType) {
				case SlideOutType.Shift:
					Atnf.prop(properties, "ss");
					break;
				case SlideOutType.Legato:
					Atnf.prop(properties, "sl");
					break;
				case SlideOutType.OutUp:
					Atnf.prop(properties, "sou");
					break;
				case SlideOutType.OutDown:
					Atnf.prop(properties, "sod");
					break;
				case SlideOutType.PickSlideDown:
					Atnf.prop(properties, "psd");
					break;
				case SlideOutType.PickSlideUp:
					Atnf.prop(properties, "psu");
					break;
			}
			if (note.isHammerPullOrigin) Atnf.prop(properties, "h");
			if (note.isLeftHandTapped) Atnf.prop(properties, "lht");
			if (note.isGhost) Atnf.prop(properties, "g");
			switch (note.accentuated) {
				case AccentuationType.Normal:
					Atnf.prop(properties, "ac");
					break;
				case AccentuationType.Heavy:
					Atnf.prop(properties, "hac");
					break;
				case AccentuationType.Tenuto:
					Atnf.prop(properties, "ten");
					break;
			}
			if (note.isPalmMute) Atnf.prop(properties, "pm");
			if (note.isStaccato) Atnf.prop(properties, "st");
			if (note.isLetRing) Atnf.prop(properties, "lr");
			if (note.isDead) Atnf.prop(properties, "x");
			if (note.isTieDestination) Atnf.prop(properties, "t");
			if (note.leftHandFinger >= Fingers.Thumb) Atnf.prop(properties, "lf", Atnf.numberValue(note.leftHandFinger + 1));
			if (note.rightHandFinger >= Fingers.Thumb) Atnf.prop(properties, "rf", Atnf.numberValue(note.rightHandFinger + 1));
			if (!note.isVisible) Atnf.prop(properties, "hide");
			if (note.isSlurOrigin) {
				const slurId = `s${note.id}`;
				Atnf.prop(properties, "slur", Atnf.identValue(slurId));
			}
			if (note.isSlurDestination) {
				const slurId = `s${note.slurOrigin.id}`;
				Atnf.prop(properties, "slur", Atnf.identValue(slurId));
			}
			if (!(note.accidentalMode === NoteAccidentalMode.Default || note.beat.voice.bar.keySignature === KeySignature.C && note.accidentalMode === NoteAccidentalMode.ForceNatural)) Atnf.prop(properties, "acc", Atnf.identValue(ModelUtils.reverseAccidentalModeMapping.get(note.accidentalMode)));
			switch (note.ornament) {
				case NoteOrnament.InvertedTurn:
					Atnf.prop(properties, "iturn");
					break;
				case NoteOrnament.Turn:
					Atnf.prop(properties, "turn");
					break;
				case NoteOrnament.UpperMordent:
					Atnf.prop(properties, "umordent");
					break;
				case NoteOrnament.LowerMordent:
					Atnf.prop(properties, "lmordent");
					break;
			}
			return properties;
		}
		buildBeatEffects(beat) {
			const properties = [];
			switch (beat.fade) {
				case FadeType.FadeIn:
					Atnf.prop(properties, "f");
					break;
				case FadeType.FadeOut:
					Atnf.prop(properties, "fo");
					break;
				case FadeType.VolumeSwell:
					Atnf.prop(properties, "vs");
					break;
			}
			if (beat.vibrato === VibratoType.Slight) Atnf.prop(properties, "v");
			else if (beat.vibrato === VibratoType.Wide) Atnf.prop(properties, "vw");
			if (beat.slap) Atnf.prop(properties, "s");
			if (beat.pop) Atnf.prop(properties, "p");
			if (beat.tap) Atnf.prop(properties, "tt");
			if (beat.dots >= 2) Atnf.prop(properties, "dd");
			else if (beat.dots > 0) Atnf.prop(properties, "d");
			if (beat.pickStroke === PickStroke.Up) Atnf.prop(properties, "su");
			else if (beat.pickStroke === PickStroke.Down) Atnf.prop(properties, "sd");
			if (beat.hasTuplet) Atnf.prop(properties, "tu", Atnf.args([Atnf.number(beat.tupletNumerator), Atnf.number(beat.tupletDenominator)]));
			if (beat.hasWhammyBar) {
				const tbeArgs = Atnf.args([Atnf.ident(AlphaTex1EnumMappings.whammyTypeReversed.get(beat.whammyBarType)), Atnf.ident(AlphaTex1EnumMappings.bendStyleReversed.get(beat.whammyStyle))], true);
				for (const p of beat.whammyBarPoints) {
					tbeArgs.arguments.push(Atnf.number(p.offset));
					tbeArgs.arguments.push(Atnf.number(p.value));
				}
				Atnf.prop(properties, "tbe", tbeArgs);
			}
			let brushType = "";
			switch (beat.brushType) {
				case BrushType.BrushUp:
					brushType = "bu";
					break;
				case BrushType.BrushDown:
					brushType = "bd";
					break;
				case BrushType.ArpeggioUp:
					brushType = "au";
					break;
				case BrushType.ArpeggioDown:
					brushType = "ad";
					break;
			}
			if (brushType) Atnf.prop(properties, brushType, Atnf.numberValue(beat.brushDuration));
			if (beat.chord != null) Atnf.prop(properties, "ch", Atnf.stringValue(beat.chord.name));
			if (beat.ottava !== Ottavia.Regular) Atnf.prop(properties, "ot", Atnf.identValue(AlphaTex1EnumMappings.ottaviaReversed.get(beat.ottava)));
			if (beat.hasRasgueado) Atnf.prop(properties, "rasg", Atnf.identValue(AlphaTex1EnumMappings.rasgueadoReversed.get(beat.rasgueado)));
			if (beat.text != null) Atnf.prop(properties, "txt", Atnf.stringValue(beat.text));
			if (beat.lyrics != null && beat.lyrics.length > 0) if (beat.lyrics.length > 1) for (let i = 0; i < beat.lyrics.length; i++) Atnf.prop(properties, "lyrics", Atnf.args([Atnf.number(i), Atnf.string(beat.lyrics[i])]));
			else Atnf.prop(properties, "lyrics", Atnf.stringValue(beat.lyrics[0]));
			if (beat.graceType !== GraceType.None) Atnf.prop(properties, "gr", beat.graceType === GraceType.BeforeBeat ? void 0 : Atnf.identValue(AlphaTex1EnumMappings.graceTypeReversed.get(beat.graceType)));
			if (beat.isTremolo) {
				const values = [Atnf.number(beat.tremoloPicking.marks)];
				if (beat.tremoloPicking.style !== TremoloPickingStyle.Default) values.push(Atnf.ident(TremoloPickingStyle[beat.tremoloPicking.style]));
				Atnf.prop(properties, "tp", Atnf.args(values));
			}
			switch (beat.crescendo) {
				case CrescendoType.Crescendo:
					Atnf.prop(properties, "cre");
					break;
				case CrescendoType.Decrescendo:
					Atnf.prop(properties, "dec");
					break;
			}
			if (beat.voice.bar.index === 0 && beat.index === 0 || beat.dynamics !== beat.previousBeat?.dynamics) Atnf.prop(properties, "dy", Atnf.identValue(AlphaTex1EnumMappings.dynamicValueReversed.get(beat.dynamics)));
			if (beat.fermata != null) Atnf.prop(properties, "fermata", Atnf.args([Atnf.ident(AlphaTex1EnumMappings.fermataTypeReversed.get(beat.fermata.type)), Atnf.number(beat.fermata.length)]));
			if (beat.isLegatoOrigin) Atnf.prop(properties, "legatoorigin");
			for (const automation of beat.automations) switch (automation.type) {
				case AutomationType.Tempo:
					Atnf.prop(properties, "tempo", Atnf.args([Atnf.number(automation.value), automation.text.length === 0 ? void 0 : Atnf.string(automation.text)]));
					break;
				case AutomationType.Volume:
					Atnf.prop(properties, "volume", Atnf.numberValue(automation.value));
					break;
				case AutomationType.Instrument:
					if (!beat.voice.bar.staff.isPercussion) Atnf.prop(properties, "instrument", Atnf.identValue(GeneralMidi.getName(automation.value)));
					break;
				case AutomationType.Balance:
					Atnf.prop(properties, "balance", Atnf.numberValue(automation.value));
					break;
			}
			switch (beat.wahPedal) {
				case WahPedal.Open:
					Atnf.prop(properties, "waho");
					break;
				case WahPedal.Closed:
					Atnf.prop(properties, "wahc");
					break;
			}
			if (beat.isBarre) Atnf.prop(properties, "barre", Atnf.args([Atnf.number(beat.barreFret), Atnf.ident(AlphaTex1EnumMappings.barreShapeReversed.get(beat.barreShape))]));
			if (beat.slashed) Atnf.prop(properties, "slashed");
			if (beat.deadSlapped) Atnf.prop(properties, "ds");
			switch (beat.golpe) {
				case GolpeType.Thumb:
					Atnf.prop(properties, "glpt");
					break;
				case GolpeType.Finger:
					Atnf.prop(properties, "glpf");
					break;
			}
			if (beat.invertBeamDirection) Atnf.prop(properties, "beam", Atnf.identValue("invert"));
			else if (beat.preferredBeamDirection !== null) Atnf.prop(properties, "beam", Atnf.identValue(BeamDirection[beat.preferredBeamDirection]));
			let beamingModeValue = "";
			switch (beat.beamingMode) {
				case BeatBeamingMode.ForceSplitToNext:
					beamingModeValue = "split";
					break;
				case BeatBeamingMode.ForceMergeWithNext:
					beamingModeValue = "merge";
					break;
				case BeatBeamingMode.ForceSplitOnSecondaryToNext:
					beamingModeValue = "splitsecondary";
					break;
			}
			if (beamingModeValue) Atnf.prop(properties, "beam", Atnf.identValue(beamingModeValue));
			if (beat.showTimer) Atnf.prop(properties, "timer");
			return properties;
		}
	};
	//#endregion
	//#region src/io/IReadable.ts
	/**
	* Thrown whenever we hit the end of input data unexpectedly.
	* @public
	*/
	var EndOfReaderError = class extends AlphaTabError {
		constructor() {
			super(AlphaTabErrorType.Format, "Unexpected end of data within reader");
		}
	};
	/**
	* Thrown whenever an overflow in data or buffer sizes is detected.
	* @public
	*/
	var OverflowError = class extends AlphaTabError {
		constructor(message) {
			super(AlphaTabErrorType.Format, message);
		}
	};
	/**
	* An {@see IReadable} implementation throwing when the end of stream is reached guarding against
	* corrupted or maliciously crafted files leading to endless reading
	* @internal
	*/
	var ThrowingReadable = class {
		_readable;
		constructor(readable) {
			this._readable = readable;
		}
		get position() {
			return this._readable.position;
		}
		set position(value) {
			this._readable.position = value;
		}
		get length() {
			return this._readable.length;
		}
		reset() {
			this._readable.reset();
		}
		skip(offset) {
			this._readable.skip(offset);
		}
		_requireBytes(bytes) {
			if (this.length - this.position < bytes) throw new EndOfReaderError();
		}
		readByte() {
			this._requireBytes(1);
			return this._readable.readByte();
		}
		read(buffer, offset, count) {
			this._requireBytes(count);
			return this._readable.read(buffer, offset, count);
		}
		readAll() {
			return this._readable.readAll();
		}
	};
	//#endregion
	//#region src/importer/ScoreImporter.ts
	/**
	* This is the base public class for creating new song importers which
	* enable reading scores from any binary datasource
	* @public
	*/
	var ScoreImporter = class {
		data;
		settings;
		/**
		* Initializes the importer with the given data and settings.
		*/
		init(data, settings) {
			if (data instanceof ThrowingReadable) this.data = data;
			else this.data = new ThrowingReadable(data);
			this.settings = settings;
			Score.resetIds();
		}
	};
	//#endregion
	//#region src/importer/UnsupportedFormatError.ts
	/**
	* The exception thrown by a {@link ScoreImporter} in case the
	* binary data does not contain a reader compatible structure.
	* @public
	*/
	var UnsupportedFormatError = class extends AlphaTabError {
		constructor(message = null, inner) {
			super(AlphaTabErrorType.Format, message ?? "Unsupported format", inner);
		}
	};
	//#endregion
	//#region src/io/ByteBuffer.ts
	/**
	* @public
	*/
	var ByteBuffer = class ByteBuffer {
		_buffer;
		length = 0;
		position = 0;
		get bytesWritten() {
			return this.position;
		}
		getBuffer() {
			return this._buffer;
		}
		static empty() {
			return ByteBuffer.withCapacity(0);
		}
		static withCapacity(capacity) {
			const buffer = new ByteBuffer();
			buffer._buffer = new Uint8Array(capacity);
			return buffer;
		}
		static fromBuffer(data) {
			const buffer = new ByteBuffer();
			buffer._buffer = data;
			buffer.length = data.length;
			return buffer;
		}
		static fromString(contents) {
			const byteArray = IOHelper.stringToBytes(contents);
			return ByteBuffer.fromBuffer(byteArray);
		}
		reset() {
			this.position = 0;
		}
		skip(offset) {
			this.position += offset;
		}
		readByte() {
			if (this.length - this.position <= 0) return -1;
			return this._buffer[this.position++];
		}
		read(buffer, offset, count) {
			let n = this.length - this.position;
			if (n > count) n = count;
			if (n <= 0) return 0;
			buffer.set(this._buffer.subarray(this.position, this.position + n), offset);
			this.position += n;
			return n;
		}
		writeByte(value) {
			const i = this.position + 1;
			this._ensureCapacity(i);
			this._buffer[this.position] = value & 255;
			if (i > this.length) this.length = i;
			this.position = i;
		}
		write(buffer, offset, count) {
			const i = this.position + count;
			this._ensureCapacity(i);
			const count1 = Math.min(count, buffer.length - offset);
			this._buffer.set(buffer.subarray(offset, offset + count1), this.position);
			if (i > this.length) this.length = i;
			this.position = i;
		}
		_ensureCapacity(value) {
			if (value > this._buffer.length) {
				let newCapacity = value;
				if (newCapacity < 256) newCapacity = 256;
				if (newCapacity < this._buffer.length * 2) newCapacity = this._buffer.length * 2;
				const newBuffer = new Uint8Array(newCapacity);
				if (this.length > 0) newBuffer.set(this._buffer.subarray(0, 0 + this.length), 0);
				this._buffer = newBuffer;
			}
		}
		readAll() {
			return this.toArray();
		}
		toArray() {
			const copy = new Uint8Array(this.length);
			copy.set(this._buffer.subarray(0, 0 + this.length), 0);
			return copy;
		}
		copyTo(destination) {
			destination.write(this._buffer, 0, this.length);
		}
	};
	//#endregion
	//#region src/importer/AlphaTexImporter.ts
	/**
	* @public
	*/
	var AlphaTexErrorWithDiagnostics = class AlphaTexErrorWithDiagnostics extends AlphaTabError {
		lexerDiagnostics;
		parserDiagnostics;
		semanticDiagnostics;
		*iterateDiagnostics() {
			if (this.lexerDiagnostics) for (const d of this.lexerDiagnostics.items) yield d;
			if (this.parserDiagnostics) for (const d of this.parserDiagnostics.items) yield d;
			if (this.semanticDiagnostics) for (const d of this.semanticDiagnostics.items) yield d;
		}
		constructor(message, lexerDiagnostics, parserDiagnostics, semanticDiagnostics) {
			super(AlphaTabErrorType.AlphaTex, message);
			this.lexerDiagnostics = lexerDiagnostics;
			this.parserDiagnostics = parserDiagnostics;
			this.semanticDiagnostics = semanticDiagnostics;
		}
		toString() {
			return [
				this.message,
				"lexer diagnostics:",
				AlphaTexErrorWithDiagnostics._diagnosticsToString(this.lexerDiagnostics, "  "),
				"parser diagnostics:",
				AlphaTexErrorWithDiagnostics._diagnosticsToString(this.parserDiagnostics, "  "),
				"semantic diagnostics:",
				AlphaTexErrorWithDiagnostics._diagnosticsToString(this.semanticDiagnostics, "  ")
			].join("\n");
		}
		static _diagnosticsToString(semanticDiagnostics, indent) {
			if (!semanticDiagnostics) return `${indent}none`;
			return semanticDiagnostics.items.map((d) => `${indent}${AlphaTexDiagnosticsSeverity[d.severity]} AT${d.code.toString().padStart(3, "0")}${AlphaTexErrorWithDiagnostics._locationToString(d)}: ${d.message}`).join("\n");
		}
		static _locationToString(d) {
			let s = "";
			if (d.start) s += `(${d.start.line},${d.start.col})`;
			if (d.end) {
				if (s.length > 0) s += "->";
				s += `(${d.end.line},${d.end.col})`;
			}
			return s;
		}
	};
	/**
	* @internal
	*/
	var AlphaTexImportState = class {
		trackChannel = 0;
		score;
		currentTrack;
		currentStaff;
		barIndex = 0;
		voiceIndex = 0;
		ignoredInitialVoice = false;
		ignoredInitialStaff = false;
		ignoredInitialTrack = false;
		currentDuration = Duration.Quarter;
		articulationUniqueIdToIndex = /* @__PURE__ */ new Map();
		hasAnyProperData = false;
		percussionArticulationNames = /* @__PURE__ */ new Map();
		slurs = /* @__PURE__ */ new Map();
		lyrics = /* @__PURE__ */ new Map();
		sustainPedalToBeat = /* @__PURE__ */ new Map();
		staffTuningApplied = /* @__PURE__ */ new Set();
		staffNoteKind = /* @__PURE__ */ new Map();
		staffHasExplicitTuning = /* @__PURE__ */ new Set();
		staffHasExplicitDisplayTransposition = /* @__PURE__ */ new Set();
		staffDisplayTranspositionApplied = /* @__PURE__ */ new Set();
		staffInitialClef = /* @__PURE__ */ new Map();
		syncPoints = [];
		currentDynamics = DynamicValue.F;
		accidentalMode = AlphaTexAccidentalMode.Explicit;
		voiceMode = AlphaTexVoiceMode.StaffWise;
		currentTupletNumerator = -1;
		currentTupletDenominator = -1;
		scoreNode;
	};
	/**
	* @public
	*/
	var AlphaTexImporter = class extends ScoreImporter {
		_parser;
		_handler = AlphaTex1LanguageHandler.instance;
		_state = new AlphaTexImportState();
		get state() {
			return this._state;
		}
		get scoreNode() {
			return this._state.scoreNode;
		}
		get name() {
			return "AlphaTex";
		}
		get lexerDiagnostics() {
			return this._parser.lexerDiagnostics;
		}
		get parserDiagnostics() {
			return this._parser.parserDiagnostics;
		}
		/**
		* The underlying parser used for parsing the AST. Available after initialization of the importer.
		*/
		get parser() {
			return this._parser;
		}
		get parseMode() {
			return this._parser.mode;
		}
		logErrors = false;
		semanticDiagnostics = new AlphaTexDiagnosticBag();
		addSemanticDiagnostic(diagnostic) {
			this.semanticDiagnostics.push(diagnostic);
		}
		initFromString(tex, settings) {
			this.data = ByteBuffer.empty();
			this._parser = new AlphaTexParser(tex);
			this.settings = settings;
			Score.resetIds();
		}
		readScore() {
			this._state = new AlphaTexImportState();
			this._createDefaultScore();
			if (this.data.length > 0) this._parser = new AlphaTexParser(IOHelper.toString(this.data.readAll(), this.settings.importer.encoding));
			let scoreNode;
			try {
				scoreNode = this._parser.read();
				this._state.scoreNode = scoreNode;
			} catch (e) {
				if (this.logErrors) Logger.error("AlphaTex", `Error while parsing alphaTex: ${e.toString()}`);
				throw new UnsupportedFormatError("Error parsing alphaTex, check inner error for details", e);
			}
			if (this._parser.parserDiagnostics.hasErrors || this._parser.lexer.lexerDiagnostics.hasErrors) {
				const error = new AlphaTexErrorWithDiagnostics("There are errors in the parsed alphaTex, check the diagnostics for details", this.lexerDiagnostics, this.parserDiagnostics, this.semanticDiagnostics);
				if (this.logErrors) Logger.error("AlphaTex", `Error while parsing alphaTex: ${error.toString()}`);
				throw new UnsupportedFormatError("Error parsing alphaTex, check diagnostics on inner error for details", error);
			}
			this._bars(scoreNode);
			if (this.semanticDiagnostics.hasErrors) if (this._state.hasAnyProperData) {
				const error = new AlphaTexErrorWithDiagnostics("There are errors in the parsed alphaTex, check the diagnostics for details", this.lexerDiagnostics, this.parserDiagnostics, this.semanticDiagnostics);
				if (this.logErrors) Logger.error("AlphaTex", `Error while parsing alphaTex: ${error.toString()}`);
				throw error;
			} else throw new UnsupportedFormatError("No alphaTex data found");
			ModelUtils.consolidate(this._state.score);
			this._state.score.finish(this.settings);
			ModelUtils.trimEmptyBarsAtEnd(this._state.score);
			this._state.score.rebuildRepeatGroups();
			this._state.score.applyFlatSyncPoints(this._state.syncPoints);
			for (const [track, lyrics] of this._state.lyrics) this._state.score.tracks[track].applyLyrics(lyrics);
			for (const [sustainPedal, beat] of this._state.sustainPedalToBeat) if (sustainPedal.ratioPosition < 1) {
				const duration = beat.voice.bar.masterBar.calculateDuration();
				sustainPedal.ratioPosition = beat.playbackStart / duration;
			}
			return this._state.score;
		}
		_createDefaultScore() {
			this._state.score = new Score();
			this._newTrack();
		}
		_newTrack() {
			this._state.currentTrack = new Track();
			this._state.currentTrack.ensureStaveCount(1);
			this._state.currentTrack.playbackInfo.program = 25;
			this._state.currentTrack.playbackInfo.primaryChannel = this._state.trackChannel++;
			this._state.currentTrack.playbackInfo.secondaryChannel = this._state.trackChannel++;
			const staff = this._state.currentTrack.staves[0];
			staff.displayTranspositionPitch = 0;
			staff.stringTuning = Tuning.getDefaultTuningFor(6);
			this._state.articulationUniqueIdToIndex.clear();
			this._beginStaff(staff);
			this._state.score.addTrack(this._state.currentTrack);
			this._state.lyrics.set(this._state.currentTrack.index, []);
			this._state.currentDynamics = DynamicValue.F;
			this._state.currentTupletDenominator = -1;
			this._state.currentTupletNumerator = -1;
		}
		_beginStaff(staff) {
			if (this._state.currentStaff) {
				this._detectTuningForStaff(this._state.currentStaff);
				this._handleTransposition(this._state.currentStaff);
			}
			this._state.currentStaff = staff;
			this._state.slurs.clear();
			this._state.barIndex = 0;
			this._state.voiceIndex = 0;
		}
		_bars(node) {
			if (node.bars.length > 0) {
				let previousBarCompleted = false;
				for (const b of node.bars) {
					this._bar(b, previousBarCompleted);
					switch (this.state.voiceMode) {
						case AlphaTexVoiceMode.StaffWise:
							this._state.barIndex++;
							previousBarCompleted = true;
							break;
						case AlphaTexVoiceMode.BarWise:
							if (b.pipe) {
								this._state.barIndex++;
								this._state.voiceIndex = 0;
								this._state.ignoredInitialVoice = false;
								previousBarCompleted = true;
							}
							break;
					}
				}
			} else {
				this._getBar(this._state.currentStaff);
				this._detectTuningForStaff(this._state.currentStaff);
				this._handleTransposition(this._state.currentStaff);
			}
		}
		_bar(node, previousBarCompleted) {
			const bar = this._barMeta(node, previousBarCompleted);
			this._detectTuningForStaff(this._state.currentStaff);
			this._handleTransposition(this._state.currentStaff);
			if (bar.index === 0 && this._state.staffInitialClef.has(this._state.currentStaff)) bar.clef = this._state.staffInitialClef.get(this._state.currentStaff);
			const voice = bar.voices[this._state.voiceIndex];
			for (const b of node.beats) this._beat(voice, b);
			if (voice.beats.length === 0) {
				const emptyBeat = new Beat();
				emptyBeat.isEmpty = true;
				voice.addBeat(emptyBeat);
			}
		}
		_beat(voice, node) {
			if (node.durationChange) this._beatDuration(node.durationChange);
			if (!node.notes && !node.rest) return;
			const beat = new Beat();
			voice.addBeat(beat);
			if (node.notes) for (const n of node.notes.notes) this._note(beat, n);
			else if (node.rest) {}
			if (node.durationValue) this._state.currentDuration = this._parseDuration(node.durationValue);
			beat.duration = this._state.currentDuration;
			beat.dynamics = this._state.currentDynamics;
			if (this._state.currentTupletNumerator !== -1 && !beat.hasTuplet) {
				beat.tupletNumerator = this._state.currentTupletNumerator;
				beat.tupletDenominator = this._state.currentTupletDenominator;
			}
			let beatRepeat = 1;
			if (node.beatMultiplierValue !== void 0) beatRepeat = node.beatMultiplierValue.value;
			if (node.beatEffects) this._beatEffects(beat, node.beatEffects);
			for (let i = 0; i < beatRepeat - 1; i++) voice.addBeat(BeatCloner.clone(beat));
		}
		_beatEffects(beat, node) {
			for (const p of node.properties) switch (this._handler.applyBeatProperty(this, beat, p)) {
				case ApplyNodeResult.Applied:
				case ApplyNodeResult.NotAppliedSemanticError:
					this._state.hasAnyProperData = true;
					break;
				case ApplyNodeResult.NotAppliedUnrecognizedMarker:
					const knownProps = Array.from(this._handler.knownBeatProperties).join(",");
					this.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT212,
						message: `Unrecogized property '${p.property.text}', expected one of ${knownProps}`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: p.start,
						end: p.end
					});
					break;
			}
		}
		_beatDuration(node) {
			if (node.value) this._state.currentDuration = this._parseDuration(node.value);
			this._state.currentTupletNumerator = -1;
			this._state.currentTupletDenominator = -1;
			if (node.properties) for (const p of node.properties.properties) switch (this._handler.applyBeatDurationProperty(this, p)) {
				case ApplyNodeResult.Applied:
				case ApplyNodeResult.NotAppliedSemanticError:
					this._state.hasAnyProperData = true;
					break;
				case ApplyNodeResult.NotAppliedUnrecognizedMarker:
					const knownProps = Array.from(this._handler.knownBeatDurationProperties).join(",");
					this.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT212,
						message: `Unrecogized property '${p.property.text}', expected one of ${knownProps}`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: p.start,
						end: p.end
					});
					break;
			}
		}
		_parseDuration(duration) {
			switch (duration.value) {
				case -4: return Duration.QuadrupleWhole;
				case -2: return Duration.DoubleWhole;
				case 1: return Duration.Whole;
				case 2: return Duration.Half;
				case 4: return Duration.Quarter;
				case 8: return Duration.Eighth;
				case 16: return Duration.Sixteenth;
				case 32: return Duration.ThirtySecond;
				case 64: return Duration.SixtyFourth;
				case 128: return Duration.OneHundredTwentyEighth;
				case 256: return Duration.TwoHundredFiftySixth;
				default:
					this.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT209,
						message: `Unexpected duration value '${duration.value}', expected: -4, -2, 1, 2, 4, 8, 16, 32, 64, 128 or 256`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: duration.start,
						end: duration.end
					});
					return this._state.currentDuration;
			}
		}
		_note(beat, node) {
			let isDead = false;
			let isTie = false;
			let numericValue = -1;
			let articulationValue = "";
			let octave = -1;
			let tone = -1;
			let accidentalMode = NoteAccidentalMode.Default;
			const noteValue = node.noteValue;
			let detectedNoteKind = void 0;
			let staffNoteKind = this._state.staffNoteKind.has(this._state.currentStaff) ? this._state.staffNoteKind.get(this._state.currentStaff) : void 0;
			switch (noteValue.nodeType) {
				case AlphaTexNodeType.Number:
					numericValue = noteValue.value;
					if (node.noteString !== void 0) detectedNoteKind = AlphaTexStaffNoteKind.Fretted;
					else detectedNoteKind = AlphaTexStaffNoteKind.Articulation;
					break;
				case AlphaTexNodeType.String:
				case AlphaTexNodeType.Ident:
					const str = noteValue.text;
					isDead = str === "x";
					isTie = str === "-";
					if (isTie || isDead) {
						numericValue = 0;
						if (node.noteStringDot && node.noteString) detectedNoteKind = AlphaTexStaffNoteKind.Fretted;
						else detectedNoteKind = void 0;
					} else {
						const tuning = ModelUtils.parseTuning(str);
						if (tuning) {
							detectedNoteKind = AlphaTexStaffNoteKind.Pitched;
							octave = tuning.octave;
							tone = tuning.tone.noteValue;
							if (this._state.accidentalMode === AlphaTexAccidentalMode.Explicit) accidentalMode = tuning.tone.accidentalMode;
						} else {
							detectedNoteKind = AlphaTexStaffNoteKind.Articulation;
							const articulationName = str.toLowerCase();
							const percussionArticulationNames = this._state.percussionArticulationNames;
							if (staffNoteKind === void 0 && percussionArticulationNames.size === 0) {
								for (const [defaultName, defaultValue] of PercussionMapper.instrumentArticulationNames) if (PercussionMapper.getInstrumentArticulationByUniqueId(defaultValue)) {
									percussionArticulationNames.set(defaultName.toLowerCase(), defaultValue);
									percussionArticulationNames.set(ModelUtils.toArticulationId(defaultName), defaultValue);
								}
							}
							if (percussionArticulationNames.has(articulationName)) articulationValue = percussionArticulationNames.get(articulationName);
							else {
								this.addSemanticDiagnostic({
									code: AlphaTexDiagnosticCode.AT209,
									message: `Unexpected percussion articulation value '${articulationName}', expected: oneOf(${Array.from(this._state.percussionArticulationNames.keys()).join(",")}).`,
									severity: AlphaTexDiagnosticsSeverity.Error,
									start: noteValue.start,
									end: noteValue.end
								});
								articulationValue = Array.from(PercussionMapper.instrumentArticulationNames.values())[0];
								return;
							}
						}
					}
					break;
			}
			if (detectedNoteKind !== void 0) {
				if (staffNoteKind === void 0) {
					staffNoteKind = detectedNoteKind;
					this.applyStaffNoteKind(this._state.currentStaff, staffNoteKind);
				} else if (staffNoteKind !== detectedNoteKind) this.addSemanticDiagnostic({
					code: AlphaTexDiagnosticCode.AT218,
					message: `Wrong note kind '${AlphaTexStaffNoteKind[detectedNoteKind]}' for staff with note kind ''${AlphaTexStaffNoteKind[staffNoteKind]}'. Do not mix incompatible staves and notes.`,
					severity: AlphaTexDiagnosticsSeverity.Error,
					start: noteValue.start,
					end: noteValue.end
				});
			} else if (staffNoteKind !== void 0) detectedNoteKind = staffNoteKind;
			const note = new Note();
			note.isDead = isDead;
			if (isDead || isTie) note.fret = numericValue;
			note.isTieDestination = isTie;
			if (detectedNoteKind !== void 0 && detectedNoteKind === staffNoteKind) switch (detectedNoteKind) {
				case AlphaTexStaffNoteKind.Pitched:
					note.octave = octave;
					note.tone = tone;
					note.accidentalMode = accidentalMode;
					break;
				case AlphaTexStaffNoteKind.Fretted:
					if (!node.noteString) {
						this.addSemanticDiagnostic({
							code: AlphaTexDiagnosticCode.AT207,
							message: `Missing string for fretted note.`,
							severity: AlphaTexDiagnosticsSeverity.Error,
							start: noteValue.end,
							end: noteValue.end
						});
						return;
					}
					const noteString = node.noteString.value;
					if (noteString < 1 || noteString > this._state.currentStaff.tuning.length) {
						this.addSemanticDiagnostic({
							code: AlphaTexDiagnosticCode.AT208,
							message: `Note string is out of range. Available range: 1-${this._state.currentStaff.tuning.length}`,
							severity: AlphaTexDiagnosticsSeverity.Error,
							start: noteValue.end,
							end: noteValue.end
						});
						return;
					}
					note.string = this._state.currentStaff.tuning.length - (noteString - 1);
					if (!isTie) note.fret = numericValue;
					break;
				case AlphaTexStaffNoteKind.Articulation:
					let articulationIndex = 0;
					if (articulationValue.length === 0 && numericValue > 0) {
						const byId = PercussionMapper.getArticulationById(numericValue);
						if (byId) articulationValue = byId.uniqueId;
					}
					if (this._state.articulationUniqueIdToIndex.has(articulationValue)) articulationIndex = this._state.articulationUniqueIdToIndex.get(articulationValue);
					else {
						articulationIndex = this._state.currentTrack.percussionArticulations.length;
						const articulation = PercussionMapper.getInstrumentArticulationByUniqueId(articulationValue);
						if (articulation === null) {
							this.addSemanticDiagnostic({
								code: AlphaTexDiagnosticCode.AT209,
								message: `Unexpected articulation value '${numericValue}', expected: oneOf(${Array.from(PercussionMapper.instrumentArticulations.keys()).join(",")}).`,
								severity: AlphaTexDiagnosticsSeverity.Error,
								start: noteValue.end,
								end: noteValue.end
							});
							return;
						}
						this._state.currentTrack.percussionArticulations.push(articulation);
						this._state.articulationUniqueIdToIndex.set(articulationValue, articulationIndex);
					}
					note.percussionArticulation = articulationIndex;
					break;
			}
			beat.addNote(note);
			this._state.hasAnyProperData = true;
			if (node.noteEffects) this._noteEffects(note, node.noteEffects);
		}
		/**
		* @internal
		*/
		getStaffNoteKind(staff) {
			return this._state.staffNoteKind.has(staff) ? this._state.staffNoteKind.get(staff) : void 0;
		}
		applyStaffNoteKind(staff, staffNoteKind) {
			this._state.staffNoteKind.set(staff, staffNoteKind);
			switch (staffNoteKind) {
				case AlphaTexStaffNoteKind.Pitched:
					staff.isPercussion = false;
					staff.stringTuning.reset();
					if (!this._state.staffHasExplicitDisplayTransposition.has(staff)) staff.displayTranspositionPitch = 0;
					break;
				case AlphaTexStaffNoteKind.Fretted:
					staff.isPercussion = false;
					this._detectTuningForStaff(staff);
					this._handleTransposition(staff);
					break;
				case AlphaTexStaffNoteKind.Articulation:
					staff.isPercussion = true;
					staff.stringTuning.reset();
					if (!this._state.staffHasExplicitDisplayTransposition.has(staff)) staff.displayTranspositionPitch = 0;
					break;
			}
		}
		_noteEffects(note, node) {
			for (const p of node.properties) {
				let result = this._handler.applyNoteProperty(this, note, p);
				if (result === ApplyNodeResult.NotAppliedUnrecognizedMarker) result = this._handler.applyBeatProperty(this, note.beat, p);
				switch (result) {
					case ApplyNodeResult.Applied:
					case ApplyNodeResult.NotAppliedSemanticError: break;
					case ApplyNodeResult.NotAppliedUnrecognizedMarker:
						const knownProps = Array.from(this._handler.knownNoteProperties).concat(Array.from(this._handler.knownBeatProperties)).join(",");
						this.addSemanticDiagnostic({
							code: AlphaTexDiagnosticCode.AT212,
							message: `Unrecogized property '${p.property.text}', expected one of ${knownProps}`,
							severity: AlphaTexDiagnosticsSeverity.Error,
							start: p.start,
							end: p.end
						});
						break;
				}
			}
		}
		_handleTransposition(staff) {
			if (!this._state.staffDisplayTranspositionApplied.has(staff) && !this._state.staffHasExplicitDisplayTransposition.has(staff)) {
				const program = staff.track.playbackInfo.program;
				if (ModelUtils.displayTranspositionPitches.has(program)) staff.displayTranspositionPitch = ModelUtils.displayTranspositionPitches.get(program);
				else this._state.currentStaff.displayTranspositionPitch = 0;
				this._state.staffDisplayTranspositionApplied.add(staff);
			}
		}
		_detectTuningForStaff(staff) {
			const program = staff.track.playbackInfo.program;
			if (!this._state.staffTuningApplied.has(staff) && !this._state.staffHasExplicitTuning.has(staff)) {
				staff.stringTuning.reset();
				if (program === 15) staff.stringTuning.tunings = Tuning.getDefaultTuningFor(6).tunings;
				else if (program >= 24 && program <= 31) staff.stringTuning.tunings = Tuning.getDefaultTuningFor(6).tunings;
				else if (program >= 32 && program <= 39) {
					staff.stringTuning.tunings = [
						43,
						38,
						33,
						28
					];
					this._state.staffInitialClef.set(staff, Clef.F4);
				} else if (program === 40 || program === 44 || program === 45 || program === 48 || program === 49 || program === 50 || program === 51) staff.stringTuning.tunings = [
					52,
					57,
					50,
					43
				];
				else if (program === 41) staff.stringTuning.tunings = [
					57,
					50,
					43,
					36
				];
				else if (program === 42) staff.stringTuning.tunings = [
					45,
					38,
					31,
					24
				];
				else if (program === 43) staff.stringTuning.tunings = [
					43,
					38,
					33,
					28
				];
				else if (program === 105) staff.stringTuning.tunings = [
					50,
					47,
					43,
					38,
					55
				];
				else if (program === 106) staff.stringTuning.tunings = [
					57,
					52,
					45
				];
				else if (program === 107) staff.stringTuning.tunings = [
					52,
					45,
					38,
					31
				];
				else if (program === 110) staff.stringTuning.tunings = [
					64,
					57,
					50,
					43
				];
				else if (this._state.staffNoteKind.has(staff) && this._state.staffNoteKind.get(staff) === AlphaTexStaffNoteKind.Fretted) staff.stringTuning = Tuning.getDefaultTuningFor(6);
				this._state.staffTuningApplied.add(staff);
			}
		}
		_barMeta(node, previousBarCompleted) {
			let initialBarMeta = this._state.score.masterBars.length > 0 ? void 0 : [];
			let previousStaff = this._state.currentStaff;
			let hadNewTrack = false;
			let hadNewStaff = false;
			let hadNewVoice = false;
			let applyInitialBarMetaToPreviousStaff = false;
			const resetInitialBarMeta = () => {
				if (!initialBarMeta) return;
				initialBarMeta = void 0;
				previousStaff = this._state.currentStaff;
				hadNewTrack = false;
				hadNewStaff = false;
				hadNewVoice = false;
				applyInitialBarMetaToPreviousStaff = false;
			};
			const bar = new Lazy(() => {
				if (!hadNewVoice && !previousBarCompleted) this._state.barIndex++;
				const b = this._getBar(this._state.currentStaff);
				if (initialBarMeta) {
					for (const initial of initialBarMeta) this._handler.applyBarMetaData(this, b, initial);
					resetInitialBarMeta();
				}
				return b;
			});
			for (const m of node.metaData) {
				const tag = m.tag.tag.text.toLowerCase();
				if (this._handler.knownStructuralMetaDataTags.has(tag)) {
					this._state.hasAnyProperData = true;
					switch (this._handler.applyStructuralMetaData(this, m)) {
						case ApplyStructuralMetaDataResult.AppliedNewTrack:
							if (hadNewStaff) applyInitialBarMetaToPreviousStaff = true;
							else if (hadNewTrack) applyInitialBarMetaToPreviousStaff = true;
							else {
								hadNewTrack = true;
								previousStaff = this._state.currentStaff;
							}
							bar.reset();
							break;
						case ApplyStructuralMetaDataResult.AppliedNewStaff:
							if (hadNewStaff) applyInitialBarMetaToPreviousStaff = true;
							else {
								hadNewStaff = true;
								previousStaff = this._state.currentStaff;
							}
							bar.reset();
							break;
						case ApplyStructuralMetaDataResult.AppliedNewVoice:
							hadNewVoice = true;
							break;
					}
					if (initialBarMeta) {
						if (applyInitialBarMetaToPreviousStaff) if (previousStaff.bars.length === 0) {
							const initialBar = new Bar();
							previousStaff.addBar(initialBar);
							const initialVoice = new Voice$1();
							initialBar.addVoice(initialVoice);
							if (previousStaff.bars.length > this._state.score.masterBars.length) {
								const master = new MasterBar();
								this._state.score.addMasterBar(master);
							}
							for (const initial of initialBarMeta) this._handler.applyBarMetaData(this, initialBar, initial);
							resetInitialBarMeta();
						} else throw new AlphaTabError(AlphaTabErrorType.AlphaTex, `Unexpected internal error, didn't expect a filled staff after multiple \\track and/or \\staff tags. Please report this problem providing the input alphaTex.`);
					}
				} else if (this._handler.knownScoreMetaDataTags.has(m.tag.tag.text.toLowerCase())) {
					this._state.hasAnyProperData = true;
					this._handler.applyScoreMetaData(this, this._state.score, m);
				} else if (this._handler.knownStaffMetaDataTags.has(m.tag.tag.text.toLowerCase())) {
					this._state.hasAnyProperData = true;
					this._handler.applyStaffMetaData(this, this._state.currentStaff, m);
				} else if (this._handler.knownBarMetaDataTags.has(m.tag.tag.text.toLowerCase())) {
					this._state.hasAnyProperData = true;
					if (initialBarMeta) initialBarMeta.push(m);
					else this._handler.applyBarMetaData(this, bar.value, m);
				} else {
					const knownMeta = Array.from(this._handler.allKnownMetaDataTags).join(",");
					this.addSemanticDiagnostic({
						code: AlphaTexDiagnosticCode.AT204,
						message: `Unrecognized metadata '${m.tag.tag.text}', expected one of: ${knownMeta}`,
						severity: AlphaTexDiagnosticsSeverity.Error,
						start: m.tag.start,
						end: m.tag.end
					});
				}
			}
			return bar.value;
		}
		_getBar(staff) {
			if (this._state.barIndex < staff.bars.length) return staff.bars[this._state.barIndex];
			const voiceCount = staff.bars.length === 0 ? this._state.voiceIndex + 1 : staff.bars[0].voices.length;
			const newBar = new Bar();
			staff.addBar(newBar);
			if (newBar.previousBar) {
				newBar.clef = newBar.previousBar.clef;
				newBar.clefOttava = newBar.previousBar.clefOttava;
				newBar.keySignature = newBar.previousBar.keySignature;
				newBar.keySignatureType = newBar.previousBar.keySignatureType;
			}
			this._state.barIndex = newBar.index;
			if (newBar.index > 0) newBar.clef = newBar.previousBar.clef;
			for (let i = 0; i < voiceCount; i++) {
				const voice = new Voice$1();
				newBar.addVoice(voice);
			}
			if (this._state.currentStaff.bars.length > this._state.score.masterBars.length) {
				const master = new MasterBar();
				this._state.score.addMasterBar(master);
				if (master.index > 0) {
					master.timeSignatureDenominator = master.previousMasterBar.timeSignatureDenominator;
					master.timeSignatureNumerator = master.previousMasterBar.timeSignatureNumerator;
					master.tripletFeel = master.previousMasterBar.tripletFeel;
				}
			}
			return newBar;
		}
		startNewStaff() {
			this._state.ignoredInitialVoice = false;
			if (this._state.ignoredInitialStaff || this._state.currentTrack.staves[0].bars.length > 0) {
				const previousWasPercussion = this._state.currentStaff.isPercussion;
				this._state.currentTrack.ensureStaveCount(this._state.currentTrack.staves.length + 1);
				const staff = this._state.currentTrack.staves[this._state.currentTrack.staves.length - 1];
				this._beginStaff(staff);
				if (previousWasPercussion) this.applyPercussionStaff(this._state.currentStaff);
				this._state.currentDynamics = DynamicValue.F;
			} else this._state.ignoredInitialStaff = true;
			return this._state.currentStaff;
		}
		applyPercussionStaff(staff) {
			staff.isPercussion = true;
			staff.showTablature = false;
			staff.track.playbackInfo.program = 0;
		}
		startNewTrack() {
			this._state.ignoredInitialVoice = false;
			this._state.ignoredInitialStaff = false;
			if (this._state.ignoredInitialTrack || this._state.score.masterBars.length > 0) this._newTrack();
			else this._state.ignoredInitialTrack = true;
			return this._state.currentTrack;
		}
		startNewVoice() {
			let shouldIgnoreInitialVoice = this._state.voiceIndex === 0 && !this._state.ignoredInitialVoice;
			if (shouldIgnoreInitialVoice) if (this._state.currentStaff.bars.length === 0) shouldIgnoreInitialVoice = true;
			else switch (this._state.voiceMode) {
				case AlphaTexVoiceMode.StaffWise:
					shouldIgnoreInitialVoice = this._state.currentStaff.bars.length === 1 && this._state.currentStaff.bars[0].isEmpty;
					break;
				case AlphaTexVoiceMode.BarWise:
					if (this._state.barIndex < this._state.currentStaff.bars.length) shouldIgnoreInitialVoice = this._state.currentStaff.bars[this._state.barIndex].voices[0].isEmpty;
					else shouldIgnoreInitialVoice = true;
					break;
			}
			if (shouldIgnoreInitialVoice) {
				this._state.ignoredInitialVoice = true;
				return;
			}
			switch (this._state.voiceMode) {
				case AlphaTexVoiceMode.StaffWise:
					this._state.voiceIndex++;
					this._state.barIndex = 0;
					this._state.currentTupletDenominator = -1;
					this._state.currentTupletNumerator = -1;
					break;
				case AlphaTexVoiceMode.BarWise:
					this._state.voiceIndex++;
					this._state.currentTupletDenominator = -1;
					this._state.currentTupletNumerator = -1;
					break;
			}
			for (const b of this._state.currentStaff.bars) while (b.voices.length <= this._state.voiceIndex) b.addVoice(new Voice$1());
		}
	};
	//#endregion
	//#region src/zip/Huffman.ts
	/**
	* @internal
	*/
	var Huffman$1 = class {};
	/**
	* @internal
	*/
	var Found = class extends Huffman$1 {
		n;
		constructor(n) {
			super();
			this.n = n;
		}
	};
	/**
	* @internal
	*/
	var NeedBit = class extends Huffman$1 {
		left;
		right;
		constructor(left, right) {
			super();
			this.left = left;
			this.right = right;
		}
	};
	/**
	* @internal
	*/
	var NeedBits = class extends Huffman$1 {
		n;
		table;
		constructor(n, table) {
			super();
			this.n = n;
			this.table = table;
		}
	};
	//#endregion
	//#region src/zip/HuffTools.ts
	/**
	* @internal
	*/
	var HuffTools = class HuffTools {
		static make(lengths, pos, nlengths, maxbits) {
			const counts = [];
			const tmp = [];
			if (maxbits > 32) throw new FormatError("Invalid huffman");
			for (let i = 0; i < maxbits; i++) {
				counts.push(0);
				tmp.push(0);
			}
			for (let i = 0; i < nlengths; i++) {
				const p = lengths[i + pos];
				if (p >= maxbits) throw new FormatError("Invalid huffman");
				counts[p]++;
			}
			let code = 0;
			for (let i = 1; i < maxbits - 1; i++) {
				code = code + counts[i] << 1;
				tmp[i] = code;
			}
			const bits = /* @__PURE__ */ new Map();
			for (let i = 0; i < nlengths; i++) {
				const l = lengths[i + pos];
				if (l !== 0) {
					const n = tmp[l - 1];
					tmp[l - 1] = n + 1;
					bits.set(n << 5 | l, i);
				}
			}
			return HuffTools._treeCompress(new NeedBit(HuffTools._treeMake(bits, maxbits, 0, 1), HuffTools._treeMake(bits, maxbits, 1, 1)));
		}
		static _treeMake(bits, maxbits, v, len) {
			if (len > maxbits) throw new FormatError("Invalid huffman");
			const idx = v << 5 | len;
			if (bits.has(idx)) return new Found(bits.get(idx));
			v = v << 1;
			len += 1;
			return new NeedBit(HuffTools._treeMake(bits, maxbits, v, len), HuffTools._treeMake(bits, maxbits, v | 1, len));
		}
		static _treeCompress(t) {
			const d = HuffTools._treeDepth(t);
			if (d === 0) return t;
			if (d === 1) {
				if (t instanceof NeedBit) return new NeedBit(HuffTools._treeCompress(t.left), HuffTools._treeCompress(t.right));
				throw new FormatError("assert");
			}
			const size = 1 << d;
			const table = [];
			for (let i = 0; i < size; i++) table.push(new Found(-1));
			HuffTools._treeWalk(table, 0, 0, d, t);
			return new NeedBits(d, table);
		}
		static _treeWalk(table, p, cd, d, t) {
			if (t instanceof NeedBit) if (d > 0) {
				HuffTools._treeWalk(table, p, cd + 1, d - 1, t.left);
				HuffTools._treeWalk(table, p | 1 << cd, cd + 1, d - 1, t.right);
			} else table[p] = HuffTools._treeCompress(t);
			else table[p] = HuffTools._treeCompress(t);
		}
		static _treeDepth(t) {
			if (t instanceof Found) return 0;
			if (t instanceof NeedBits) throw new FormatError("assert");
			if (t instanceof NeedBit) {
				const da = HuffTools._treeDepth(t.left);
				const db = HuffTools._treeDepth(t.right);
				return 1 + (da < db ? da : db);
			}
			return 0;
		}
	};
	//#endregion
	//#region src/zip/Inflate.ts
	/**
	* @internal
	*/
	var InflateWindow = class InflateWindow {
		static _size = 32768;
		static _bufferSize = 65536;
		buffer = new Uint8Array(InflateWindow._bufferSize);
		pos = 0;
		slide() {
			const b = new Uint8Array(InflateWindow._bufferSize);
			this.pos -= InflateWindow._size;
			b.set(this.buffer.subarray(InflateWindow._size, InflateWindow._size + this.pos), 0);
			this.buffer = b;
		}
		addBytes(b, p, len) {
			if (this.pos + len > InflateWindow._bufferSize) this.slide();
			this.buffer.set(b.subarray(p, p + len), this.pos);
			this.pos += len;
		}
		addByte(c) {
			if (this.pos === InflateWindow._bufferSize) this.slide();
			this.buffer[this.pos] = c;
			this.pos++;
		}
		getLastChar() {
			return this.buffer[this.pos - 1];
		}
		available() {
			return this.pos;
		}
	};
	/**
	* @internal
	*/
	var Inflate = class Inflate {
		static _lenExtraBitsTbl = [
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			0,
			1,
			1,
			1,
			1,
			2,
			2,
			2,
			2,
			3,
			3,
			3,
			3,
			4,
			4,
			4,
			4,
			5,
			5,
			5,
			5,
			0,
			-1,
			-1
		];
		static _lenBaseValTbl = [
			3,
			4,
			5,
			6,
			7,
			8,
			9,
			10,
			11,
			13,
			15,
			17,
			19,
			23,
			27,
			31,
			35,
			43,
			51,
			59,
			67,
			83,
			99,
			115,
			131,
			163,
			195,
			227,
			258
		];
		static _distExtraBitsTbl = [
			0,
			0,
			0,
			0,
			1,
			1,
			2,
			2,
			3,
			3,
			4,
			4,
			5,
			5,
			6,
			6,
			7,
			7,
			8,
			8,
			9,
			9,
			10,
			10,
			11,
			11,
			12,
			12,
			13,
			13,
			-1,
			-1
		];
		static _distBaseValTbl = [
			1,
			2,
			3,
			4,
			5,
			7,
			9,
			13,
			17,
			25,
			33,
			49,
			65,
			97,
			129,
			193,
			257,
			385,
			513,
			769,
			1025,
			1537,
			2049,
			3073,
			4097,
			6145,
			8193,
			12289,
			16385,
			24577
		];
		static _codeLengthsPos = [
			16,
			17,
			18,
			0,
			8,
			7,
			9,
			6,
			10,
			5,
			11,
			4,
			12,
			3,
			13,
			2,
			14,
			1,
			15
		];
		static _fixedHuffman = Inflate._buildFixedHuffman();
		static _buildFixedHuffman() {
			const a = [];
			for (let n = 0; n < 288; n++) a.push(n <= 143 ? 8 : n <= 255 ? 9 : n <= 279 ? 7 : 8);
			return HuffTools.make(a, 0, 288, 10);
		}
		_nbits = 0;
		_bits = 0;
		_state = 1;
		_isFinal = false;
		_huffman = Inflate._fixedHuffman;
		_huffdist = null;
		_len = 0;
		_dist = 0;
		_needed = 0;
		_output = null;
		_outpos = 0;
		_input;
		_lengths = [];
		_window = new InflateWindow();
		constructor(readable) {
			this._input = readable;
			for (let i = 0; i < 19; i++) this._lengths.push(-1);
		}
		readBytes(b, pos, len) {
			this._needed = len;
			this._outpos = pos;
			this._output = b;
			if (len > 0) while (this._inflateLoop());
			return len - this._needed;
		}
		_inflateLoop() {
			switch (this._state) {
				case 0:
					const cmf = this._input.readByte();
					if ((cmf & 15) !== 8) throw new FormatError("Invalid data");
					const flg = this._input.readByte();
					const fdict = (flg & 32) !== 0;
					if (((cmf << 8) + flg) % 31 !== 0) throw new FormatError("Invalid data");
					if (fdict) throw new FormatError("Unsupported dictionary");
					this._state = 1;
					return true;
				case 4:
					this._state = 7;
					return true;
				case 7: return false;
				case 1:
					this._isFinal = this._getBit();
					switch (this._getBits(2)) {
						case 0:
							this._len = IOHelper.readUInt16LE(this._input);
							if (IOHelper.readUInt16LE(this._input) !== 65535 - this._len) throw new FormatError("Invalid data");
							this._state = 3;
							const r = this._inflateLoop();
							this._resetBits();
							return r;
						case 1:
							this._huffman = Inflate._fixedHuffman;
							this._huffdist = null;
							this._state = 2;
							return true;
						case 2:
							const hlit = this._getBits(5) + 257;
							const hdist = this._getBits(5) + 1;
							const hclen = this._getBits(4) + 4;
							for (let i = 0; i < hclen; i++) this._lengths[Inflate._codeLengthsPos[i]] = this._getBits(3);
							for (let i = hclen; i < 19; i++) this._lengths[Inflate._codeLengthsPos[i]] = 0;
							this._huffman = HuffTools.make(this._lengths, 0, 19, 8);
							const xlengths = [];
							for (let i = 0; i < hlit + hdist; i++) xlengths.push(0);
							this._inflateLengths(xlengths, hlit + hdist);
							this._huffdist = HuffTools.make(xlengths, hlit, hdist, 16);
							this._huffman = HuffTools.make(xlengths, 0, hlit, 16);
							this._state = 2;
							return true;
						default: throw new FormatError("Invalid data");
					}
				case 3: {
					const rlen = this._len < this._needed ? this._len : this._needed;
					const bytes = IOHelper.readByteArray(this._input, rlen);
					this._len -= rlen;
					this._addBytes(bytes, 0, rlen);
					if (this._len === 0) this._state = this._isFinal ? 4 : 1;
					return this._needed > 0;
				}
				case 6: {
					const rlen = this._len < this._needed ? this._len : this._needed;
					this._addDistOne(rlen);
					this._len -= rlen;
					if (this._len === 0) this._state = 2;
					return this._needed > 0;
				}
				case 5:
					while (this._len > 0 && this._needed > 0) {
						const rdist = this._len < this._dist ? this._len : this._dist;
						const rlen = this._needed < rdist ? this._needed : rdist;
						this._addDist(this._dist, rlen);
						this._len -= rlen;
					}
					if (this._len === 0) this._state = 2;
					return this._needed > 0;
				case 2:
					let n = this._applyHuffman(this._huffman);
					if (n < 256) {
						this._addByte(n);
						return this._needed > 0;
					}
					if (n === 256) {
						this._state = this._isFinal ? 4 : 1;
						return true;
					}
					n = n - 257 & 255;
					let extraBits = Inflate._lenExtraBitsTbl[n];
					if (extraBits === -1) throw new FormatError("Invalid data");
					this._len = Inflate._lenBaseValTbl[n] + this._getBits(extraBits);
					const huffdist = this._huffdist;
					const distCode = !huffdist ? this._getRevBits(5) : this._applyHuffman(huffdist);
					extraBits = Inflate._distExtraBitsTbl[distCode];
					if (extraBits === -1) throw new FormatError("Invalid data");
					this._dist = Inflate._distBaseValTbl[distCode] + this._getBits(extraBits);
					if (this._dist > this._window.available()) throw new FormatError("Invalid data");
					this._state = this._dist === 1 ? 6 : 5;
					return true;
			}
			return false;
		}
		_addDistOne(n) {
			const c = this._window.getLastChar();
			for (let i = 0; i < n; i++) this._addByte(c);
		}
		_addByte(b) {
			this._window.addByte(b);
			this._output[this._outpos] = b;
			this._needed--;
			this._outpos++;
		}
		_addDist(d, len) {
			this._addBytes(this._window.buffer, this._window.pos - d, len);
		}
		_getBit() {
			if (this._nbits === 0) {
				this._nbits = 8;
				this._bits = this._input.readByte();
			}
			const b = (this._bits & 1) === 1;
			this._nbits--;
			this._bits = this._bits >> 1;
			return b;
		}
		_getBits(n) {
			while (this._nbits < n) {
				this._bits = this._bits | this._input.readByte() << this._nbits;
				this._nbits += 8;
			}
			const b = this._bits & (1 << n) - 1;
			this._nbits -= n;
			this._bits = this._bits >> n;
			return b;
		}
		_getRevBits(n) {
			return n === 0 ? 0 : this._getBit() ? 1 << n - 1 | this._getRevBits(n - 1) : this._getRevBits(n - 1);
		}
		_resetBits() {
			this._bits = 0;
			this._nbits = 0;
		}
		_addBytes(b, p, len) {
			this._window.addBytes(b, p, len);
			this._output.set(b.subarray(p, p + len), this._outpos);
			this._needed -= len;
			this._outpos += len;
		}
		_inflateLengths(a, max) {
			let i = 0;
			let prev = 0;
			while (i < max) {
				const n = this._applyHuffman(this._huffman);
				switch (n) {
					case 0:
					case 1:
					case 2:
					case 3:
					case 4:
					case 5:
					case 6:
					case 7:
					case 8:
					case 9:
					case 10:
					case 11:
					case 12:
					case 13:
					case 14:
					case 15:
						prev = n;
						a[i] = n;
						i++;
						break;
					case 16:
						const end = i + 3 + this._getBits(2);
						if (end > max) throw new FormatError("Invalid data");
						while (i < end) {
							a[i] = prev;
							i++;
						}
						break;
					case 17:
						i += 3 + this._getBits(3);
						if (i > max) throw new FormatError("Invalid data");
						break;
					case 18:
						i += 11 + this._getBits(7);
						if (i > max) throw new FormatError("Invalid data");
						break;
					default: throw new FormatError("Invalid data");
				}
			}
		}
		_applyHuffman(h) {
			if (h instanceof Found) return h.n;
			if (h instanceof NeedBit) return this._applyHuffman(this._getBit() ? h.right : h.left);
			if (h instanceof NeedBits) return this._applyHuffman(h.table[this._getBits(h.n)]);
			throw new FormatError("Invalid data");
		}
	};
	//#endregion
	//#region src/zip/ZipEntry.ts
	/**
	* @internal
	*/
	var ZipEntry = class {
		static OptionalDataDescriptorSignature = 134695760;
		static CompressionMethodDeflate = 8;
		static LocalFileHeaderSignature = 67324752;
		static CentralFileHeaderSignature = 33639248;
		static EndOfCentralDirSignature = 101010256;
		fullName;
		fileName;
		data;
		constructor(fullName, data) {
			this.fullName = fullName;
			const i = fullName.lastIndexOf("/");
			this.fileName = i === -1 || i === fullName.length - 1 ? this.fullName : fullName.substr(i + 1);
			this.data = data;
		}
	};
	//#endregion
	//#region src/zip/ZipReader.ts
	/**
	* @internal
	*/
	var ZipReader = class {
		_readable;
		_maxDecodingBufferSize;
		constructor(readable, maxDecodingBufferSize) {
			this._readable = readable;
			this._maxDecodingBufferSize = maxDecodingBufferSize;
		}
		read() {
			const entries = [];
			while (true) {
				const e = this._readEntry();
				if (!e) break;
				entries.push(e);
			}
			return entries;
		}
		_readEntry() {
			const readable = this._readable;
			if (IOHelper.readInt32LE(readable) !== ZipEntry.LocalFileHeaderSignature) return null;
			IOHelper.readUInt16LE(readable);
			const flags = IOHelper.readUInt16LE(readable);
			const compressionMethod = IOHelper.readUInt16LE(readable);
			const compressed = compressionMethod !== 0;
			if (compressed && compressionMethod !== ZipEntry.CompressionMethodDeflate) return null;
			IOHelper.readInt16LE(this._readable);
			IOHelper.readInt16LE(this._readable);
			IOHelper.readInt32LE(readable);
			IOHelper.readInt32LE(readable);
			const uncompressedSize = IOHelper.readInt32LE(readable);
			if (uncompressedSize > this._maxDecodingBufferSize) throw new OverflowError(`Zip contains files exceeding the configured maxDecodingBufferSize`);
			const fileNameLength = IOHelper.readInt16LE(readable);
			if (fileNameLength > this._maxDecodingBufferSize) throw new OverflowError(`Zip contains file names exceeding the configured maxDecodingBufferSize`);
			const extraFieldLength = IOHelper.readInt16LE(readable);
			const fname = IOHelper.toString(IOHelper.readByteArray(readable, fileNameLength), "utf-8");
			readable.skip(extraFieldLength);
			let data;
			if (compressed) {
				const target = ByteBuffer.empty();
				const z = new Inflate(this._readable);
				const buffer = new Uint8Array(65536);
				while (true) {
					const bytes = z.readBytes(buffer, 0, buffer.length);
					target.write(buffer, 0, bytes);
					if (target.length > this._maxDecodingBufferSize) throw new OverflowError(`Zip entry "${fname}" contains data exceeding the configured maxDecodingBufferSize`);
					if (bytes < buffer.length) break;
				}
				data = target.toArray();
			} else data = IOHelper.readByteArray(this._readable, uncompressedSize);
			if ((flags & 8) !== 0) {
				if (IOHelper.readInt32LE(this._readable) === ZipEntry.OptionalDataDescriptorSignature) IOHelper.readInt32LE(this._readable);
				IOHelper.readInt32LE(this._readable);
				IOHelper.readInt32LE(this._readable);
			}
			return new ZipEntry(fname, data);
		}
	};
	//#endregion
	//#region src/xml/XmlNode.ts
	/**
	* @internal
	*/
	var XmlNodeType = /* @__PURE__ */ function(XmlNodeType) {
		XmlNodeType[XmlNodeType["None"] = 0] = "None";
		XmlNodeType[XmlNodeType["Element"] = 1] = "Element";
		XmlNodeType[XmlNodeType["Text"] = 2] = "Text";
		XmlNodeType[XmlNodeType["CDATA"] = 3] = "CDATA";
		XmlNodeType[XmlNodeType["Document"] = 4] = "Document";
		XmlNodeType[XmlNodeType["DocumentType"] = 5] = "DocumentType";
		XmlNodeType[XmlNodeType["Comment"] = 6] = "Comment";
		return XmlNodeType;
	}({});
	/**
	* @internal
	*/
	var XmlNode = class XmlNode {
		nodeType = 0;
		localName = null;
		value = null;
		childNodes = [];
		attributes = /* @__PURE__ */ new Map();
		firstChild = null;
		firstElement = null;
		*childElements() {
			for (const c of this.childNodes) if (c.nodeType === 1) yield c;
		}
		addChild(node) {
			this.childNodes.push(node);
			this.firstChild = node;
			if (node.nodeType === 1 || node.nodeType === 3) this.firstElement = node;
		}
		getAttribute(name, defaultValue = "") {
			if (this.attributes.has(name)) return this.attributes.get(name);
			return defaultValue;
		}
		getElementsByTagName(name, recursive = false) {
			const tags = [];
			this._searchElementsByTagName(this.childNodes, tags, name, recursive);
			return tags;
		}
		_searchElementsByTagName(all, result, name, recursive = false) {
			for (const c of all) {
				if (c && c.nodeType === 1 && c.localName === name) result.push(c);
				if (recursive) this._searchElementsByTagName(c.childNodes, result, name, true);
			}
		}
		findChildElement(name) {
			for (const c of this.childNodes) if (c && c.nodeType === 1 && c.localName === name) return c;
			return null;
		}
		addElement(name) {
			const newNode = new XmlNode();
			newNode.nodeType = 1;
			newNode.localName = name;
			this.addChild(newNode);
			return newNode;
		}
		get innerText() {
			if (this.nodeType === 1 || this.nodeType === 4) {
				if (this.firstElement && this.firstElement.nodeType === 3) return this.firstElement.innerText;
				let txt = "";
				for (const c of this.childNodes) txt += c.innerText?.toString();
				return txt.trim();
			}
			return this.value ?? "";
		}
		set innerText(value) {
			const textNode = new XmlNode();
			textNode.nodeType = 2;
			textNode.value = value;
			this.childNodes = [textNode];
		}
		setCData(s) {
			const textNode = new XmlNode();
			textNode.nodeType = 3;
			textNode.value = s;
			this.childNodes = [textNode];
		}
	};
	//#endregion
	//#region src/xml/XmlError.ts
	/**
	* @internal
	*/
	var XmlError = class extends AlphaTabError {
		xml;
		pos = 0;
		constructor(message, xml, pos) {
			super(AlphaTabErrorType.Format, message);
			this.xml = xml;
			this.pos = pos;
		}
	};
	//#endregion
	//#region src/xml/XmlParser.ts
	/**
	* @internal
	*/
	var XmlParser = class XmlParser {
		static CharCodeLF = 10;
		static CharCodeTab = 9;
		static CharCodeCR = 13;
		static CharCodeSpace = 32;
		static CharCodeLowerThan = 60;
		static CharCodeAmp = 38;
		static CharCodeBrackedClose = 93;
		static CharCodeBrackedOpen = 91;
		static CharCodeGreaterThan = 62;
		static CharCodeExclamation = 33;
		static CharCodeUpperD = 68;
		static CharCodeLowerD = 100;
		static CharCodeMinus = 45;
		static CharCodeQuestion = 63;
		static CharCodeSlash = 47;
		static CharCodeEquals = 61;
		static CharCodeDoubleQuote = 34;
		static CharCodeSingleQuote = 39;
		static CharCodeSharp = 35;
		static CharCodeLowerX = 120;
		static CharCodeLowerA = 97;
		static CharCodeLowerZ = 122;
		static CharCodeUpperA = 65;
		static CharCodeUpperZ = 90;
		static CharCode0 = 48;
		static CharCode9 = 57;
		static CharCodeColon = 58;
		static CharCodeDot = 46;
		static CharCodeUnderscore = 95;
		static CharCodeSemi = 59;
		static _escapes = new Map([
			["lt", "<"],
			["gt", ">"],
			["amp", "&"],
			["quot", "\""],
			["apos", "'"]
		]);
		static parse(str, p, parent) {
			let c = str.charCodeAt(p);
			let state = 1;
			let next = 1;
			let start = 0;
			let buf = "";
			let escapeNext = 1;
			let xml = null;
			let aname = null;
			let nbrackets = 0;
			let attrValQuote = 0;
			while (p < str.length) {
				c = str.charCodeAt(p);
				switch (state) {
					case 0:
						switch (c) {
							case XmlParser.CharCodeLF:
							case XmlParser.CharCodeCR:
							case XmlParser.CharCodeTab:
							case XmlParser.CharCodeSpace: break;
							default:
								state = next;
								continue;
						}
						break;
					case 1:
						switch (c) {
							case XmlParser.CharCodeLowerThan:
								state = 0;
								next = 2;
								break;
							default:
								start = p;
								state = 13;
								continue;
						}
						break;
					case 13:
						if (c === XmlParser.CharCodeLowerThan) {
							buf += str.substr(start, p - start);
							const child = new XmlNode();
							child.nodeType = XmlNodeType.Text;
							child.value = buf;
							buf = "";
							parent.addChild(child);
							state = 0;
							next = 2;
						} else if (c === XmlParser.CharCodeAmp) {
							buf += str.substr(start, p - start);
							state = 18;
							escapeNext = 13;
							start = p + 1;
						}
						break;
					case 17:
						if (c === XmlParser.CharCodeBrackedClose && str.charCodeAt(p + 1) === XmlParser.CharCodeBrackedClose && str.charCodeAt(p + 2) === XmlParser.CharCodeGreaterThan) {
							const child = new XmlNode();
							child.nodeType = XmlNodeType.CDATA;
							child.value = str.substr(start, p - start);
							parent.addChild(child);
							p += 2;
							state = 1;
						}
						break;
					case 2:
						switch (c) {
							case XmlParser.CharCodeExclamation:
								if (str.charCodeAt(p + 1) === XmlParser.CharCodeBrackedOpen) {
									p += 2;
									if (str.substr(p, 6).toUpperCase() !== "CDATA[") throw new XmlError("Expected <![CDATA[", str, p);
									p += 5;
									state = 17;
									start = p + 1;
								} else if (str.charCodeAt(p + 1) === XmlParser.CharCodeUpperD || str.charCodeAt(p + 1) === XmlParser.CharCodeLowerD) {
									if (str.substr(p + 2, 6).toUpperCase() !== "OCTYPE") throw new XmlError("Expected <!DOCTYPE", str, p);
									p += 8;
									state = 16;
									start = p + 1;
								} else if (str.charCodeAt(p + 1) !== XmlParser.CharCodeMinus || str.charCodeAt(p + 2) !== XmlParser.CharCodeMinus) throw new XmlError("Expected <!--", str, p);
								else {
									p += 2;
									state = 15;
									start = p + 1;
								}
								break;
							case XmlParser.CharCodeQuestion:
								state = 14;
								start = p;
								break;
							case XmlParser.CharCodeSlash:
								if (!parent) throw new XmlError("Expected node name", str, p);
								start = p + 1;
								state = 0;
								next = 10;
								break;
							default:
								state = 3;
								start = p;
								continue;
						}
						break;
					case 3:
						if (!XmlParser._isValidChar(c)) {
							if (p === start) throw new XmlError("Expected node name", str, p);
							xml = new XmlNode();
							xml.nodeType = XmlNodeType.Element;
							xml.localName = str.substr(start, p - start);
							parent.addChild(xml);
							state = 0;
							next = 4;
							continue;
						}
						break;
					case 4:
						switch (c) {
							case XmlParser.CharCodeSlash:
								state = 11;
								break;
							case XmlParser.CharCodeGreaterThan:
								state = 9;
								break;
							default:
								state = 5;
								start = p;
								continue;
						}
						break;
					case 5:
						if (!XmlParser._isValidChar(c)) {
							if (start === p) throw new XmlError("Expected attribute name", str, p);
							aname = str.substr(start, p - start);
							if (xml.attributes.has(aname)) throw new XmlError(`Duplicate attribute [${aname}]`, str, p);
							state = 0;
							next = 6;
							continue;
						}
						break;
					case 6:
						switch (c) {
							case XmlParser.CharCodeEquals:
								state = 0;
								next = 7;
								break;
							default: throw new XmlError("Expected =", str, p);
						}
						break;
					case 7:
						switch (c) {
							case XmlParser.CharCodeDoubleQuote:
							case XmlParser.CharCodeSingleQuote:
								buf = "";
								state = 8;
								start = p + 1;
								attrValQuote = c;
								break;
						}
						break;
					case 8:
						switch (c) {
							case XmlParser.CharCodeAmp:
								buf += str.substr(start, p - start);
								state = 18;
								escapeNext = 8;
								start = p + 1;
								break;
							default:
								if (c === attrValQuote) {
									buf += str.substr(start, p - start);
									const value = buf;
									buf = "";
									xml.attributes.set(aname, value);
									state = 0;
									next = 4;
								}
								break;
						}
						break;
					case 9:
						p = XmlParser.parse(str, p, xml);
						start = p;
						state = 1;
						break;
					case 11:
						switch (c) {
							case XmlParser.CharCodeGreaterThan:
								state = 1;
								break;
							default: throw new XmlError("Expected >", str, p);
						}
						break;
					case 12: switch (c) {
						case XmlParser.CharCodeGreaterThan: return p;
						default: throw new XmlError("Expected >", str, p);
					}
					case 10:
						if (!XmlParser._isValidChar(c)) {
							if (start === p) throw new XmlError("Expected node name", str, p);
							if (str.substr(start, p - start) !== parent.localName) throw new XmlError(`Expected </${parent.localName}>`, str, p);
							state = 0;
							next = 12;
							continue;
						}
						break;
					case 15:
						if (c === XmlParser.CharCodeMinus && str.charCodeAt(p + 1) === XmlParser.CharCodeMinus && str.charCodeAt(p + 2) === XmlParser.CharCodeGreaterThan) {
							p += 2;
							state = 1;
						}
						break;
					case 16:
						if (c === XmlParser.CharCodeBrackedOpen) nbrackets++;
						else if (c === XmlParser.CharCodeBrackedClose) nbrackets--;
						else if (c === XmlParser.CharCodeGreaterThan && nbrackets === 0) {
							const node = new XmlNode();
							node.nodeType = XmlNodeType.DocumentType;
							node.value = str.substr(start, p - start);
							parent.addChild(node);
							state = 1;
						}
						break;
					case 14:
						if (c === XmlParser.CharCodeQuestion && str.charCodeAt(p + 1) === XmlParser.CharCodeGreaterThan) {
							p++;
							state = 1;
						}
						break;
					case 18:
						if (c === XmlParser.CharCodeSemi) {
							const s = str.substr(start, p - start);
							if (s.charCodeAt(0) === XmlParser.CharCodeSharp) {
								const code = s.charCodeAt(1) === XmlParser.CharCodeLowerX ? Number.parseInt(`0${s.substr(1, s.length - 1)}`, 10) : Number.parseInt(s.substr(1, s.length - 1), 10);
								buf += String.fromCharCode(code);
							} else if (XmlParser._escapes.has(s)) buf += XmlParser._escapes.get(s);
							else buf += `&${s};`.toString();
							start = p + 1;
							state = escapeNext;
						} else if (!XmlParser._isValidChar(c) && c !== XmlParser.CharCodeSharp) {
							buf += "&";
							buf += str.substr(start, p - start);
							p--;
							start = p + 1;
							state = escapeNext;
						}
						break;
				}
				p++;
			}
			if (state === 1) {
				start = p;
				state = 13;
			}
			if (state === 13) {
				if (p !== start) {
					buf += str.substr(start, p - start);
					const node = new XmlNode();
					node.nodeType = XmlNodeType.Text;
					node.value = buf;
					parent.addChild(node);
				}
				return p;
			}
			if (state === 18 && escapeNext === 13) {
				buf += "&";
				buf += str.substr(start, p - start);
				const node = new XmlNode();
				node.nodeType = XmlNodeType.Text;
				node.value = buf;
				parent.addChild(node);
				return p;
			}
			throw new XmlError("Unexpected end", str, p);
		}
		static _isValidChar(c) {
			return c >= XmlParser.CharCodeLowerA && c <= XmlParser.CharCodeLowerZ || c >= XmlParser.CharCodeUpperA && c <= XmlParser.CharCodeUpperZ || c >= XmlParser.CharCode0 && c <= XmlParser.CharCode9 || c === XmlParser.CharCodeColon || c === XmlParser.CharCodeDot || c === XmlParser.CharCodeUnderscore || c === XmlParser.CharCodeMinus;
		}
	};
	//#endregion
	//#region src/xml/XmlWriter.ts
	/**
	* @internal
	*/
	var XmlWriter = class XmlWriter {
		_result = [];
		_indention;
		_xmlHeader;
		_isStartOfLine;
		_currentIndention;
		constructor(indention, xmlHeader) {
			this._indention = indention;
			this._xmlHeader = xmlHeader;
			this._currentIndention = "";
			this._isStartOfLine = true;
		}
		writeNode(xml) {
			switch (xml.nodeType) {
				case XmlNodeType.None: break;
				case XmlNodeType.Element:
					if (this._result.length > 0) this._writeLine();
					this._write(`<${xml.localName}`);
					for (const [name, value] of xml.attributes) {
						this._write(` ${name}="`);
						this._writeAttributeValue(value);
						this._write("\"");
					}
					if (xml.childNodes.length === 0) this._write("/>");
					else {
						this._write(">");
						if (xml.childNodes.length === 1 && !xml.firstElement) this.writeNode(xml.childNodes[0]);
						else {
							this._indent();
							for (const child of xml.childNodes) if (child.nodeType === XmlNodeType.Element || child.nodeType === XmlNodeType.Comment) this.writeNode(child);
							this._unindend();
							this._writeLine();
						}
						this._write(`</${xml.localName}>`);
					}
					break;
				case XmlNodeType.Text:
					if (xml.value) this._write(xml.value);
					break;
				case XmlNodeType.CDATA:
					if (xml.value !== null) this._write(`<![CDATA[${xml.value}]]>`);
					break;
				case XmlNodeType.Document:
					if (this._xmlHeader) this._write("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
					for (const child of xml.childNodes) this.writeNode(child);
					break;
				case XmlNodeType.DocumentType:
					this._write(`<!DOCTYPE ${xml.value}>`);
					break;
				case XmlNodeType.Comment:
					this._write(`<!-- ${xml.value} -->`);
					break;
			}
		}
		_unindend() {
			this._currentIndention = this._currentIndention.substr(0, this._currentIndention.length - this._indention.length);
		}
		_indent() {
			this._currentIndention += this._indention;
		}
		_writeAttributeValue(value) {
			for (let i = 0; i < value.length; i++) {
				const c = value.charAt(i);
				switch (c) {
					case "<":
						this._result.push("&lt;");
						break;
					case ">":
						this._result.push("&gt;");
						break;
					case "&":
						this._result.push("&amp;");
						break;
					case "'":
						this._result.push("&apos;");
						break;
					case "\"":
						this._result.push("&quot;");
						break;
					default:
						this._result.push(c);
						break;
				}
			}
		}
		static write(xml, indention, xmlHeader) {
			const writer = new XmlWriter(indention, xmlHeader);
			writer.writeNode(xml);
			return writer.toString();
		}
		_write(s) {
			if (this._isStartOfLine) this._result.push(this._currentIndention);
			this._result.push(s);
			this._isStartOfLine = false;
		}
		_writeLine(s = null) {
			if (s) this._write(s);
			if (this._indention.length > 0 && !this._isStartOfLine) {
				this._result.push("\n");
				this._isStartOfLine = true;
			}
		}
		toString() {
			return this._result.join("").trimRight();
		}
	};
	//#endregion
	//#region src/xml/XmlDocument.ts
	/**
	* @internal
	*/
	var XmlDocument = class extends XmlNode {
		constructor() {
			super();
			this.nodeType = XmlNodeType.Document;
		}
		parse(xml) {
			XmlParser.parse(xml, 0, this);
		}
		toString() {
			return this.toFormattedString();
		}
		toFormattedString(indention = "", xmlHeader = false) {
			return XmlWriter.write(this, indention, xmlHeader);
		}
	};
	//#endregion
	//#region src/importer/CapellaParser.ts
	/**
	* @internal
	*/
	var DrawObject = class {
		noteRange = 1;
		x = 0;
		y = 0;
	};
	/**
	* @internal
	*/
	var TextDrawObject = class extends DrawObject {
		align = TextAlign.Left;
		frame = 0;
		text = "";
		fontFace = "";
		weight = 0;
		height = 0;
	};
	/**
	* @internal
	*/
	var GuitarDrawObject = class extends DrawObject {
		chord = new Chord();
	};
	/**
	* @internal
	*/
	var SlurDrawObject = class extends DrawObject {};
	/**
	* @internal
	*/
	var WavyLineDrawObject = class extends DrawObject {};
	/**
	* @internal
	*/
	var TupletBracketDrawObject = class extends DrawObject {
		number = 0;
	};
	/**
	* @internal
	*/
	var WedgeDrawObject = class extends DrawObject {
		decrescendo = false;
	};
	/**
	* @internal
	*/
	var VoltaDrawObject = class extends DrawObject {
		allNumbers = false;
		firstNumber = 0;
		lastNumber = 0;
	};
	/**
	* @internal
	*/
	var OctaveClefDrawObject = class extends DrawObject {
		octave = 1;
	};
	/**
	* @internal
	*/
	var TrillDrawObject = class extends DrawObject {};
	/**
	* @internal
	*/
	var StaffLayout = class {
		defaultClef = Clef.G2;
		description = "";
		percussion = false;
		instrument = 0;
		volume = 0;
		transpose = 0;
		index = 0;
	};
	/**
	* @internal
	*/
	var Bracket = class {
		from = 0;
		to = 0;
		curly = false;
	};
	/**
	* @internal
	*/
	var CapellaVoiceState = class {
		currentBarIndex = -1;
		currentBarComplete = true;
		currentBarDuration = 0;
		currentPosition = 0;
		voiceStemDir = null;
		repeatCount = 0;
		repeatEnd = null;
	};
	/**
	* @internal
	*/
	var CapellaParser = class CapellaParser {
		score;
		_trackChannel = 0;
		_beamingMode = BeatBeamingMode.Auto;
		_galleryObjects;
		_voiceCounts;
		_isFirstSystem = true;
		_initialTempo = -1;
		parseXml(xml, settings) {
			this._galleryObjects = /* @__PURE__ */ new Map();
			this._tieStarts = [];
			this._tieStartIds = /* @__PURE__ */ new Map();
			this._voiceCounts = /* @__PURE__ */ new Map();
			this._slurs = /* @__PURE__ */ new Map();
			this._crescendo = /* @__PURE__ */ new Map();
			this._isFirstSystem = true;
			const dom = new XmlDocument();
			try {
				dom.parse(xml);
			} catch (e) {
				throw new UnsupportedFormatError("Could not parse XML", e);
			}
			this._parseDom(dom);
			this._consolidate();
			this.score.finish(settings);
		}
		_consolidate() {
			ModelUtils.consolidate(this.score);
			CapellaParser._applyEffectRange(this._slurs, (_, beat) => {
				beat.isLegatoOrigin = true;
			});
			CapellaParser._applyEffectRange(this._crescendo, (cre, beat) => {
				beat.crescendo = cre.decrescendo ? CrescendoType.Decrescendo : CrescendoType.Crescendo;
			});
		}
		static _applyEffectRange(effects, applyEffect) {
			for (const [startBeat, effect] of effects) {
				const noteRange = effect.noteRange;
				let endBeat = startBeat;
				for (let i = 0; i < noteRange; i++) {
					applyEffect(effect, endBeat);
					if (endBeat.index + 1 < endBeat.voice.beats.length) endBeat = endBeat.voice.beats[endBeat.index + 1];
					else if (endBeat.voice.bar.index + 1 < endBeat.voice.bar.staff.bars.length) endBeat = endBeat.voice.bar.staff.bars[endBeat.voice.bar.index + 1].voices[endBeat.voice.index].beats[0];
					else break;
				}
			}
		}
		_parseDom(dom) {
			const root = dom.firstElement;
			if (!root) throw new UnsupportedFormatError("No valid XML");
			if (root.localName === "score") {
				this.score = new Score();
				for (const n of root.childElements()) switch (n.localName) {
					case "info":
						this._parseInfo(n);
						break;
					case "layout":
						this._parseLayout(n);
						break;
					case "gallery":
						this._parseGallery(n);
						break;
					case "pageObjects":
						this._parsePageObjects(n);
						break;
					case "systems":
						this._parseSystems(n);
						break;
				}
			} else throw new UnsupportedFormatError("Root node of XML was not \"score\"");
		}
		_staffLookup = /* @__PURE__ */ new Map();
		_parseLayout(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "staves":
					this._parseLayoutStaves(c);
					break;
				case "brackets":
					this._parseBrackets(c);
					break;
			}
			const curlyBrackets = this._brackets.filter((b) => !!b.curly);
			curlyBrackets.sort((a, b) => a.from - b.from);
			let currentBracketIndex = 0;
			let currentTrack = null;
			for (let i = 0; i < this._staffLayouts.length; i++) {
				const staffLayout = this._staffLayouts[i];
				while (currentBracketIndex < curlyBrackets.length && i > curlyBrackets[currentBracketIndex].to) currentBracketIndex++;
				if (currentTrack && currentBracketIndex < curlyBrackets.length && i > curlyBrackets[currentBracketIndex].from && i <= curlyBrackets[currentBracketIndex].to) currentTrack.ensureStaveCount(currentTrack.staves.length + 1);
				else {
					currentTrack = new Track();
					currentTrack.ensureStaveCount(1);
					currentTrack.name = staffLayout.description;
					currentTrack.playbackInfo.volume = Math.floor(staffLayout.volume / 128 * 16);
					currentTrack.playbackInfo.program = staffLayout.instrument;
					if (staffLayout.percussion) {
						currentTrack.playbackInfo.primaryChannel = 9;
						currentTrack.playbackInfo.secondaryChannel = 9;
					} else {
						currentTrack.playbackInfo.primaryChannel = this._trackChannel++;
						currentTrack.playbackInfo.secondaryChannel = this._trackChannel++;
					}
					this.score.addTrack(currentTrack);
				}
				const staff = currentTrack.staves[currentTrack.staves.length - 1];
				staff.isPercussion = staffLayout.percussion;
				staff.transpositionPitch = staffLayout.transpose;
				staff.displayTranspositionPitch = 0;
				staff.showTablature = false;
				this._staffLookup.set(staffLayout.index, staff);
			}
		}
		_brackets = [];
		_parseBrackets(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "bracket":
					this._parseBracket(c);
					break;
			}
		}
		_parseBracket(element) {
			const bracket = new Bracket();
			bracket.from = Number.parseInt(element.getAttribute("from"), 10);
			bracket.to = Number.parseInt(element.getAttribute("to"), 10);
			if (element.attributes.has("curly")) bracket.curly = element.attributes.get("curly") === "true";
			this._brackets.push(bracket);
		}
		_parseLayoutStaves(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "staffLayout":
					this._parseStaffLayout(c);
					break;
			}
		}
		_staffLayoutLookup = /* @__PURE__ */ new Map();
		_staffLayouts = [];
		_parseStaffLayout(element) {
			const layout = new StaffLayout();
			layout.description = element.getAttribute("description");
			for (const c of element.childElements()) switch (c.localName) {
				case "notation":
					if (c.attributes.has("defaultClef")) layout.defaultClef = this._parseClef(c.attributes.get("defaultClef"));
					break;
				case "sound":
					if (c.attributes.has("percussion")) layout.percussion = c.attributes.get("percussion") === "true";
					if (c.attributes.has("instr")) layout.instrument = Number.parseInt(c.attributes.get("instr"), 10);
					if (c.attributes.has("volume")) layout.volume = Number.parseInt(c.attributes.get("volume"), 10);
					if (c.attributes.has("transpose")) layout.transpose = Number.parseInt(c.attributes.get("transpose"), 10);
					break;
			}
			this._staffLayoutLookup.set(layout.description, layout);
			layout.index = this._staffLayouts.length;
			this._staffLayouts.push(layout);
		}
		_parseClef(v) {
			switch (v) {
				case "treble": return Clef.G2;
				case "bass": return Clef.F4;
				case "alto": return Clef.C4;
				case "tenor": return Clef.C4;
			}
			return Clef.G2;
		}
		_parseClefOttava(v) {
			if (v.endsWith("-")) return Ottavia._8vb;
			if (v.endsWith("+")) return Ottavia._8va;
			return Ottavia.Regular;
		}
		_parseSystems(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "system":
					this._parseSystem(c);
					break;
			}
		}
		_parseSystem(element) {
			if (element.attributes.has("tempo")) {
				if (this.score.masterBars.length === 0) this._initialTempo = Number.parseInt(element.attributes.get("tempo"), 10);
			}
			if (element.getAttribute("beamGrouping") === "0") this._beamingMode = BeatBeamingMode.ForceSplitToNext;
			for (const c of element.childElements()) switch (c.localName) {
				case "staves":
					this._parseStaves(element, c);
					break;
			}
			this._isFirstSystem = false;
		}
		_parseStaves(systemElement, element) {
			const firstBarIndex = this.score.masterBars.length;
			for (const c of element.childElements()) switch (c.localName) {
				case "staff":
					this._parseStaff(systemElement, firstBarIndex, c);
					break;
			}
		}
		_timeSignature = new MasterBar();
		_currentStaffLayout;
		_parseStaff(systemElement, firstBarIndex, element) {
			const staffId = element.getAttribute("layout");
			this._currentStaffLayout = this._staffLayoutLookup.get(staffId);
			this._timeSignature.timeSignatureNumerator = 4;
			this._timeSignature.timeSignatureDenominator = 4;
			this._timeSignature.timeSignatureCommon = false;
			this._parseTime(element.getAttribute("defaultTime"));
			const staff = this._staffLookup.get(this._currentStaffLayout.index);
			while (staff.bars.length < firstBarIndex) this._addNewBar(staff);
			for (const c of element.childElements()) switch (c.localName) {
				case "voices":
					this._parseVoices(staffId, staff, systemElement, firstBarIndex, c);
					break;
			}
		}
		_parseTime(value) {
			switch (value) {
				case "allaBreve":
				case "C":
					this._timeSignature.timeSignatureNumerator = 2;
					this._timeSignature.timeSignatureDenominator = 2;
					this._timeSignature.timeSignatureCommon = true;
					break;
				case "longAllaBreve":
					this._timeSignature.timeSignatureNumerator = 4;
					this._timeSignature.timeSignatureDenominator = 4;
					this._timeSignature.timeSignatureCommon = true;
					break;
				default:
					if (value.indexOf("/") > 0) {
						const parts = value.split("/");
						this._timeSignature.timeSignatureNumerator = Number.parseInt(parts[0], 10);
						this._timeSignature.timeSignatureDenominator = Number.parseInt(parts[1], 10);
						this._timeSignature.timeSignatureCommon = false;
					}
					break;
			}
		}
		_parseVoices(staffId, staff, systemElement, firstBarIndex, element) {
			let voiceIndex = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "voice":
					this._parseVoice(staffId, staff, systemElement, voiceIndex, firstBarIndex, c);
					voiceIndex++;
					break;
			}
		}
		_getOrCreateBar(staff, barIndex) {
			if (barIndex < staff.bars.length) return staff.bars[barIndex];
			return this._addNewBar(staff);
		}
		_addNewBar(staff) {
			const currentBar = new Bar();
			if (staff.bars.length > 0) {
				currentBar.clef = staff.bars[staff.bars.length - 1].clef;
				currentBar.clefOttava = staff.bars[staff.bars.length - 1].clefOttava;
				currentBar.keySignature = staff.bars[staff.bars.length - 1].keySignature;
				currentBar.keySignatureType = staff.bars[staff.bars.length - 1].keySignatureType;
			} else currentBar.clef = this._currentStaffLayout.defaultClef;
			staff.addBar(currentBar);
			if (staff.bars.length > this.score.masterBars.length) {
				const master = new MasterBar();
				this.score.addMasterBar(master);
				if (master.index > 0) master.tripletFeel = master.previousMasterBar.tripletFeel;
				else if (this._initialTempo > 0) master.tempoAutomations.push(Automation.buildTempoAutomation(false, 0, this._initialTempo, 0));
				master.timeSignatureDenominator = this._timeSignature.timeSignatureDenominator;
				master.timeSignatureNumerator = this._timeSignature.timeSignatureNumerator;
				master.timeSignatureCommon = this._timeSignature.timeSignatureCommon;
			}
			return currentBar;
		}
		_voiceStates = /* @__PURE__ */ new Map();
		_currentVoiceState;
		_currentBar;
		_currentVoice;
		_newBar(staff, voiceIndex) {
			this._currentVoiceState.currentBarIndex++;
			this._currentBar = this._getOrCreateBar(staff, this._currentVoiceState.currentBarIndex);
			this._currentVoiceState.currentBarDuration = this._currentBar.masterBar.calculateDuration(false);
			this._currentVoiceState.currentBarComplete = false;
			this._currentVoiceState.currentPosition = 0;
			this._ensureVoice(staff, voiceIndex);
		}
		_parseVoice(staffId, staff, systemElement, voiceIndex, firstBarIndex, element) {
			const voiceStateKey = `${staffId}_${voiceIndex}`;
			if (this._currentVoiceState && !this._currentVoiceState.currentBarComplete) this._currentBar.masterBar.isAnacrusis = true;
			if (!this._voiceStates.has(voiceStateKey)) {
				this._currentVoiceState = new CapellaVoiceState();
				this._currentVoiceState.currentBarIndex = firstBarIndex - 1;
				this._voiceStates.set(voiceStateKey, this._currentVoiceState);
				this._newBar(staff, voiceIndex);
			} else {
				this._currentVoiceState = this._voiceStates.get(voiceStateKey);
				this._currentBar = this._getOrCreateBar(staff, this._currentVoiceState.currentBarIndex);
				this._ensureVoice(staff, voiceIndex);
			}
			if (element.attributes.has("stemDir")) switch (element.attributes.get("stemDir")) {
				case "up":
					this._currentVoiceState.voiceStemDir = BeamDirection.Up;
					break;
				case "down":
					this._currentVoiceState.voiceStemDir = BeamDirection.Down;
					break;
				default:
					this._currentVoiceState.voiceStemDir = null;
					break;
			}
			else this._currentVoiceState.voiceStemDir = null;
			const noteObjects = element.findChildElement("noteObjects");
			if (systemElement.attributes.has("tempo")) {
				const automation = new Automation();
				automation.isLinear = true;
				automation.type = AutomationType.Tempo;
				automation.value = Number.parseInt(systemElement.attributes.get("tempo"), 10);
				automation.ratioPosition = this._currentVoiceState.currentPosition / this._currentVoiceState.currentBarDuration;
				this._currentBar.masterBar.tempoAutomations.push(automation);
			}
			if (noteObjects) for (const c of noteObjects.childElements()) {
				if (this._currentVoiceState.currentBarComplete && c.localName !== "barline") this._newBar(staff, voiceIndex);
				switch (c.localName) {
					case "clefSign":
						this._currentBar.clef = this._parseClef(c.getAttribute("clef"));
						this._currentBar.clefOttava = this._parseClefOttava(c.getAttribute("clef"));
						break;
					case "keySign":
						this._currentBar.keySignature = Number.parseInt(c.getAttribute("fifths"), 10);
						break;
					case "timeSign":
						this._parseTime(c.getAttribute("time"));
						this._currentBar.masterBar.timeSignatureDenominator = this._timeSignature.timeSignatureDenominator;
						this._currentBar.masterBar.timeSignatureNumerator = this._timeSignature.timeSignatureNumerator;
						this._currentBar.masterBar.timeSignatureCommon = this._timeSignature.timeSignatureCommon;
						this._currentVoiceState.currentPosition = 0;
						this._currentVoiceState.currentBarDuration = this._currentBar.masterBar.calculateDuration(false);
						break;
					case "barline":
						switch (c.getAttribute("type")) {
							case "double":
								this._currentBar.barLineRight = BarLineStyle.LightLight;
								if (!this._currentVoiceState.currentBarComplete) this._currentBar.masterBar.isAnacrusis = true;
								this._currentVoiceState.currentBarComplete = true;
								break;
							case "end":
								if (!this._currentVoiceState.currentBarComplete) this._currentBar.masterBar.isAnacrusis = true;
								break;
							case "repEnd":
								this._currentVoiceState.repeatEnd = this._currentBar.masterBar;
								if (this._currentBar.masterBar.repeatCount < this._currentVoiceState.repeatCount) this._currentBar.masterBar.repeatCount = this._currentVoiceState.repeatCount;
								this._parseBarDrawObject(c);
								if (!this._currentVoiceState.currentBarComplete) this._currentBar.masterBar.isAnacrusis = true;
								this._currentVoiceState.currentBarComplete = true;
								break;
							case "repBegin":
								this._newBar(staff, voiceIndex);
								this._currentBar.masterBar.isRepeatStart = true;
								this._currentVoiceState.repeatEnd = null;
								this._currentVoiceState.repeatCount = 0;
								break;
							case "repEndBegin":
								this._currentVoiceState.repeatEnd = this._currentBar.masterBar;
								if (this._currentBar.masterBar.repeatCount < this._currentVoiceState.repeatCount) this._currentBar.masterBar.repeatCount = this._currentVoiceState.repeatCount;
								this._parseBarDrawObject(c);
								this._newBar(staff, voiceIndex);
								this._currentBar.masterBar.isRepeatStart = true;
								break;
							case "dashed":
								if (!this._currentVoiceState.currentBarComplete) this._currentBar.masterBar.isAnacrusis = true;
								this._currentVoiceState.currentBarComplete = true;
								break;
							default:
								if (!this._currentVoiceState.currentBarComplete) this._currentBar.masterBar.isAnacrusis = true;
								this._currentVoiceState.currentBarComplete = true;
								break;
						}
						break;
					case "chord":
						const chordBeat = new Beat();
						this._initFromPreviousBeat(chordBeat, this._currentVoice);
						chordBeat.beamingMode = this._beamingMode;
						if (this._currentVoiceState.voiceStemDir) chordBeat.preferredBeamDirection = this._currentVoiceState.voiceStemDir;
						this._parseDuration(chordBeat, c.findChildElement("duration"));
						chordBeat.updateDurations();
						this._currentVoiceState.currentPosition += chordBeat.playbackDuration;
						this._currentVoice.addBeat(chordBeat);
						this._parseChord(chordBeat, c);
						if (this._currentVoiceState.currentPosition >= this._currentVoiceState.currentBarDuration) this._currentVoiceState.currentBarComplete = true;
						break;
					case "rest":
						const restBeat = this._parseRestDurations(c.findChildElement("duration"));
						if (restBeat) {
							this._initFromPreviousBeat(restBeat, this._currentVoice);
							restBeat.updateDurations();
							this._currentVoiceState.currentPosition += restBeat.playbackDuration;
							this._currentVoice.addBeat(restBeat);
							if (this._currentVoiceState.currentPosition >= this._currentVoiceState.currentBarDuration) this._currentVoiceState.currentBarComplete = true;
						}
						break;
				}
			}
		}
		_initFromPreviousBeat(chordBeat, currentVoice) {
			const previousBeat = this._getLastBeat(currentVoice);
			if (previousBeat) chordBeat.dynamics = previousBeat.dynamics;
		}
		_getLastBeat(voice) {
			if (voice.beats.length > 0) return voice.beats[voice.beats.length - 1];
			if (voice.bar.index > 0) {
				const previousBar = voice.bar.staff.bars[voice.bar.index - 1];
				if (voice.index < previousBar.voices.length) {
					const previousVoice = previousBar.voices[voice.index];
					return this._getLastBeat(previousVoice);
				}
			}
			return null;
		}
		_ensureVoice(staff, voiceIndex) {
			while (this._currentBar.voices.length < voiceIndex + 1) this._currentBar.addVoice(new Voice$1());
			if (!this._voiceCounts.has(staff.track.index) || this._voiceCounts.get(staff.track.index) < this._currentBar.voices.length) this._voiceCounts.set(staff.track.index, this._currentBar.voices.length);
			this._currentVoice = this._currentBar.voices[voiceIndex];
		}
		_parseChord(beat, element) {
			const articulation = new Note();
			for (const c of element.childElements()) switch (c.localName) {
				case "stem":
					switch (c.getAttribute("dir")) {
						case "up":
							beat.preferredBeamDirection = BeamDirection.Up;
							break;
						case "down":
							beat.preferredBeamDirection = BeamDirection.Down;
							break;
					}
					break;
				case "articulation":
					switch (c.getAttribute("type")) {
						case "staccato":
							articulation.isStaccato = true;
							break;
						case "normalAccent":
							articulation.accentuated = AccentuationType.Normal;
							break;
						case "strongAccent":
							articulation.accentuated = AccentuationType.Heavy;
							break;
					}
					break;
				case "lyric":
					this._parseLyric(beat, c);
					break;
				case "drawObjects":
					this._parseBeatDrawObject(beat, c);
					break;
				case "heads":
					this._parseHeads(beat, articulation, c);
					break;
				case "beam":
					switch (c.getAttribute("group")) {
						case "force":
							beat.beamingMode = BeatBeamingMode.ForceMergeWithNext;
							break;
						case "divide":
							beat.beamingMode = BeatBeamingMode.ForceSplitToNext;
							break;
					}
					break;
			}
		}
		_parseHeads(beat, articulation, element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "head":
					this._parseHead(beat, articulation, c);
					break;
			}
		}
		_tieStarts;
		_tieStartIds;
		_slurs;
		_crescendo;
		_parseHead(beat, articulation, element) {
			const note = new Note();
			const pitch = ModelUtils.parseTuning(element.getAttribute("pitch"));
			note.octave = pitch.octave - 1;
			note.tone = pitch.tone.noteValue;
			note.isStaccato = articulation.isStaccato;
			note.accentuated = articulation.accentuated;
			beat.addNote(note);
			for (const c of element.childElements()) switch (c.localName) {
				case "alter":
					if (c.attributes.has("step")) note.tone += Number.parseInt(c.attributes.get("step"), 10);
					break;
				case "tie":
					if (c.attributes.has("begin")) {
						if (!this._tieStartIds.has(note.id)) {
							this._tieStartIds.set(note.id, true);
							this._tieStarts.push(note);
						}
					} else if (c.attributes.has("end") && this._tieStarts.length > 0 && !note.isTieDestination) {
						note.isTieDestination = true;
						note.tieOrigin = this._tieStarts[0];
						this._tieStarts.splice(0, 1);
						this._tieStartIds.delete(note.id);
					}
					break;
			}
		}
		_parseBeatDrawObject(beat, element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "drawObj":
					const obj = this._parseDrawObj(c);
					if (obj) {
						if (obj instanceof TextDrawObject) {
							if (obj.fontFace.startsWith("capella")) {
								if (obj.text === "u") {
									beat.fermata = new Fermata();
									beat.fermata.type = FermataType.Medium;
								} else if (obj.text === "f") beat.dynamics = DynamicValue.F;
								else if (obj.text === "j") beat.dynamics = DynamicValue.MF;
							} else if (this._isFirstSystem && this.score.title === "" && obj.align === TextAlign.Center && obj.height > 16 && obj.weight > 400) this.score.title = obj.text;
							else if (this._isFirstSystem && this.score.artist === "" && obj.align === TextAlign.Center && obj.y < 0) this.score.artist = obj.text;
							else if (this._isFirstSystem && this.score.music === "" && obj.align === TextAlign.Right && obj.y < 0) this.score.music = obj.text;
							else if (!obj.text.startsWith("by capella")) beat.text = obj.text;
						} else if (obj instanceof GuitarDrawObject) {} else if (obj instanceof WavyLineDrawObject) beat.vibrato = VibratoType.Slight;
						else if (obj instanceof WedgeDrawObject) {
							beat.crescendo = obj.decrescendo ? CrescendoType.Decrescendo : CrescendoType.Crescendo;
							obj.noteRange++;
							this._crescendo.set(beat, obj);
						} else if (obj instanceof SlurDrawObject) {
							const slur = obj;
							this._slurs.set(beat, slur);
						} else if (obj instanceof VoltaDrawObject) this._applyVolta(obj);
					}
					break;
			}
		}
		_parseBarDrawObject(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "drawObj":
					const obj = this._parseDrawObj(c);
					if (obj) {
						if (obj instanceof VoltaDrawObject) this._applyVolta(obj);
					}
					break;
			}
		}
		_applyVolta(obj) {
			if (obj.lastNumber > 0) {
				this._currentVoiceState.repeatCount = obj.lastNumber;
				if (this._currentVoiceState.repeatEnd && this._currentVoiceState.repeatEnd.repeatCount < this._currentVoiceState.repeatCount) this._currentVoiceState.repeatEnd.repeatCount = this._currentVoiceState.repeatCount;
			} else if (obj.firstNumber > 0) {
				this._currentVoiceState.repeatCount = obj.firstNumber;
				if (this._currentVoiceState.repeatEnd && this._currentVoiceState.repeatEnd.repeatCount < this._currentVoiceState.repeatCount) this._currentVoiceState.repeatEnd.repeatCount = this._currentVoiceState.repeatCount;
			}
			if (obj.lastNumber > 0 && obj.firstNumber > 0) {
				let alternateEndings = 0;
				for (let i = obj.firstNumber; i <= obj.lastNumber; i++) alternateEndings = alternateEndings | 1 << i - 1;
				this._currentBar.masterBar.alternateEndings = alternateEndings;
			} else if (obj.lastNumber > 0) this._currentBar.masterBar.alternateEndings = 1 << obj.lastNumber - 1;
			else if (obj.firstNumber > 0) this._currentBar.masterBar.alternateEndings = 1 << obj.firstNumber - 1;
		}
		_parseLyric(beat, element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "verse":
					if (!beat.lyrics) beat.lyrics = [];
					let text = c.innerText;
					if (c.getAttribute("hyphen") === "true") text += "-";
					beat.lyrics.push(text);
					break;
			}
		}
		_parseRestDurations(element) {
			const durationBase = element.getAttribute("base");
			if (durationBase.indexOf("/") !== -1) {
				const restBeat = new Beat();
				restBeat.beamingMode = this._beamingMode;
				this._parseDuration(restBeat, element);
				return restBeat;
			}
			if (Number.parseInt(durationBase, 10) === 1) {
				const restBeat = new Beat();
				restBeat.beamingMode = this._beamingMode;
				restBeat.duration = Duration.Whole;
				return restBeat;
			}
			Logger.warning("Importer", "Multi-Bar rests are not supported");
			return null;
		}
		_parseDurationValue(s) {
			switch (s) {
				case "2/1": return Duration.DoubleWhole;
				case "1/1": return Duration.Whole;
				case "1/2": return Duration.Half;
				case "1/4": return Duration.Quarter;
				case "1/8": return Duration.Eighth;
				case "1/16": return Duration.Sixteenth;
				case "1/32": return Duration.ThirtySecond;
				case "1/64": return Duration.SixtyFourth;
				case "1/128": return Duration.OneHundredTwentyEighth;
				default:
					Logger.warning("Importer", "Unsupported duration");
					return Duration.Quarter;
			}
		}
		_parseDuration(beat, element) {
			const durationBase = element.getAttribute("base");
			beat.duration = this._parseDurationValue(durationBase);
			if (element.attributes.has("dots")) beat.dots = Number.parseInt(element.attributes.get("dots"), 10);
			const tuplet = element.findChildElement("tuplet");
			if (tuplet) {
				beat.tupletNumerator = Number.parseInt(tuplet.getAttribute("count"), 10);
				const tripartiteMultiplicator = tuplet.getAttribute("tripartite") === "true" ? 3 : 1;
				const prolongDiff = tuplet.getAttribute("prolong") === "true" ? 0 : 1;
				let power = 0;
				while (tripartiteMultiplicator * Math.pow(2, power + prolongDiff) < beat.tupletNumerator) power++;
				beat.tupletDenominator = tripartiteMultiplicator * Math.pow(2, power);
			}
		}
		_parsePageObjects(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "drawObj":
					const obj = this._parseDrawObj(c);
					if (obj) {
						if (obj instanceof TextDrawObject) switch (obj.align) {
							case TextAlign.Center:
								if (!this.score.title) this.score.title = c.innerText;
								else if (!this.score.subTitle) this.score.subTitle = c.innerText;
								break;
							case TextAlign.Right:
								if (!this.score.artist) this.score.artist = c.innerText;
								break;
						}
					}
					break;
			}
		}
		_parseGallery(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "drawObj":
					const obj = this._parseDrawObj(c);
					if (obj) this._galleryObjects.set(c.getAttribute("name"), obj);
					break;
			}
		}
		_parseDrawObj(element) {
			let obj = null;
			let noteRange = 1;
			for (const c of element.childElements()) switch (c.localName) {
				case "text":
					obj = this._parseText(c);
					break;
				case "guitar":
					obj = this._parseGuitar(c);
					break;
				case "slur":
					obj = this._parseSlur(c);
					break;
				case "wavyLine":
					obj = this._parseWavyLine(c);
					break;
				case "bracket":
					obj = this._parseTupletBracket(c);
					break;
				case "wedge":
					obj = this._parseWedge(c);
					break;
				case "volta":
					obj = this._parseVolta(c);
					break;
				case "octaveClef":
					obj = this._parseOctaveClef(c);
					break;
				case "trill":
					obj = this._parseTrill(c);
					break;
				case "basic":
					if (c.attributes.has("noteRange")) noteRange = Number.parseInt(c.attributes.get("noteRange"), 10);
					break;
			}
			if (obj) obj.noteRange = noteRange;
			return obj;
		}
		_parseTrill(_unused) {
			return new TrillDrawObject();
		}
		_parseOctaveClef(element) {
			const obj = new OctaveClefDrawObject();
			if (element.attributes.has("octave")) obj.octave = Number.parseInt(element.attributes.get("octave"), 10);
			return obj;
		}
		_parseVolta(element) {
			const obj = new VoltaDrawObject();
			obj.allNumbers = element.attributes.get("allNumbers") === "true";
			if (element.attributes.has("firstNumber")) obj.firstNumber = Number.parseInt(element.attributes.get("firstNumber"), 10);
			if (element.attributes.has("lastNumber")) obj.lastNumber = Number.parseInt(element.attributes.get("lastNumber"), 10);
			return obj;
		}
		_parseWedge(element) {
			const obj = new WedgeDrawObject();
			obj.decrescendo = element.attributes.get("decrescendo") === "true";
			return obj;
		}
		_parseTupletBracket(element) {
			const obj = new TupletBracketDrawObject();
			if (element.attributes.has("number")) obj.number = Number.parseInt(element.attributes.get("number"), 10);
			return obj;
		}
		_parseWavyLine(_unused) {
			return new WavyLineDrawObject();
		}
		_parseSlur(_unused) {
			return new SlurDrawObject();
		}
		_parseGuitar(element) {
			const obj = new GuitarDrawObject();
			const strings = element.innerText.trim();
			for (let i = 0; i < strings.length; i++) if (strings.charAt(i) === "/") obj.chord.strings.push(0);
			else obj.chord.strings.push(Number.parseInt(strings.charAt(i), 10));
			return obj;
		}
		_parseText(element) {
			const obj = new TextDrawObject();
			if (element.attributes.has("x")) obj.x = Number.parseFloat(element.attributes.get("x"));
			if (element.attributes.has("x")) obj.y = Number.parseFloat(element.attributes.get("y"));
			switch (element.getAttribute("align")) {
				case "left":
					obj.align = TextAlign.Left;
					break;
				case "center":
					obj.align = TextAlign.Center;
					break;
				case "right":
					obj.align = TextAlign.Right;
					break;
			}
			switch (element.getAttribute("frame")) {
				case "rectangle":
					obj.frame = 1;
					break;
				case "ellipse":
					obj.frame = 2;
					break;
				case "circle":
					obj.frame = 3;
					break;
				case "none":
					obj.frame = 0;
					break;
			}
			if (element.firstElement) for (const c of element.childElements()) switch (c.localName) {
				case "font":
					obj.fontFace = c.getAttribute("face");
					if (c.attributes.has("weight")) obj.weight = Number.parseInt(c.attributes.get("weight"), 10);
					if (c.attributes.has("height")) obj.height = Number.parseInt(c.attributes.get("height"), 10);
					break;
				case "content":
					obj.text = c.innerText;
					break;
			}
			else obj.text = element.innerText;
			return obj;
		}
		_parseInfo(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "author":
					this.score.tab = c.firstChild.innerText;
					break;
				case "comment":
					this.score.notices = c.firstChild.innerText;
					break;
			}
		}
	};
	//#endregion
	//#region src/importer/CapellaImporter.ts
	/**
	* This ScoreImporter can read Capella (cap/capx) files.
	* @internal
	*/
	var CapellaImporter = class extends ScoreImporter {
		get name() {
			return "Capella";
		}
		readScore() {
			Logger.debug(this.name, "Loading ZIP entries");
			const fileSystem = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
			let entries;
			let xml = null;
			entries = fileSystem.read();
			Logger.debug(this.name, "Zip entries loaded");
			if (entries.length > 0) for (const entry of entries) switch (entry.fileName) {
				case "score.xml":
					xml = IOHelper.toString(entry.data, this.settings.importer.encoding);
					break;
			}
			else {
				this.data.reset();
				xml = IOHelper.toString(this.data.readAll(), this.settings.importer.encoding);
			}
			if (!xml) throw new UnsupportedFormatError("No valid capella file");
			Logger.debug(this.name, "Start Parsing score.xml");
			try {
				const capellaParser = new CapellaParser();
				capellaParser.parseXml(xml, this.settings);
				Logger.debug(this.name, "score.xml parsed");
				return capellaParser.score;
			} catch (e) {
				throw new UnsupportedFormatError("Failed to parse CapXML", e);
			}
		}
	};
	//#endregion
	//#region src/model/Direction.ts
	/**
	* Lists all directions which can be applied to a masterbar.
	* @public
	*/
	var Direction = /* @__PURE__ */ function(Direction) {
		Direction[Direction["TargetFine"] = 0] = "TargetFine";
		Direction[Direction["TargetSegno"] = 1] = "TargetSegno";
		Direction[Direction["TargetSegnoSegno"] = 2] = "TargetSegnoSegno";
		Direction[Direction["TargetCoda"] = 3] = "TargetCoda";
		Direction[Direction["TargetDoubleCoda"] = 4] = "TargetDoubleCoda";
		Direction[Direction["JumpDaCapo"] = 5] = "JumpDaCapo";
		Direction[Direction["JumpDaCapoAlCoda"] = 6] = "JumpDaCapoAlCoda";
		Direction[Direction["JumpDaCapoAlDoubleCoda"] = 7] = "JumpDaCapoAlDoubleCoda";
		Direction[Direction["JumpDaCapoAlFine"] = 8] = "JumpDaCapoAlFine";
		Direction[Direction["JumpDalSegno"] = 9] = "JumpDalSegno";
		Direction[Direction["JumpDalSegnoAlCoda"] = 10] = "JumpDalSegnoAlCoda";
		Direction[Direction["JumpDalSegnoAlDoubleCoda"] = 11] = "JumpDalSegnoAlDoubleCoda";
		Direction[Direction["JumpDalSegnoAlFine"] = 12] = "JumpDalSegnoAlFine";
		Direction[Direction["JumpDalSegnoSegno"] = 13] = "JumpDalSegnoSegno";
		Direction[Direction["JumpDalSegnoSegnoAlCoda"] = 14] = "JumpDalSegnoSegnoAlCoda";
		Direction[Direction["JumpDalSegnoSegnoAlDoubleCoda"] = 15] = "JumpDalSegnoSegnoAlDoubleCoda";
		Direction[Direction["JumpDalSegnoSegnoAlFine"] = 16] = "JumpDalSegnoSegnoAlFine";
		Direction[Direction["JumpDaCoda"] = 17] = "JumpDaCoda";
		Direction[Direction["JumpDaDoubleCoda"] = 18] = "JumpDaDoubleCoda";
		return Direction;
	}({});
	//#endregion
	//#region src/importer/Gp3To5Importer.ts
	/**
	* @internal
	*/
	var Gp3To5Importer = class Gp3To5Importer extends ScoreImporter {
		static _versionString = "FICHIER GUITAR PRO ";
		static _gp5PercussionInstrumentMap = new Map([
			[27, 42],
			[28, 60],
			[29, 29],
			[30, 30],
			[32, 31]
		]);
		_versionNumber = 0;
		_score;
		_globalTripletFeel = TripletFeel.NoTripletFeel;
		_lyricsTrack = 0;
		_lyrics = [];
		_barCount = 0;
		_trackCount = 0;
		_playbackInfos = [];
		_doubleBars = /* @__PURE__ */ new Set();
		_clefsPerTrack = /* @__PURE__ */ new Map();
		_keySignatures = /* @__PURE__ */ new Map();
		_beatTextChunksByTrack = /* @__PURE__ */ new Map();
		_directionLookup = /* @__PURE__ */ new Map();
		_initialTempo;
		get name() {
			return "Guitar Pro 3-5";
		}
		readScore() {
			this._directionLookup.clear();
			this.readVersion();
			this._score = new Score();
			this.readScoreInformation();
			if (this._versionNumber < 500) this._globalTripletFeel = GpBinaryHelpers.gpReadBool(this.data) ? TripletFeel.Triplet8th : TripletFeel.NoTripletFeel;
			if (this._versionNumber >= 400) this.readLyrics();
			if (this._versionNumber >= 510) this.data.skip(19);
			this._initialTempo = Automation.buildTempoAutomation(false, 0, 0, 0);
			if (this._versionNumber >= 500) {
				this.readPageSetup();
				this._initialTempo.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			}
			this._initialTempo.value = IOHelper.readInt32LE(this.data);
			if (this._versionNumber >= 510) GpBinaryHelpers.gpReadBool(this.data);
			IOHelper.readInt32LE(this.data);
			if (this._versionNumber >= 400) this.data.readByte();
			this.readPlaybackInfos();
			if (this._versionNumber >= 500) {
				this._readDirection(Direction.TargetCoda);
				this._readDirection(Direction.TargetDoubleCoda);
				this._readDirection(Direction.TargetSegno);
				this._readDirection(Direction.TargetSegnoSegno);
				this._readDirection(Direction.TargetFine);
				this._readDirection(Direction.JumpDaCapo);
				this._readDirection(Direction.JumpDaCapoAlCoda);
				this._readDirection(Direction.JumpDaCapoAlDoubleCoda);
				this._readDirection(Direction.JumpDaCapoAlFine);
				this._readDirection(Direction.JumpDalSegno);
				this._readDirection(Direction.JumpDalSegnoAlCoda);
				this._readDirection(Direction.JumpDalSegnoAlDoubleCoda);
				this._readDirection(Direction.JumpDalSegnoAlFine);
				this._readDirection(Direction.JumpDalSegnoSegno);
				this._readDirection(Direction.JumpDalSegnoSegnoAlCoda);
				this._readDirection(Direction.JumpDalSegnoSegnoAlDoubleCoda);
				this._readDirection(Direction.JumpDalSegnoSegnoAlFine);
				this._readDirection(Direction.JumpDaCoda);
				this._readDirection(Direction.JumpDaDoubleCoda);
				this.data.skip(4);
			}
			this._barCount = IOHelper.readInt32LE(this.data);
			this._ensureLoopBoundary(this._barCount, Gp3To5Importer._maxBarCount, "bar count");
			this._trackCount = IOHelper.readInt32LE(this.data);
			this._ensureLoopBoundary(this._trackCount, Gp3To5Importer._maxTrackCount, "track count");
			this.readMasterBars();
			this.readTracks();
			this.readBars();
			if (this._score.masterBars.length > 0) {
				const automation = Automation.buildTempoAutomation(false, 0, this._score.tempo, 2);
				automation.text = this._score.tempoLabel;
				this._score.masterBars[0].tempoAutomations.push(automation);
			}
			ModelUtils.consolidate(this._score);
			this._score.finish(this.settings);
			if (this._lyrics && this._lyricsTrack >= 0) this._score.tracks[this._lyricsTrack].applyLyrics(this._lyrics);
			return this._score;
		}
		_readDirection(direction) {
			let directionIndex = IOHelper.readInt16LE(this.data);
			if (directionIndex === -1) return;
			directionIndex--;
			let directionsList;
			if (this._directionLookup.has(directionIndex)) directionsList = this._directionLookup.get(directionIndex);
			else {
				directionsList = [];
				this._directionLookup.set(directionIndex, directionsList);
			}
			directionsList.push(direction);
		}
		readVersion() {
			let version = GpBinaryHelpers.gpReadStringByteLength(this.data, 30, this.settings.importer.encoding);
			if (!version.startsWith(Gp3To5Importer._versionString)) throw new UnsupportedFormatError("Unsupported format");
			version = version.substr(Gp3To5Importer._versionString.length + 1);
			const dot = version.indexOf(String.fromCharCode(46));
			this._versionNumber = 100 * Number.parseInt(version.substr(0, dot), 10) + Number.parseInt(version.substr(dot + 1), 10);
			Logger.debug(this.name, `Guitar Pro version ${version} detected`);
		}
		readScoreInformation() {
			this._score.title = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			this._score.subTitle = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			this._score.artist = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			this._score.album = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			this._score.words = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			this._score.music = this._versionNumber >= 500 ? GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize) : this._score.words;
			this._score.copyright = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			this._score.tab = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			this._score.instructions = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			const noticeLines = IOHelper.readInt32LE(this.data);
			this._ensureLoopBoundary(noticeLines, Gp3To5Importer._maxNoticeLines, "notice line count");
			let notice = "";
			for (let i = 0; i < noticeLines; i++) {
				if (i > 0) notice += "\r\n";
				notice += GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize)?.toString();
			}
			this._score.notices = notice;
		}
		static _maxNoticeLines = 1e3;
		static _maxBarCount = 1e3;
		static _maxTrackCount = 100;
		static _maxBeatCount = 100;
		static _maxBendPointCount = BendPoint.MaxPosition * 4;
		_ensureLoopBoundary(value, maximumValue, label) {
			if (value > maximumValue) throw new OverflowError(`'${label}' with value ${value} has exceeded the internal safety threshold of ${maximumValue}`);
		}
		readLyrics() {
			this._lyrics = [];
			this._lyricsTrack = IOHelper.readInt32LE(this.data) - 1;
			for (let i = 0; i < 5; i++) {
				const lyrics = new Lyrics();
				lyrics.startBar = IOHelper.readInt32LE(this.data) - 1;
				lyrics.text = GpBinaryHelpers.gpReadStringInt(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
				this._lyrics.push(lyrics);
			}
		}
		readPageSetup() {
			this.data.skip(28);
			const flags = IOHelper.readInt16LE(this.data);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Title).isVisible = (flags & 1) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Title).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.SubTitle).isVisible = (flags & 2) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.SubTitle).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Artist).isVisible = (flags & 4) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Artist).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Album).isVisible = (flags & 8) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Album).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Words).isVisible = (flags & 16) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Words).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Music).isVisible = (flags & 32) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Music).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.WordsAndMusic).isVisible = (flags & 64) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.WordsAndMusic).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Copyright).isVisible = (flags & 128) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.Copyright).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.CopyrightSecondLine).isVisible = (flags & 128) !== 0;
			ModelUtils.getOrCreateHeaderFooterStyle(this._score, ScoreSubElement.CopyrightSecondLine).template = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
		}
		readPlaybackInfos() {
			this._playbackInfos = [];
			let channel = 0;
			for (let i = 0; i < 64; i++) {
				const info = new PlaybackInformation();
				info.primaryChannel = channel++;
				info.secondaryChannel = channel++;
				info.program = IOHelper.readInt32LE(this.data);
				info.volume = this.data.readByte();
				info.balance = this.data.readByte();
				this.data.skip(6);
				this._playbackInfos.push(info);
			}
		}
		readMasterBars() {
			for (let i = 0; i < this._barCount; i++) this.readMasterBar();
		}
		readMasterBar() {
			let previousMasterBar = null;
			if (this._score.masterBars.length > 0) previousMasterBar = this._score.masterBars[this._score.masterBars.length - 1];
			const newMasterBar = new MasterBar();
			if (!previousMasterBar && this._initialTempo.value > 0) newMasterBar.tempoAutomations.push(this._initialTempo);
			const flags = this.data.readByte();
			if ((flags & 1) !== 0) newMasterBar.timeSignatureNumerator = this.data.readByte();
			else if (previousMasterBar) newMasterBar.timeSignatureNumerator = previousMasterBar.timeSignatureNumerator;
			if ((flags & 2) !== 0) newMasterBar.timeSignatureDenominator = this.data.readByte();
			else if (previousMasterBar) newMasterBar.timeSignatureDenominator = previousMasterBar.timeSignatureDenominator;
			newMasterBar.isRepeatStart = (flags & 4) !== 0;
			if ((flags & 8) !== 0) newMasterBar.repeatCount = this.data.readByte() + (this._versionNumber >= 500 ? 0 : 1);
			if ((flags & 16) !== 0 && this._versionNumber < 500) {
				let currentMasterBar = previousMasterBar;
				let existentAlternatives = 0;
				while (currentMasterBar) {
					if (currentMasterBar.isRepeatEnd && currentMasterBar !== previousMasterBar) break;
					if (currentMasterBar.isRepeatStart) break;
					existentAlternatives = existentAlternatives | currentMasterBar.alternateEndings;
					currentMasterBar = currentMasterBar.previousMasterBar;
				}
				let repeatAlternative = 0;
				const repeatMask = this.data.readByte();
				for (let i = 0; i < 8; i++) {
					const repeating = 1 << i;
					if (repeatMask > i && (existentAlternatives & repeating) === 0) repeatAlternative = repeatAlternative | repeating;
				}
				newMasterBar.alternateEndings = repeatAlternative;
			}
			if ((flags & 32) !== 0) {
				const section = new Section();
				section.text = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
				section.marker = "";
				GpBinaryHelpers.gpReadColor(this.data, false);
				newMasterBar.section = section;
			}
			if ((flags & 64) !== 0) this._keySignatures.set(this._score.masterBars.length, [IOHelper.readSInt8(this.data), this.data.readByte()]);
			if (this._versionNumber >= 500 && (flags & 3) !== 0) this.data.skip(4);
			if (this._versionNumber >= 500) newMasterBar.alternateEndings = this.data.readByte();
			if (this._versionNumber >= 500) {
				switch (this.data.readByte()) {
					case 1:
						newMasterBar.tripletFeel = TripletFeel.Triplet8th;
						break;
					case 2:
						newMasterBar.tripletFeel = TripletFeel.Triplet16th;
						break;
				}
				this.data.readByte();
			} else newMasterBar.tripletFeel = this._globalTripletFeel;
			const isDoubleBar = (flags & 128) !== 0;
			newMasterBar.isDoubleBar = isDoubleBar;
			const barIndexForDirection = this._score.masterBars.length;
			if (this._directionLookup.has(barIndexForDirection)) for (const direction of this._directionLookup.get(barIndexForDirection)) newMasterBar.addDirection(direction);
			this._score.addMasterBar(newMasterBar);
			if (isDoubleBar) this._doubleBars.add(newMasterBar.index);
		}
		readTracks() {
			for (let i = 0; i < this._trackCount; i++) this.readTrack();
		}
		/**
		* Guitar Pro 3-6 changes to a bass clef if any string tuning is below B1
		*/
		static _bassClefTuningThreshold = ModelUtils.parseTuning("B1").realValue;
		readTrack() {
			const newTrack = new Track();
			newTrack.ensureStaveCount(1);
			this._score.addTrack(newTrack);
			const mainStaff = newTrack.staves[0];
			const flags = this.data.readByte();
			newTrack.name = GpBinaryHelpers.gpReadStringByteLength(this.data, 40, this.settings.importer.encoding);
			if ((flags & 1) !== 0) mainStaff.isPercussion = true;
			if (this._versionNumber >= 500) newTrack.isVisibleOnMultiTrack = (flags & 8) !== 0;
			if (this._score.stylesheet.perTrackDisplayTuning === null) this._score.stylesheet.perTrackDisplayTuning = /* @__PURE__ */ new Map();
			this._score.stylesheet.perTrackDisplayTuning.set(newTrack.index, (flags & 128) !== 0);
			const stringCount = IOHelper.readInt32LE(this.data);
			const tuning = [];
			for (let i = 0; i < 7; i++) {
				const stringTuning = IOHelper.readInt32LE(this.data);
				if (stringCount > i) tuning.push(stringTuning);
			}
			mainStaff.stringTuning.tunings = tuning;
			const port = IOHelper.readInt32LE(this.data);
			const index = IOHelper.readInt32LE(this.data) - 1;
			const effectChannel = IOHelper.readInt32LE(this.data) - 1;
			this.data.skip(4);
			if (index >= 0 && index < this._playbackInfos.length) {
				const info = this._playbackInfos[index];
				info.port = port;
				info.isSolo = (flags & 16) !== 0;
				info.isMute = (flags & 32) !== 0;
				info.secondaryChannel = effectChannel;
				if (GeneralMidi.isGuitar(info.program)) mainStaff.displayTranspositionPitch = -12;
				newTrack.playbackInfo = info;
			}
			mainStaff.capo = IOHelper.readInt32LE(this.data);
			newTrack.color = GpBinaryHelpers.gpReadColor(this.data, false);
			if (this._versionNumber >= 500) {
				const staffFlags = this.data.readByte();
				mainStaff.showTablature = (staffFlags & 1) !== 0;
				mainStaff.showStandardNotation = (staffFlags & 2) !== 0;
				const showChordDiagramListOnTopOfScore = (staffFlags & 100) !== 0;
				if (this._score.stylesheet.perTrackChordDiagramsOnTop === null) this._score.stylesheet.perTrackChordDiagramsOnTop = /* @__PURE__ */ new Map();
				this._score.stylesheet.perTrackChordDiagramsOnTop.set(newTrack.index, showChordDiagramListOnTopOfScore);
				this.data.readByte();
				this.data.readByte();
				newTrack.playbackInfo.bank = this.data.readByte();
				this.data.readByte();
				if (IOHelper.readInt32LE(this.data) === 12 || tuning[tuning.length - 1] < Gp3To5Importer._bassClefTuningThreshold) this._clefsPerTrack.set(newTrack.index, Clef.F4);
				else this._clefsPerTrack.set(newTrack.index, Clef.G2);
				IOHelper.readInt32LE(this.data);
				IOHelper.readInt32LE(this.data);
				this.data.skip(10);
				this.data.readByte();
				this.data.readByte();
				this._readRseBank();
				if (this._versionNumber >= 510) {
					this.data.skip(4);
					GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
					GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
				}
			} else if (tuning[tuning.length - 1] < Gp3To5Importer._bassClefTuningThreshold) this._clefsPerTrack.set(newTrack.index, Clef.F4);
			else this._clefsPerTrack.set(newTrack.index, Clef.G2);
		}
		readBars() {
			for (let i = 0; i < this._barCount; i++) for (let t = 0; t < this._trackCount; t++) this.readBar(this._score.tracks[t]);
		}
		readBar(track) {
			const newBar = new Bar();
			const mainStaff = track.staves[0];
			if (mainStaff.isPercussion) newBar.clef = Clef.Neutral;
			else if (this._clefsPerTrack.has(track.index)) newBar.clef = this._clefsPerTrack.get(track.index);
			mainStaff.addBar(newBar);
			if (this._keySignatures.has(newBar.index)) {
				const newKeySignature = this._keySignatures.get(newBar.index);
				newBar.keySignature = newKeySignature[0];
				newBar.keySignatureType = newKeySignature[1];
			} else if (newBar.index > 0) {
				newBar.keySignature = newBar.previousBar.keySignature;
				newBar.keySignatureType = newBar.previousBar.keySignatureType;
			}
			if (this._doubleBars.has(newBar.index)) newBar.barLineRight = BarLineStyle.LightLight;
			let voiceCount = 1;
			if (this._versionNumber >= 500) {
				this.data.readByte();
				voiceCount = 2;
			}
			for (let v = 0; v < voiceCount; v++) this.readVoice(track, newBar);
		}
		readVoice(track, bar) {
			const beatCount = IOHelper.readInt32LE(this.data);
			if (beatCount === 0) return;
			const newVoice = new Voice$1();
			bar.addVoice(newVoice);
			this._ensureLoopBoundary(beatCount, Gp3To5Importer._maxBeatCount, "beat count");
			for (let i = 0; i < beatCount; i++) this.readBeat(track, bar, newVoice);
		}
		readBeat(track, bar, voice) {
			const newBeat = new Beat();
			const flags = this.data.readByte();
			if ((flags & 1) !== 0) newBeat.dots = 1;
			if ((flags & 64) !== 0) newBeat.isEmpty = (this.data.readByte() & 2) === 0;
			voice.addBeat(newBeat);
			switch (IOHelper.readSInt8(this.data)) {
				case -2:
					newBeat.duration = Duration.Whole;
					break;
				case -1:
					newBeat.duration = Duration.Half;
					break;
				case 0:
					newBeat.duration = Duration.Quarter;
					break;
				case 1:
					newBeat.duration = Duration.Eighth;
					break;
				case 2:
					newBeat.duration = Duration.Sixteenth;
					break;
				case 3:
					newBeat.duration = Duration.ThirtySecond;
					break;
				case 4:
					newBeat.duration = Duration.SixtyFourth;
					break;
				default:
					newBeat.duration = Duration.Quarter;
					break;
			}
			if ((flags & 32) !== 0) {
				newBeat.tupletNumerator = IOHelper.readInt32LE(this.data);
				switch (newBeat.tupletNumerator) {
					case 1:
						newBeat.tupletDenominator = 1;
						break;
					case 3:
						newBeat.tupletDenominator = 2;
						break;
					case 5:
					case 6:
					case 7:
						newBeat.tupletDenominator = 4;
						break;
					case 9:
					case 10:
					case 11:
					case 12:
					case 13:
						newBeat.tupletDenominator = 8;
						break;
					case 2:
					case 4:
					case 8: break;
					default:
						newBeat.tupletNumerator = 1;
						newBeat.tupletDenominator = 1;
						break;
				}
			}
			if ((flags & 2) !== 0) this.readChord(newBeat);
			const beatTextAsLyrics = this.settings.importer.beatTextAsLyrics && track.index !== this._lyricsTrack;
			if ((flags & 4) !== 0) {
				const text = GpBinaryHelpers.gpReadStringIntUnused(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
				if (beatTextAsLyrics) {
					const lyrics = new Lyrics();
					lyrics.text = text.trim();
					lyrics.finish(true);
					const beatLyrics = [];
					for (let i = lyrics.chunks.length - 1; i >= 0; i--) beatLyrics.push(lyrics.chunks[i]);
					this._beatTextChunksByTrack.set(track.index, beatLyrics);
				} else newBeat.text = text;
			}
			let allNoteHarmonicType = HarmonicType.None;
			if ((flags & 8) !== 0) allNoteHarmonicType = this.readBeatEffects(newBeat);
			if ((flags & 16) !== 0) this.readMixTableChange(newBeat);
			const stringFlags = this.data.readByte();
			for (let i = 6; i >= 0; i--) if ((stringFlags & 1 << i) !== 0 && 6 - i < bar.staff.tuning.length) {
				const note = this.readNote(track, bar, voice, newBeat, 6 - i);
				if (allNoteHarmonicType !== HarmonicType.None) {
					note.harmonicType = allNoteHarmonicType;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(note.fret);
				}
			}
			if (this._versionNumber >= 500) {
				const flags2 = IOHelper.readInt16LE(this.data);
				if ((flags2 & 1) !== 0) {
					if (newBeat.index > 0) voice.beats[newBeat.index - 1].beamingMode = BeatBeamingMode.ForceSplitToNext;
				}
				if ((flags2 & 2) !== 0) newBeat.preferredBeamDirection = BeamDirection.Down;
				if ((flags2 & 4) !== 0) {
					if (newBeat.index > 0) voice.beats[newBeat.index - 1].beamingMode = BeatBeamingMode.ForceMergeWithNext;
				}
				if ((flags2 & 8) !== 0) newBeat.preferredBeamDirection = BeamDirection.Up;
				if ((flags2 & 16) !== 0) newBeat.ottava = Ottavia._8va;
				if ((flags2 & 32) !== 0) newBeat.ottava = Ottavia._8vb;
				if ((flags2 & 64) !== 0) newBeat.ottava = Ottavia._15ma;
				if ((flags2 & 256) !== 0) newBeat.ottava = Ottavia._15mb;
				if ((flags2 & 2048) !== 0) {
					const breakSecondaryBeams = this.data.readByte() !== 0;
					if (newBeat.index > 0 && breakSecondaryBeams) voice.beats[newBeat.index - 1].beamingMode = BeatBeamingMode.ForceSplitOnSecondaryToNext;
				}
			}
			if (beatTextAsLyrics && !newBeat.isRest && this._beatTextChunksByTrack.has(track.index) && this._beatTextChunksByTrack.get(track.index).length > 0) newBeat.lyrics = [this._beatTextChunksByTrack.get(track.index).pop()];
		}
		readChord(beat) {
			const chord = new Chord();
			const chordId = ModelUtils.newGuid();
			if (this._versionNumber >= 500) {
				this.data.skip(17);
				chord.name = GpBinaryHelpers.gpReadStringByteLength(this.data, 21, this.settings.importer.encoding);
				this.data.skip(4);
				chord.firstFret = IOHelper.readInt32LE(this.data);
				for (let i = 0; i < 7; i++) {
					const fret = IOHelper.readInt32LE(this.data);
					if (i < beat.voice.bar.staff.tuning.length) chord.strings.push(fret);
				}
				const numberOfBarres = this.data.readByte();
				const barreFrets = new Uint8Array(5);
				this.data.read(barreFrets, 0, barreFrets.length);
				for (let i = 0; i < numberOfBarres; i++) chord.barreFrets.push(barreFrets[i]);
				this.data.skip(26);
			} else if (this.data.readByte() !== 0) if (this._versionNumber >= 400) {
				this.data.skip(16);
				chord.name = GpBinaryHelpers.gpReadStringByteLength(this.data, 21, this.settings.importer.encoding);
				this.data.skip(4);
				chord.firstFret = IOHelper.readInt32LE(this.data);
				for (let i = 0; i < 7; i++) {
					const fret = IOHelper.readInt32LE(this.data);
					if (i < beat.voice.bar.staff.tuning.length) chord.strings.push(fret);
				}
				const numberOfBarres = this.data.readByte();
				const barreFrets = new Uint8Array(5);
				this.data.read(barreFrets, 0, barreFrets.length);
				for (let i = 0; i < numberOfBarres; i++) chord.barreFrets.push(barreFrets[i]);
				this.data.skip(26);
			} else {
				this.data.skip(25);
				chord.name = GpBinaryHelpers.gpReadStringByteLength(this.data, 34, this.settings.importer.encoding);
				chord.firstFret = IOHelper.readInt32LE(this.data);
				for (let i = 0; i < 6; i++) {
					const fret = IOHelper.readInt32LE(this.data);
					if (i < beat.voice.bar.staff.tuning.length) chord.strings.push(fret);
				}
				this.data.skip(36);
			}
			else {
				const strings = this._versionNumber >= 406 ? 7 : 6;
				chord.name = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
				chord.firstFret = IOHelper.readInt32LE(this.data);
				if (chord.firstFret > 0) for (let i = 0; i < strings; i++) {
					const fret = IOHelper.readInt32LE(this.data);
					if (i < beat.voice.bar.staff.tuning.length) chord.strings.push(fret);
				}
			}
			if (chord.name) {
				beat.chordId = chordId;
				beat.voice.bar.staff.addChord(beat.chordId, chord);
			}
		}
		readBeatEffects(beat) {
			const flags = this.data.readByte();
			let flags2 = 0;
			if (this._versionNumber >= 400) flags2 = this.data.readByte();
			if ((flags & 16) !== 0) beat.fade = FadeType.FadeIn;
			if (this._versionNumber < 400 && (flags & 1) !== 0 || (flags & 2) !== 0) beat.vibrato = VibratoType.Slight;
			if ((flags2 & 1) !== 0) beat.rasgueado = Rasgueado.Ii;
			if ((flags & 32) !== 0 && this._versionNumber >= 400) switch (IOHelper.readSInt8(this.data)) {
				case 1:
					beat.tap = true;
					break;
				case 2:
					beat.slap = true;
					break;
				case 3:
					beat.pop = true;
					break;
			}
			else if ((flags & 32) !== 0) {
				switch (IOHelper.readSInt8(this.data)) {
					case 1:
						beat.tap = true;
						break;
					case 2:
						beat.slap = true;
						break;
					case 3:
						beat.pop = true;
						break;
				}
				this.data.skip(4);
			}
			if ((flags2 & 4) !== 0) this.readTremoloBarEffect(beat);
			if ((flags & 64) !== 0) {
				let strokeUp = 0;
				let strokeDown = 0;
				if (this._versionNumber < 500) {
					strokeDown = this.data.readByte();
					strokeUp = this.data.readByte();
				} else {
					strokeUp = this.data.readByte();
					strokeDown = this.data.readByte();
				}
				if (strokeUp > 0) {
					beat.brushType = BrushType.BrushUp;
					beat.brushDuration = Gp3To5Importer._toStrokeValue(strokeUp);
				} else if (strokeDown > 0) {
					beat.brushType = BrushType.BrushDown;
					beat.brushDuration = Gp3To5Importer._toStrokeValue(strokeDown);
				}
			}
			if ((flags2 & 2) !== 0) switch (IOHelper.readSInt8(this.data)) {
				case 0:
					beat.pickStroke = PickStroke.None;
					break;
				case 1:
					beat.pickStroke = PickStroke.Up;
					break;
				case 2:
					beat.pickStroke = PickStroke.Down;
					break;
			}
			if (this._versionNumber < 400) {
				if ((flags & 4) !== 0) return HarmonicType.Natural;
				if ((flags & 8) !== 0) return HarmonicType.Artificial;
			}
			return HarmonicType.None;
		}
		readTremoloBarEffect(beat) {
			this.data.readByte();
			IOHelper.readInt32LE(this.data);
			const pointCount = IOHelper.readInt32LE(this.data);
			this._ensureLoopBoundary(pointCount, Gp3To5Importer._maxBendPointCount, "tremolo bar point count");
			if (pointCount > 0) for (let i = 0; i < pointCount; i++) {
				const point = new BendPoint(0, 0);
				point.offset = IOHelper.readInt32LE(this.data);
				point.value = IOHelper.readInt32LE(this.data) / Gp3To5Importer._bendStep | 0;
				GpBinaryHelpers.gpReadBool(this.data);
				beat.addWhammyBarPoint(point);
			}
		}
		static _toStrokeValue(value) {
			switch (value) {
				case 1: return 30;
				case 2: return 30;
				case 3: return 60;
				case 4: return 120;
				case 5: return 240;
				case 6: return 480;
				default: return 0;
			}
		}
		_readRseBank() {
			this.data.skip(4);
			this.data.skip(4);
			this.data.skip(4);
			this.data.skip(4);
		}
		readMixTableChange(beat) {
			const tableChange = new MixTableChange();
			tableChange.instrument = IOHelper.readSInt8(this.data);
			if (this._versionNumber >= 500) this._readRseBank();
			tableChange.volume = IOHelper.readSInt8(this.data);
			tableChange.balance = IOHelper.readSInt8(this.data);
			const chorus = IOHelper.readSInt8(this.data);
			const reverb = IOHelper.readSInt8(this.data);
			const phaser = IOHelper.readSInt8(this.data);
			const tremolo = IOHelper.readSInt8(this.data);
			if (this._versionNumber >= 500) tableChange.tempoName = GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			tableChange.tempo = IOHelper.readInt32LE(this.data);
			if (tableChange.volume >= 0) this.data.readByte();
			if (tableChange.balance >= 0) this.data.readByte();
			if (chorus >= 0) this.data.readByte();
			if (reverb >= 0) this.data.readByte();
			if (phaser >= 0) this.data.readByte();
			if (tremolo >= 0) this.data.readByte();
			if (tableChange.tempo >= 0) {
				tableChange.duration = IOHelper.readSInt8(this.data);
				if (this._versionNumber >= 510) this.data.readByte();
			}
			if (this._versionNumber >= 400) this.data.readByte();
			if (this._versionNumber >= 500) {
				const wahType = IOHelper.readSInt8(this.data);
				if (wahType >= 100) beat.wahPedal = WahPedal.Closed;
				else if (wahType >= 0) beat.wahPedal = WahPedal.Open;
			}
			if (this._versionNumber >= 510) {
				GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
				GpBinaryHelpers.gpReadStringIntByte(this.data, this.settings.importer.encoding, this.settings.importer.maxDecodingBufferSize);
			}
			if (tableChange.volume >= 0) {
				const volumeAutomation = new Automation();
				volumeAutomation.isLinear = true;
				volumeAutomation.type = AutomationType.Volume;
				volumeAutomation.value = tableChange.volume;
				beat.automations.push(volumeAutomation);
			}
			if (tableChange.balance >= 0) {
				const balanceAutomation = new Automation();
				balanceAutomation.isLinear = true;
				balanceAutomation.type = AutomationType.Balance;
				balanceAutomation.value = tableChange.balance;
				beat.automations.push(balanceAutomation);
			}
			if (tableChange.instrument >= 0) {
				const instrumentAutomation = new Automation();
				instrumentAutomation.isLinear = true;
				instrumentAutomation.type = AutomationType.Instrument;
				instrumentAutomation.value = tableChange.instrument;
				beat.automations.push(instrumentAutomation);
			}
			if (tableChange.tempo >= 0) {
				const tempoAutomation = new Automation();
				tempoAutomation.isLinear = true;
				tempoAutomation.type = AutomationType.Tempo;
				tempoAutomation.value = tableChange.tempo;
				beat.automations.push(tempoAutomation);
				if (!beat.voice.bar.masterBar.tempoAutomations.some((a) => a.ratioPosition === tempoAutomation.ratioPosition && a.value === tempoAutomation.value)) beat.voice.bar.masterBar.tempoAutomations.push(tempoAutomation);
			}
		}
		readNote(track, bar, voice, beat, stringIndex) {
			const newNote = new Note();
			newNote.string = bar.staff.tuning.length - stringIndex;
			const flags = this.data.readByte();
			if ((flags & 2) !== 0) newNote.accentuated = AccentuationType.Heavy;
			else if ((flags & 64) !== 0) newNote.accentuated = AccentuationType.Normal;
			newNote.isGhost = (flags & 4) !== 0;
			if ((flags & 32) !== 0) {
				const noteType = this.data.readByte();
				if (noteType === 3) newNote.isDead = true;
				else if (noteType === 2) newNote.isTieDestination = true;
			}
			if ((flags & 1) !== 0 && this._versionNumber < 500) {
				this.data.readByte();
				this.data.readByte();
			}
			if ((flags & 16) !== 0) {
				const dynamicNumber = IOHelper.readSInt8(this.data);
				newNote.dynamics = this.toDynamicValue(dynamicNumber);
				beat.dynamics = newNote.dynamics;
			}
			if ((flags & 32) !== 0) newNote.fret = IOHelper.readSInt8(this.data);
			if ((flags & 128) !== 0) {
				newNote.leftHandFinger = IOHelper.readSInt8(this.data);
				newNote.rightHandFinger = IOHelper.readSInt8(this.data);
			}
			let swapAccidentals = false;
			if (this._versionNumber >= 500) {
				if ((flags & 1) !== 0) newNote.durationPercent = IOHelper.readFloat64BE(this.data);
				swapAccidentals = (this.data.readByte() & 2) !== 0;
			}
			beat.addNote(newNote);
			if ((flags & 8) !== 0) this.readNoteEffects(track, voice, beat, newNote);
			if (bar.staff.isPercussion) {
				newNote.percussionArticulation = Gp3To5Importer._gp5PercussionInstrumentMap.has(newNote.fret) ? Gp3To5Importer._gp5PercussionInstrumentMap.get(newNote.fret) : newNote.fret;
				newNote.string = -1;
				newNote.fret = -1;
			}
			if (swapAccidentals) {
				const accidental = ModelUtils.computeAccidental(bar.keySignature, NoteAccidentalMode.Default, newNote.realValueWithoutHarmonic, false);
				if (accidental === AccidentalType.Sharp) newNote.accidentalMode = NoteAccidentalMode.ForceFlat;
				else if (accidental === AccidentalType.Flat) newNote.accidentalMode = NoteAccidentalMode.ForceSharp;
			}
			return newNote;
		}
		toDynamicValue(value) {
			switch (value) {
				case 1: return DynamicValue.PPP;
				case 2: return DynamicValue.PP;
				case 3: return DynamicValue.P;
				case 4: return DynamicValue.MP;
				case 5: return DynamicValue.MF;
				case 6: return DynamicValue.F;
				case 7: return DynamicValue.FF;
				case 8: return DynamicValue.FFF;
				default: return DynamicValue.F;
			}
		}
		readNoteEffects(_track, voice, beat, note) {
			const flags = this.data.readByte();
			let flags2 = 0;
			if (this._versionNumber >= 400) flags2 = this.data.readByte();
			if ((flags & 1) !== 0) this.readBend(note);
			if ((flags & 16) !== 0) this.readGrace(voice, note);
			if ((flags2 & 4) !== 0) this.readTremoloPicking(beat);
			if ((flags2 & 8) !== 0) this.readSlide(note);
			else if (this._versionNumber < 400) {
				if ((flags & 4) !== 0) note.slideOutType = SlideOutType.Shift;
			}
			if ((flags2 & 16) !== 0) this.readArtificialHarmonic(note);
			if ((flags2 & 32) !== 0) this.readTrill(note);
			note.isLetRing = (flags & 8) !== 0;
			note.isHammerPullOrigin = (flags & 2) !== 0;
			if ((flags2 & 64) !== 0) note.vibrato = VibratoType.Slight;
			note.isPalmMute = (flags2 & 2) !== 0;
			note.isStaccato = (flags2 & 1) !== 0;
		}
		static _bendStep = 25;
		readBend(note) {
			this.data.readByte();
			IOHelper.readInt32LE(this.data);
			const pointCount = IOHelper.readInt32LE(this.data);
			this._ensureLoopBoundary(pointCount, Gp3To5Importer._maxBendPointCount, "note bend point count");
			if (pointCount > 0) for (let i = 0; i < pointCount; i++) {
				const point = new BendPoint(0, 0);
				point.offset = IOHelper.readInt32LE(this.data);
				point.value = IOHelper.readInt32LE(this.data) / Gp3To5Importer._bendStep | 0;
				GpBinaryHelpers.gpReadBool(this.data);
				note.addBendPoint(point);
			}
		}
		readGrace(voice, note) {
			const graceBeat = new Beat();
			const graceNote = new Note();
			graceNote.string = note.string;
			graceNote.fret = IOHelper.readSInt8(this.data);
			graceBeat.duration = Duration.ThirtySecond;
			graceBeat.dynamics = this.toDynamicValue(IOHelper.readSInt8(this.data));
			switch (IOHelper.readSInt8(this.data)) {
				case 0: break;
				case 1:
					graceNote.slideOutType = SlideOutType.Legato;
					graceNote.slideTarget = note;
					break;
				case 2: break;
				case 3:
					graceNote.isHammerPullOrigin = true;
					break;
			}
			graceNote.dynamics = graceBeat.dynamics;
			this.data.skip(1);
			if (this._versionNumber < 500) graceBeat.graceType = GraceType.BeforeBeat;
			else {
				const flags = this.data.readByte();
				graceNote.isDead = (flags & 1) !== 0;
				graceBeat.graceType = (flags & 2) !== 0 ? GraceType.OnBeat : GraceType.BeforeBeat;
			}
			voice.addGraceBeat(graceBeat);
			graceBeat.addNote(graceNote);
		}
		readTremoloPicking(beat) {
			const effect = new TremoloPickingEffect();
			beat.tremoloPicking = effect;
			effect.marks = this.data.readByte();
		}
		readSlide(note) {
			if (this._versionNumber >= 500) {
				const type = IOHelper.readSInt8(this.data);
				if ((type & 1) !== 0) note.slideOutType = SlideOutType.Shift;
				else if ((type & 2) !== 0) note.slideOutType = SlideOutType.Legato;
				else if ((type & 4) !== 0) note.slideOutType = SlideOutType.OutDown;
				else if ((type & 8) !== 0) note.slideOutType = SlideOutType.OutUp;
				if ((type & 16) !== 0) note.slideInType = SlideInType.IntoFromBelow;
				else if ((type & 32) !== 0) note.slideInType = SlideInType.IntoFromAbove;
			} else switch (IOHelper.readSInt8(this.data)) {
				case 1:
					note.slideOutType = SlideOutType.Shift;
					break;
				case 2:
					note.slideOutType = SlideOutType.Legato;
					break;
				case 3:
					note.slideOutType = SlideOutType.OutDown;
					break;
				case 4:
					note.slideOutType = SlideOutType.OutUp;
					break;
				case -1:
					note.slideInType = SlideInType.IntoFromBelow;
					break;
				case -2:
					note.slideInType = SlideInType.IntoFromAbove;
					break;
			}
		}
		readArtificialHarmonic(note) {
			const type = this.data.readByte();
			if (this._versionNumber >= 500) switch (type) {
				case 1:
					note.harmonicType = HarmonicType.Natural;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(note.fret);
					break;
				case 2:
					const harmonicTone = this.data.readByte();
					let harmonicKey = this.data.readByte();
					if (harmonicKey === 255) harmonicKey = -1;
					const harmonicOctaveOffset = this.data.readByte();
					const harmonicPitch = harmonicTone + harmonicKey;
					const playedPitch = (note.fret + note.stringTuning) % 12;
					let targetHarmonic = harmonicPitch + harmonicOctaveOffset * 12;
					if (targetHarmonic < playedPitch) targetHarmonic += 12;
					const deltaFrets = targetHarmonic - playedPitch;
					note.harmonicType = HarmonicType.Artificial;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(deltaFrets);
					break;
				case 3:
					note.harmonicType = HarmonicType.Tap;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(this.data.readByte());
					break;
				case 4:
					note.harmonicType = HarmonicType.Pinch;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(12);
					break;
				case 5:
					note.harmonicType = HarmonicType.Semi;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(12);
					break;
			}
			else if (this._versionNumber >= 400) switch (type) {
				case 1:
					note.harmonicType = HarmonicType.Natural;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(note.fret);
					break;
				case 3:
					note.harmonicType = HarmonicType.Tap;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(12);
					break;
				case 4:
					note.harmonicType = HarmonicType.Pinch;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(12);
					break;
				case 5:
					note.harmonicType = HarmonicType.Semi;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(12);
					break;
				case 15:
					note.harmonicType = HarmonicType.Artificial;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(5);
					break;
				case 17:
					note.harmonicType = HarmonicType.Artificial;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(7);
					break;
				case 22:
					note.harmonicType = HarmonicType.Artificial;
					note.harmonicValue = ModelUtils.deltaFretToHarmonicValue(12);
					break;
			}
		}
		readTrill(note) {
			note.trillValue = this.data.readByte() + note.stringTuning;
			switch (this.data.readByte()) {
				case 1:
					note.trillSpeed = Duration.Sixteenth;
					break;
				case 2:
					note.trillSpeed = Duration.ThirtySecond;
					break;
				case 3:
					note.trillSpeed = Duration.SixtyFourth;
					break;
			}
		}
	};
	/**
	* @internal
	*/
	var GpBinaryHelpers = class GpBinaryHelpers {
		static gpReadColor(data, readAlpha = false) {
			const r = data.readByte();
			const g = data.readByte();
			const b = data.readByte();
			let a = 255;
			if (readAlpha) a = data.readByte();
			else data.skip(1);
			return new Color(r, g, b, a);
		}
		static gpReadBool(data) {
			return data.readByte() !== 0;
		}
		/**
		* Skips an integer (4byte) and reads a string using
		* a bytesize
		*/
		static gpReadStringIntUnused(data, encoding, maxDecodingBufferSize) {
			data.skip(4);
			return GpBinaryHelpers.gpReadString(data, data.readByte(), encoding, maxDecodingBufferSize);
		}
		/**
		* Reads an integer as size, and then the string itself
		*/
		static gpReadStringInt(data, encoding, maxDecodingBufferSize) {
			return GpBinaryHelpers.gpReadString(data, IOHelper.readInt32LE(data), encoding, maxDecodingBufferSize);
		}
		/**
		* Reads an integer as size, skips a byte and reads the string itself
		*/
		static gpReadStringIntByte(data, encoding, maxDecodingBufferSize) {
			const length = IOHelper.readInt32LE(data) - 1;
			data.readByte();
			return GpBinaryHelpers.gpReadString(data, length, encoding, maxDecodingBufferSize);
		}
		static gpReadString(data, length, encoding, maxDecodingBufferSize) {
			if (length > maxDecodingBufferSize) throw new OverflowError(`Detected string exceeding maxDecodingBufferSize at offset ${data.position}`);
			const b = new Uint8Array(length);
			data.read(b, 0, b.length);
			return IOHelper.toString(b, encoding);
		}
		static gpWriteString(data, s) {
			const encoded = IOHelper.stringToBytes(s);
			data.writeByte(s.length);
			data.write(encoded, 0, encoded.length);
		}
		/**
		* Reads a byte as size and the string itself.
		* Additionally it is ensured the specified amount of bytes is read.
		* @param data the data to read from.
		* @param length the amount of bytes to read
		* @param encoding The encoding to use to decode the byte into a string
		* @returns
		*/
		static gpReadStringByteLength(data, length, encoding) {
			const stringLength = data.readByte();
			const fieldBytes = new Uint8Array(length);
			data.read(fieldBytes, 0, length);
			const effectiveLength = Math.min(stringLength, length);
			return IOHelper.toString(fieldBytes.subarray(0, effectiveLength), encoding);
		}
	};
	/**
	* A mixtablechange describes several track changes.
	* @internal
	*/
	var MixTableChange = class {
		volume = -1;
		balance = -1;
		instrument = -1;
		tempoName = "";
		tempo = -1;
		duration = -1;
	};
	//#endregion
	//#region src/rendering/utils/Bounds.ts
	/**
	* Represents a rectangular area within the renderer music notation.
	* @public
	*/
	var Bounds = class {
		/**
		* Gets or sets the X-position of the rectangle within the music notation.
		*/
		x;
		/**
		* Gets or sets the Y-position of the rectangle within the music notation.
		*/
		y;
		/**
		* Gets or sets the width of the rectangle.
		*/
		w;
		/**
		* Gets or sets the height of the rectangle.
		*/
		h;
		scaleWith(scale) {
			this.x *= scale;
			this.y *= scale;
			this.w *= scale;
			this.h *= scale;
		}
		constructor(x = 0, y = 0, w = 0, h = 0) {
			this.x = x;
			this.y = y;
			this.h = h;
			this.w = w;
		}
	};
	//#endregion
	//#region src/importer/BinaryStylesheet.ts
	/**
	* A BinaryStylesheet from Guitar Pro 6 and 7 files.
	* The BinaryStylesheet is a simple binary key-value store for additional settings
	* related to the display of the music sheet.
	*
	* File:
	*     int32 (big endian) | Number of KeyValuePairs
	*     KeyValuePair[]     | The raw records
	*
	* KeyValuePair:
	*     1 Byte  | length of the key
	*     n Bytes | key as utf8 encoded string
	*     1 Byte  | Data Type
	*     n Bytes | Value
	*
	* Values based on Data Type:
	*     0 = bool
	*         0===false
	*     1 = int32 (big endian)
	*     2 = float (big endian, IEEE)
	*     3 = string
	*       int16 (big endian) | length of string
	*       n bytes            | utf-8 encoded string
	*     4 = point
	*       int32 (big endian) | X-coordinate
	*       int32 (big endian) | Y-coordinate
	*     5 = size
	*       int32 (big endian) | Width
	*       int32 (big endian) | Height
	*     6 = rectangle
	*       int32 (big endian) | X-coordinate
	*       int32 (big endian) | Y-coordinate
	*       int32 (big endian) | Width
	*       int32 (big endian) | Height
	*     7 = color
	*       1 byte | Red
	*       1 byte | Green
	*       1 byte | Blue
	*       1 byte | Alpha
	* @internal
	*/
	var BinaryStylesheet = class BinaryStylesheet {
		_types = /* @__PURE__ */ new Map();
		raw = /* @__PURE__ */ new Map();
		constructor(data, maxDecodingBufferSize = 0) {
			if (data) this._read(data, maxDecodingBufferSize);
		}
		_read(data, maxDecodingBufferSize) {
			const readable = ByteBuffer.fromBuffer(data);
			const entryCount = IOHelper.readInt32BE(readable);
			for (let i = 0; i < entryCount; i++) {
				const key = GpBinaryHelpers.gpReadString(readable, readable.readByte(), "utf-8", maxDecodingBufferSize);
				const type = readable.readByte();
				this._types.set(key, type);
				switch (type) {
					case 0:
						const flag = readable.readByte() === 1;
						this.addValue(key, flag);
						break;
					case 1:
						const ivalue = IOHelper.readInt32BE(readable);
						this.addValue(key, ivalue);
						break;
					case 2:
						const fvalue = IOHelper.readFloat32BE(readable);
						this.addValue(key, fvalue);
						break;
					case 3:
						const s = GpBinaryHelpers.gpReadString(readable, IOHelper.readInt16BE(readable), "utf-8", maxDecodingBufferSize);
						this.addValue(key, s);
						break;
					case 4:
						const x = IOHelper.readInt32BE(readable);
						const y = IOHelper.readInt32BE(readable);
						this.addValue(key, new BendPoint(x, y));
						break;
					case 5:
						const width = IOHelper.readInt32BE(readable);
						const height = IOHelper.readInt32BE(readable);
						this.addValue(key, new BendPoint(width, height));
						break;
					case 6:
						const rect = new Bounds();
						rect.x = IOHelper.readInt32BE(readable);
						rect.y = IOHelper.readInt32BE(readable);
						rect.w = IOHelper.readInt32BE(readable);
						rect.h = IOHelper.readInt32BE(readable);
						this.addValue(key, rect);
						break;
					case 7:
						const color = GpBinaryHelpers.gpReadColor(readable, true);
						this.addValue(key, color);
						break;
				}
			}
		}
		apply(score) {
			for (const [key, value] of this.raw) switch (key) {
				case "StandardNotation/hideDynamics":
					score.stylesheet.hideDynamics = value;
					break;
				case "System/bracketExtendMode":
					score.stylesheet.bracketExtendMode = value;
					break;
				case "Global/useSystemSignSeparator":
					score.stylesheet.useSystemSignSeparator = value;
					break;
				case "Global/DisplayTuning":
					score.stylesheet.globalDisplayTuning = value;
					break;
				case "Global/DrawChords":
					score.stylesheet.globalDisplayChordDiagramsOnTop = value;
					break;
				case "System/drawChordInScore":
					score.stylesheet.globalDisplayChordDiagramsInScore = value;
					break;
				case "System/showTrackNameSingle":
					if (!value) score.stylesheet.singleTrackTrackNamePolicy = TrackNamePolicy.Hidden;
					break;
				case "System/showTrackNameMulti":
					if (!value) score.stylesheet.multiTrackTrackNamePolicy = TrackNamePolicy.Hidden;
					break;
				case "System/trackNameModeSingle":
					if (score.stylesheet.singleTrackTrackNamePolicy !== TrackNamePolicy.Hidden) switch (value) {
						case 0:
							score.stylesheet.singleTrackTrackNamePolicy = TrackNamePolicy.FirstSystem;
							break;
						case 1:
							score.stylesheet.singleTrackTrackNamePolicy = TrackNamePolicy.FirstSystem;
							break;
						case 2:
							score.stylesheet.singleTrackTrackNamePolicy = TrackNamePolicy.AllSystems;
							break;
					}
					break;
				case "System/trackNameModeMulti":
					if (score.stylesheet.multiTrackTrackNamePolicy !== TrackNamePolicy.Hidden) switch (value) {
						case 0:
							score.stylesheet.multiTrackTrackNamePolicy = TrackNamePolicy.FirstSystem;
							break;
						case 1:
							score.stylesheet.multiTrackTrackNamePolicy = TrackNamePolicy.FirstSystem;
							break;
						case 2:
							score.stylesheet.multiTrackTrackNamePolicy = TrackNamePolicy.AllSystems;
							break;
					}
					break;
				case "System/shortTrackNameOnFirstSystem":
					if (value) score.stylesheet.firstSystemTrackNameMode = TrackNameMode.ShortName;
					else score.stylesheet.firstSystemTrackNameMode = TrackNameMode.FullName;
					break;
				case "System/shortTrackNameOnOtherSystems":
					if (value) score.stylesheet.otherSystemsTrackNameMode = TrackNameMode.ShortName;
					else score.stylesheet.otherSystemsTrackNameMode = TrackNameMode.FullName;
					break;
				case "System/horizontalTrackNameOnFirstSystem":
					if (value) score.stylesheet.firstSystemTrackNameOrientation = TrackNameOrientation.Horizontal;
					else score.stylesheet.firstSystemTrackNameOrientation = TrackNameOrientation.Vertical;
					break;
				case "System/horizontalTrackNameOnOtherSystems":
					if (value) score.stylesheet.otherSystemsTrackNameOrientation = TrackNameOrientation.Horizontal;
					else score.stylesheet.otherSystemsTrackNameOrientation = TrackNameOrientation.Vertical;
					break;
				case "System/ExtendedBarLines":
					score.stylesheet.extendBarLines = value;
					break;
				case "Header/Title":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Title).template = value;
					break;
				case "Header/TitleAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Title).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawTitle":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Title).isVisible = value;
					break;
				case "Header/Subtitle":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.SubTitle).template = value;
					break;
				case "Header/SubtitleAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.SubTitle).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawSubtitle":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.SubTitle).isVisible = value;
					break;
				case "Header/Artist":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Artist).template = value;
					break;
				case "Header/ArtistAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Artist).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawArtist":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Artist).isVisible = value;
					break;
				case "Header/Album":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Album).template = value;
					break;
				case "Header/AlbumAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Album).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawAlbum":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Album).isVisible = value;
					break;
				case "Header/Words":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Words).template = value;
					break;
				case "Header/WordsAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Words).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawWords":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Words).isVisible = value;
					break;
				case "Header/Music":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Music).template = value;
					break;
				case "Header/MusicAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Music).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawMusic":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Music).isVisible = value;
					break;
				case "Header/WordsAndMusic":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.WordsAndMusic).template = value;
					break;
				case "Header/WordsAndMusicAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.WordsAndMusic).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawWordsAndMusic":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.WordsAndMusic).isVisible = value;
					break;
				case "Header/Tabber":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Transcriber).template = value;
					break;
				case "Header/TabberAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Transcriber).textAlign = this._toTextAlign(value);
					break;
				case "Header/drawTabber":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Transcriber).isVisible = value;
					break;
				case "Footer/Copyright":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Copyright).template = value;
					break;
				case "Footer/CopyrightAlignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Copyright).textAlign = this._toTextAlign(value);
					break;
				case "Footer/drawCopyright":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.Copyright).isVisible = value;
					break;
				case "Footer/Copyright2":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.CopyrightSecondLine).template = value;
					break;
				case "Footer/Copyright2Alignment":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.CopyrightSecondLine).textAlign = this._toTextAlign(value);
					break;
				case "Footer/drawCopyright2":
					ModelUtils.getOrCreateHeaderFooterStyle(score, ScoreSubElement.CopyrightSecondLine).isVisible = value;
					break;
				case "System/barIndexDrawType":
					switch (value) {
						case 0:
							score.stylesheet.barNumberDisplay = BarNumberDisplay.AllBars;
							break;
						case 1:
							score.stylesheet.barNumberDisplay = BarNumberDisplay.FirstOfSystem;
							break;
						case 2:
							score.stylesheet.barNumberDisplay = BarNumberDisplay.Hide;
							break;
					}
					break;
			}
		}
		_toTextAlign(value) {
			switch (value) {
				case 0: return TextAlign.Left;
				case 1: return TextAlign.Center;
				case 2: return TextAlign.Right;
			}
			return TextAlign.Left;
		}
		addValue(key, value, type) {
			this.raw.set(key, value);
			if (type !== void 0) this._types.set(key, type);
		}
		writeTo(writer) {
			IOHelper.writeInt32BE(writer, this.raw.size);
			for (const [k, v] of this.raw) {
				const dataType = this._getDataType(k, v);
				GpBinaryHelpers.gpWriteString(writer, k);
				writer.writeByte(dataType);
				switch (dataType) {
					case 0:
						writer.writeByte(v ? 1 : 0);
						break;
					case 1:
						IOHelper.writeInt32BE(writer, v);
						break;
					case 2:
						IOHelper.writeFloat32BE(writer, v);
						break;
					case 3:
						const encoded = IOHelper.stringToBytes(v);
						IOHelper.writeInt16BE(writer, encoded.length);
						writer.write(encoded, 0, encoded.length);
						break;
					case 4:
						IOHelper.writeInt32BE(writer, v.offset);
						IOHelper.writeInt32BE(writer, v.value);
						break;
					case 5:
						IOHelper.writeInt32BE(writer, v.offset);
						IOHelper.writeInt32BE(writer, v.value);
						break;
					case 6:
						IOHelper.writeInt32BE(writer, v.x);
						IOHelper.writeInt32BE(writer, v.y);
						IOHelper.writeInt32BE(writer, v.w);
						IOHelper.writeInt32BE(writer, v.h);
						break;
					case 7:
						writer.writeByte(v.r);
						writer.writeByte(v.g);
						writer.writeByte(v.b);
						writer.writeByte(v.a);
						break;
				}
			}
		}
		_getDataType(key, value) {
			if (this._types.has(key)) return this._types.get(key);
			const type = typeof value;
			switch (typeof value) {
				case "string": return 3;
				case "number": return value === (value | 0) ? 1 : 2;
				case "object":
					if (value instanceof BendPoint) return 4;
					if (value instanceof Bounds) return 6;
					if (value instanceof Color) return 7;
					break;
			}
			throw new AlphaTabError(AlphaTabErrorType.General, `Unknown value type in BinaryStylesheet: ${type}`);
		}
		static writeForScore(score) {
			const binaryStylesheet = new BinaryStylesheet();
			binaryStylesheet.addValue("StandardNotation/hideDynamics", score.stylesheet.hideDynamics, 0);
			binaryStylesheet.addValue("System/bracketExtendMode", score.stylesheet.bracketExtendMode, 1);
			binaryStylesheet.addValue("Global/useSystemSignSeparator", score.stylesheet.useSystemSignSeparator, 0);
			binaryStylesheet.addValue("Global/DisplayTuning", score.stylesheet.globalDisplayTuning, 0);
			binaryStylesheet.addValue("Global/DrawChords", score.stylesheet.globalDisplayChordDiagramsOnTop, 0);
			binaryStylesheet.addValue("System/drawChordInScore", score.stylesheet.globalDisplayChordDiagramsInScore, 0);
			switch (score.stylesheet.singleTrackTrackNamePolicy) {
				case TrackNamePolicy.Hidden:
					binaryStylesheet.addValue("System/showTrackNameSingle", false, 0);
					break;
				case TrackNamePolicy.FirstSystem:
					binaryStylesheet.addValue("System/trackNameModeSingle", 0, 1);
					break;
				case TrackNamePolicy.AllSystems:
					binaryStylesheet.addValue("System/trackNameModeSingle", 2, 1);
					break;
			}
			switch (score.stylesheet.multiTrackTrackNamePolicy) {
				case TrackNamePolicy.Hidden:
					binaryStylesheet.addValue("System/showTrackNameMulti", false, 0);
					break;
				case TrackNamePolicy.FirstSystem:
					binaryStylesheet.addValue("System/trackNameModeMulti", 0, 1);
					break;
				case TrackNamePolicy.AllSystems:
					binaryStylesheet.addValue("System/trackNameModeMulti", 2, 1);
					break;
			}
			switch (score.stylesheet.firstSystemTrackNameMode) {
				case TrackNameMode.FullName:
					binaryStylesheet.addValue("System/shortTrackNameOnFirstSystem", false, 0);
					break;
				case TrackNameMode.ShortName:
					binaryStylesheet.addValue("System/shortTrackNameOnFirstSystem", true, 0);
					break;
			}
			switch (score.stylesheet.otherSystemsTrackNameMode) {
				case TrackNameMode.FullName:
					binaryStylesheet.addValue("System/shortTrackNameOnOtherSystems", false, 0);
					break;
				case TrackNameMode.ShortName:
					binaryStylesheet.addValue("System/shortTrackNameOnOtherSystems", true, 0);
					break;
			}
			switch (score.stylesheet.firstSystemTrackNameOrientation) {
				case TrackNameOrientation.Horizontal:
					binaryStylesheet.addValue("System/horizontalTrackNameOnFirstSystem", true, 0);
					break;
				case TrackNameOrientation.Vertical:
					binaryStylesheet.addValue("System/horizontalTrackNameOnFirstSystem", false, 0);
					break;
			}
			switch (score.stylesheet.otherSystemsTrackNameOrientation) {
				case TrackNameOrientation.Horizontal:
					binaryStylesheet.addValue("System/horizontalTrackNameOnOtherSystems", true, 0);
					break;
				case TrackNameOrientation.Vertical:
					binaryStylesheet.addValue("System/horizontalTrackNameOnOtherSystems", false, 0);
					break;
			}
			binaryStylesheet.addValue("System/ExtendedBarLines", score.stylesheet.extendBarLines, 0);
			const scoreStyle = score.style;
			if (scoreStyle) for (const [k, v] of scoreStyle.headerAndFooter) switch (k) {
				case ScoreSubElement.Title:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "Title");
					break;
				case ScoreSubElement.SubTitle:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "Subtitle");
					break;
				case ScoreSubElement.Artist:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "Artist");
					break;
				case ScoreSubElement.Album:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "Album");
					break;
				case ScoreSubElement.Words:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "Words");
					break;
				case ScoreSubElement.Music:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "Music");
					break;
				case ScoreSubElement.WordsAndMusic:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "WordsAndMusic");
					break;
				case ScoreSubElement.Transcriber:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Header/", "Tabber");
					break;
				case ScoreSubElement.Copyright:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Footer/", "Copyright");
					break;
				case ScoreSubElement.CopyrightSecondLine:
					BinaryStylesheet._addHeaderAndFooter(binaryStylesheet, v, "Footer/", "Copyright2");
					break;
			}
			switch (score.stylesheet.barNumberDisplay) {
				case BarNumberDisplay.AllBars:
					binaryStylesheet.addValue("System/barIndexDrawType", 0, 1);
					break;
				case BarNumberDisplay.FirstOfSystem:
					binaryStylesheet.addValue("System/barIndexDrawType", 1, 1);
					break;
				case BarNumberDisplay.Hide:
					binaryStylesheet.addValue("System/barIndexDrawType", 2, 1);
					break;
			}
			const writer = ByteBuffer.withCapacity(128);
			binaryStylesheet.writeTo(writer);
			return writer.toArray();
		}
		static _addHeaderAndFooter(binaryStylesheet, style, prefix, name) {
			binaryStylesheet.addValue(`${prefix}${name}`, style.template, 3);
			binaryStylesheet.addValue(`${prefix}${name}Alignment`, style.textAlign, 1);
			if (style.isVisible !== void 0) binaryStylesheet.addValue(`${prefix}draw${name}`, style.isVisible, 0);
		}
	};
	//#endregion
	//#region src/model/BackingTrack.ts
	/**
	* Holds information about the backing track which can be played instead of synthesized audio.
	* @json
	* @json_strict
	* @public
	*/
	var BackingTrack = class {
		/**
		* The data of the raw audio file to be used for playback.
		* @json_ignore
		*/
		rawAudioFile;
	};
	//#endregion
	//#region src/importer/GpifParser.ts
	/**
	* This structure represents a duration within a gpif
	* @internal
	*/
	var GpifRhythm = class {
		id = "";
		dots = 0;
		tupletDenominator = -1;
		tupletNumerator = -1;
		value = Duration.Quarter;
	};
	/**
	* @internal
	*/
	var GpifSound = class {
		name = "";
		path = "";
		role = "";
		get uniqueId() {
			return `${this.path};${this.name};${this.role}`;
		}
		program = 0;
		bank = 0;
	};
	/**
	* This class can parse a score.gpif xml file into the model structure
	* @internal
	*/
	var GpifParser = class GpifParser {
		static _invalidId = "-1";
		/**
		* GPX range: 0-100
		* Internal range: 0 - 60
		*/
		static _bendPointPositionFactor = BendPoint.MaxPosition / 100;
		/**
		* GPIF: 25 per quarternote
		* Internal Range: 1 per quarter note
		*/
		static _bendPointValueFactor = 1 / 25;
		static _sampleRate = 44100;
		score;
		_backingTrackAssetId;
		_masterTrackAutomations;
		_automationsPerTrackIdAndBarIndex;
		_sustainPedalsPerTrackIdAndBarIndex;
		_tracksMapping;
		_tracksById;
		_masterBars;
		_barsOfMasterBar;
		_barsById;
		_voicesOfBar;
		_voiceById;
		_beatsOfVoice;
		_rhythmOfBeat;
		_beatById;
		_rhythmById;
		_noteById;
		_notesOfBeat;
		_tappedNotes;
		_lyricsByTrack;
		_soundsByTrack;
		_hasAnacrusis = false;
		_articulationByName;
		_skipApplyLyrics = false;
		_backingTrackPadding = 0;
		_doubleBars = /* @__PURE__ */ new Set();
		_keySignatures = /* @__PURE__ */ new Map();
		loadAsset;
		parseXml(xml, settings) {
			this._masterTrackAutomations = /* @__PURE__ */ new Map();
			this._automationsPerTrackIdAndBarIndex = /* @__PURE__ */ new Map();
			this._sustainPedalsPerTrackIdAndBarIndex = /* @__PURE__ */ new Map();
			this._tracksMapping = [];
			this._tracksById = /* @__PURE__ */ new Map();
			this._masterBars = [];
			this._barsOfMasterBar = [];
			this._voicesOfBar = /* @__PURE__ */ new Map();
			this._barsById = /* @__PURE__ */ new Map();
			this._voiceById = /* @__PURE__ */ new Map();
			this._beatsOfVoice = /* @__PURE__ */ new Map();
			this._beatById = /* @__PURE__ */ new Map();
			this._rhythmOfBeat = /* @__PURE__ */ new Map();
			this._rhythmById = /* @__PURE__ */ new Map();
			this._notesOfBeat = /* @__PURE__ */ new Map();
			this._noteById = /* @__PURE__ */ new Map();
			this._tappedNotes = /* @__PURE__ */ new Map();
			this._lyricsByTrack = /* @__PURE__ */ new Map();
			this._soundsByTrack = /* @__PURE__ */ new Map();
			this._skipApplyLyrics = false;
			const dom = new XmlDocument();
			try {
				dom.parse(xml);
			} catch (e) {
				throw new UnsupportedFormatError("Could not parse XML", e);
			}
			this._parseDom(dom);
			this._buildModel();
			ModelUtils.consolidate(this.score);
			this.score.finish(settings);
			if (!this._skipApplyLyrics && this._lyricsByTrack.size > 0) for (const [t, lyrics] of this._lyricsByTrack) this._tracksById.get(t).applyLyrics(lyrics);
		}
		_parseDom(dom) {
			const root = dom.firstElement;
			if (!root) return;
			if (root.localName === "GPIF") {
				this.score = new Score();
				for (const n of root.childElements()) switch (n.localName) {
					case "Score":
						this._parseScoreNode(n);
						break;
					case "MasterTrack":
						this._parseMasterTrackNode(n);
						break;
					case "BackingTrack":
						this._parseBackingTrackNode(n);
						break;
					case "Tracks":
						this._parseTracksNode(n);
						break;
					case "MasterBars":
						this._parseMasterBarsNode(n);
						break;
					case "Bars":
						this._parseBars(n);
						break;
					case "Voices":
						this._parseVoices(n);
						break;
					case "Beats":
						this._parseBeats(n);
						break;
					case "Notes":
						this._parseNotes(n);
						break;
					case "Rhythms":
						this._parseRhythms(n);
						break;
					case "Assets":
						this._parseAssets(n);
						break;
				}
			} else throw new UnsupportedFormatError("Root node of XML was not GPIF");
		}
		_parseAssets(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "Asset":
					if (c.getAttribute("id") === this._backingTrackAssetId) this._parseBackingTrackAsset(c);
					break;
			}
		}
		_parseBackingTrackAsset(element) {
			let embeddedFilePath = "";
			for (const c of element.childElements()) switch (c.localName) {
				case "EmbeddedFilePath":
					embeddedFilePath = c.innerText;
					break;
			}
			const loadAsset = this.loadAsset;
			if (loadAsset) {
				const assetData = loadAsset(embeddedFilePath);
				if (assetData) this.score.backingTrack.rawAudioFile = assetData;
				else this.score.backingTrack = void 0;
			}
		}
		_parseScoreNode(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "Title":
					this.score.title = c.innerText;
					break;
				case "SubTitle":
					this.score.subTitle = c.innerText;
					break;
				case "Artist":
					this.score.artist = c.innerText;
					break;
				case "Album":
					this.score.album = c.innerText;
					break;
				case "Words":
					this.score.words = c.innerText;
					break;
				case "Music":
					this.score.music = c.innerText;
					break;
				case "WordsAndMusic":
					const wordsAndMusic = c.innerText;
					if (wordsAndMusic !== "") {
						if (wordsAndMusic && !this.score.words) this.score.words = wordsAndMusic;
						if (wordsAndMusic && !this.score.music) this.score.music = wordsAndMusic;
					}
					break;
				case "Copyright":
					this.score.copyright = c.innerText;
					break;
				case "Tabber":
					this.score.tab = c.innerText;
					break;
				case "Instructions":
					this.score.instructions = c.innerText;
					break;
				case "Notices":
					this.score.notices = c.innerText;
					break;
				case "ScoreSystemsDefaultLayout":
					this.score.defaultSystemsLayout = GpifParser._parseIntSafe(c.innerText, 4);
					break;
				case "ScoreSystemsLayout":
					this.score.systemsLayout = GpifParser._splitSafe(c.innerText).map((i) => GpifParser._parseIntSafe(i, 4));
					break;
			}
		}
		static _parseIntSafe(text, fallback) {
			if (!text) return fallback;
			const i = Number.parseInt(text, 10);
			if (!Number.isNaN(i)) return i;
			return fallback;
		}
		static _parseFloatSafe(text, fallback) {
			if (!text) return fallback;
			const i = Number.parseFloat(text);
			if (!Number.isNaN(i)) return i;
			return fallback;
		}
		static _splitSafe(text, separator = " ") {
			if (!text) return [];
			return text.split(separator).map((t) => t.trim()).filter((t) => t.length > 0);
		}
		_parseBackingTrackNode(node) {
			const backingTrack = new BackingTrack();
			let enabled = false;
			let source = "";
			let assetId = "";
			for (const c of node.childElements()) switch (c.localName) {
				case "Enabled":
					enabled = c.innerText === "true";
					break;
				case "Source":
					source = c.innerText;
					break;
				case "AssetId":
					assetId = c.innerText;
					break;
				case "FramePadding":
					this._backingTrackPadding = GpifParser._parseIntSafe(c.innerText, 0) / GpifParser._sampleRate * 1e3;
					break;
			}
			if (enabled && source === "Local") {
				this.score.backingTrack = backingTrack;
				this._backingTrackAssetId = assetId;
			}
		}
		_parseMasterTrackNode(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Automations":
					this._parseAutomations(c, this._masterTrackAutomations, null, null);
					break;
				case "Tracks":
					this._tracksMapping = GpifParser._splitSafe(c.innerText);
					break;
				case "Anacrusis":
					this._hasAnacrusis = true;
					break;
			}
		}
		_parseAutomations(node, automations, sounds, sustainPedals) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Automation":
					this._parseAutomation(c, automations, sounds, sustainPedals);
					break;
			}
		}
		_parseAutomation(node, automations, sounds, sustainPedals) {
			let type = null;
			let isLinear = false;
			let barIndex = -1;
			let ratioPosition = 0;
			let numberValue = 0;
			let textValue = null;
			let reference = 0;
			let text = null;
			let syncPointValue = void 0;
			let isVisible = true;
			for (const c of node.childElements()) switch (c.localName) {
				case "Type":
					type = c.innerText;
					break;
				case "Linear":
					isLinear = c.innerText.toLowerCase() === "true";
					break;
				case "Bar":
					barIndex = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "Position":
					ratioPosition = GpifParser._parseFloatSafe(c.innerText, 0);
					break;
				case "Value":
					if (c.firstElement && c.firstElement.nodeType === XmlNodeType.CDATA) textValue = c.innerText;
					else if (c.firstElement && c.firstElement.nodeType === XmlNodeType.Element && type === "SyncPoint") {
						syncPointValue = new SyncPointData();
						for (const vc of c.childElements()) switch (vc.localName) {
							case "BarIndex":
								barIndex = GpifParser._parseIntSafe(vc.innerText, 0);
								break;
							case "BarOccurrence":
								syncPointValue.barOccurence = GpifParser._parseIntSafe(vc.innerText, 0);
								break;
							case "FrameOffset":
								const frameOffset = GpifParser._parseFloatSafe(vc.innerText, 0);
								syncPointValue.millisecondOffset = frameOffset / GpifParser._sampleRate * 1e3;
								break;
						}
					} else {
						const parts = GpifParser._splitSafe(c.innerText);
						if (parts.length === 1) {
							numberValue = GpifParser._parseFloatSafe(parts[0], 0);
							reference = 1;
						} else {
							numberValue = GpifParser._parseFloatSafe(parts[0], 0);
							reference = GpifParser._parseIntSafe(parts[1], 0);
						}
					}
					break;
				case "Text":
					text = c.innerText;
					break;
				case "Visible":
					isVisible = c.innerText.toLowerCase() === "true";
					break;
			}
			if (!type) return;
			const newAutomations = [];
			switch (type) {
				case "Tempo":
					newAutomations.push(Automation.buildTempoAutomation(isLinear, ratioPosition, numberValue, reference, isVisible));
					break;
				case "SyncPoint":
					const syncPoint = new Automation();
					syncPoint.type = AutomationType.SyncPoint;
					syncPoint.isLinear = isLinear;
					syncPoint.ratioPosition = ratioPosition;
					syncPoint.syncPointValue = syncPointValue;
					syncPoint.isVisible = isVisible;
					newAutomations.push(syncPoint);
					break;
				case "Sound":
					if (textValue && sounds && sounds.has(textValue)) {
						const bankChange = new Automation();
						bankChange.type = AutomationType.Bank;
						bankChange.ratioPosition = ratioPosition;
						bankChange.value = sounds.get(textValue).bank;
						bankChange.isVisible = isVisible;
						newAutomations.push(bankChange);
						const programChange = Automation.buildInstrumentAutomation(isLinear, ratioPosition, sounds.get(textValue).program);
						newAutomations.push(programChange);
					}
					break;
				case "SustainPedal":
					if (sustainPedals) {
						let v;
						if (sustainPedals.has(barIndex)) v = sustainPedals.get(barIndex);
						else {
							v = [];
							sustainPedals.set(barIndex, v);
						}
						const sustain = new SustainPedalMarker();
						sustain.ratioPosition = ratioPosition;
						switch (reference) {
							case 1:
								sustain.pedalType = SustainPedalMarkerType.Down;
								break;
							case 3:
								sustain.pedalType = SustainPedalMarkerType.Up;
								break;
						}
						v.push(sustain);
					}
					break;
			}
			if (newAutomations.length) {
				if (text) for (const a of newAutomations) a.text = text;
				if (barIndex >= 0) {
					if (!automations.has(barIndex)) automations.set(barIndex, []);
					for (const a of newAutomations) automations.get(barIndex).push(a);
				}
			}
		}
		_parseTracksNode(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Track":
					this._parseTrack(c);
					break;
			}
		}
		_parseTrack(node) {
			this._articulationByName = /* @__PURE__ */ new Map();
			const track = new Track();
			track.ensureStaveCount(1);
			const staff = track.staves[0];
			staff.showStandardNotation = true;
			const trackId = node.getAttribute("id");
			for (const c of node.childElements()) switch (c.localName) {
				case "Name":
					track.name = c.innerText;
					break;
				case "Color":
					const parts = GpifParser._splitSafe(c.innerText);
					if (parts.length >= 3) track.color = new Color(GpifParser._parseIntSafe(parts[0], 0), GpifParser._parseIntSafe(parts[1], 0), GpifParser._parseIntSafe(parts[2], 0), 255);
					break;
				case "Instrument":
					const instrumentName = c.getAttribute("ref");
					if (instrumentName.endsWith("-gs") || instrumentName.endsWith("GrandStaff")) {
						track.ensureStaveCount(2);
						track.staves[1].showStandardNotation = true;
					}
					break;
				case "InstrumentSet":
					this._parseInstrumentSet(track, c);
					break;
				case "NotationPatch":
					this._parseNotationPatch(track, c);
					break;
				case "ShortName":
					track.shortName = c.innerText;
					break;
				case "SystemsDefautLayout":
					track.defaultSystemsLayout = GpifParser._parseIntSafe(c.innerText, 4);
					break;
				case "SystemsLayout":
					track.systemsLayout = GpifParser._splitSafe(c.innerText).map((i) => GpifParser._parseIntSafe(i, 4));
					break;
				case "Lyrics":
					this._parseLyrics(trackId, c);
					break;
				case "Properties":
					this._parseTrackProperties(track, c);
					break;
				case "GeneralMidi":
				case "MidiConnection":
				case "MIDISettings":
					this._parseGeneralMidi(track, c);
					break;
				case "Sounds":
					this._parseSounds(trackId, track, c);
					break;
				case "PlaybackState":
					const state = c.innerText;
					track.playbackInfo.isSolo = state === "Solo";
					track.playbackInfo.isMute = state === "Mute";
					break;
				case "PartSounding":
					this._parsePartSounding(trackId, track, c);
					break;
				case "Staves":
					this._parseStaves(track, c);
					break;
				case "Transpose":
					this._parseTranspose(trackId, track, c);
					break;
				case "RSE":
					this._parseRSE(track, c);
					break;
				case "Automations":
					this._parseTrackAutomations(trackId, c);
					break;
			}
			this._tracksById.set(trackId, track);
		}
		_parseTrackAutomations(trackId, c) {
			const trackAutomations = /* @__PURE__ */ new Map();
			this._automationsPerTrackIdAndBarIndex.set(trackId, trackAutomations);
			const sustainPedals = /* @__PURE__ */ new Map();
			this._sustainPedalsPerTrackIdAndBarIndex.set(trackId, sustainPedals);
			this._parseAutomations(c, trackAutomations, this._soundsByTrack.get(trackId), sustainPedals);
		}
		_parseNotationPatch(track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "LineCount":
					const lineCount = GpifParser._parseIntSafe(c.innerText, 5);
					for (const staff of track.staves) staff.standardNotationLineCount = lineCount;
					break;
				case "Elements":
					this._parseElements(track, c, false);
					break;
			}
		}
		_parseInstrumentSet(track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Type":
					if (c.innerText === "drumKit") for (const staff of track.staves) staff.isPercussion = true;
					break;
				case "Elements":
					this._parseElements(track, c, true);
					break;
				case "LineCount":
					const lineCount = GpifParser._parseIntSafe(c.innerText, 5);
					for (const staff of track.staves) staff.standardNotationLineCount = lineCount;
					break;
			}
		}
		_parseElements(track, node, isInstrumentSet) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Element":
					this._parseElement(track, c, isInstrumentSet);
					break;
			}
		}
		_parseElement(track, node, isInstrumentSet) {
			const name = node.findChildElement("Name")?.innerText ?? "";
			for (const c of node.childElements()) switch (c.localName) {
				case "Name":
				case "Articulations":
					this._parseArticulations(track, c, isInstrumentSet, name);
					break;
			}
		}
		_parseArticulations(track, node, isInstrumentSet, elementName) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Articulation":
					this._parseArticulation(track, c, isInstrumentSet, elementName);
					break;
			}
		}
		_parseArticulation(track, node, isInstrumentSet, elementName) {
			const articulation = new InstrumentArticulation();
			articulation.outputMidiNumber = -1;
			articulation.elementType = elementName;
			let name = "";
			for (const c of node.childElements()) {
				const txt = c.innerText;
				switch (c.localName) {
					case "Name":
						name = c.innerText;
						break;
					case "InputMidiNumbers":
						articulation.id = GpifParser._parseIntSafe(txt.split(" ")[0], 0);
						break;
					case "OutputMidiNumber":
						articulation.outputMidiNumber = GpifParser._parseIntSafe(txt, 0);
						break;
					case "TechniqueSymbol":
						articulation.techniqueSymbol = GpifParser.parseTechniqueSymbol(txt);
						break;
					case "TechniquePlacement":
						articulation.techniqueSymbolPlacement = GpifParser.parseTechniqueSymbolPlacement(txt);
						break;
					case "Noteheads":
						const noteHeadsTxt = GpifParser._splitSafe(txt);
						if (noteHeadsTxt.length >= 1) articulation.noteHeadDefault = GpifParser.parseNoteHead(noteHeadsTxt[0]);
						if (noteHeadsTxt.length >= 2) articulation.noteHeadHalf = GpifParser.parseNoteHead(noteHeadsTxt[1]);
						if (noteHeadsTxt.length >= 3) articulation.noteHeadWhole = GpifParser.parseNoteHead(noteHeadsTxt[2]);
						if (articulation.noteHeadHalf === MusicFontSymbol.None) articulation.noteHeadHalf = articulation.noteHeadDefault;
						if (articulation.noteHeadWhole === MusicFontSymbol.None) articulation.noteHeadWhole = articulation.noteHeadDefault;
						break;
					case "StaffLine":
						articulation.staffLine = GpifParser._parseIntSafe(txt, 0);
						break;
				}
			}
			const fullName = `${elementName}.${name}`;
			if (isInstrumentSet) {
				track.percussionArticulations.push(articulation);
				this._articulationByName.set(fullName, articulation);
			} else if (this._articulationByName.has(fullName)) this._articulationByName.get(fullName).staffLine = articulation.staffLine;
		}
		/**
		* @internal
		*/
		static parseTechniqueSymbol(txt) {
			switch (txt) {
				case "pictEdgeOfCymbal": return MusicFontSymbol.PictEdgeOfCymbal;
				case "articStaccatoAbove": return MusicFontSymbol.ArticStaccatoAbove;
				case "noteheadParenthesis": return MusicFontSymbol.NoteheadParenthesis;
				case "stringsUpBow": return MusicFontSymbol.StringsUpBow;
				case "stringsDownBow": return MusicFontSymbol.StringsDownBow;
				case "guitarGolpe": return MusicFontSymbol.GuitarGolpe;
				default: return MusicFontSymbol.None;
			}
		}
		/**
		* @internal
		*/
		static parseTechniqueSymbolPlacement(txt) {
			switch (txt) {
				case "outside": return TechniqueSymbolPlacement.Outside;
				case "inside": return TechniqueSymbolPlacement.Inside;
				case "above": return TechniqueSymbolPlacement.Above;
				case "below": return TechniqueSymbolPlacement.Below;
				default: return TechniqueSymbolPlacement.Outside;
			}
		}
		/**
		* @internal
		*/
		static parseNoteHead(txt) {
			switch (txt) {
				case "noteheadDoubleWholeSquare": return MusicFontSymbol.NoteheadDoubleWholeSquare;
				case "noteheadDoubleWhole": return MusicFontSymbol.NoteheadDoubleWhole;
				case "noteheadWhole": return MusicFontSymbol.NoteheadWhole;
				case "noteheadHalf": return MusicFontSymbol.NoteheadHalf;
				case "noteheadBlack": return MusicFontSymbol.NoteheadBlack;
				case "noteheadNull": return MusicFontSymbol.NoteheadNull;
				case "noteheadXOrnate": return MusicFontSymbol.NoteheadXOrnate;
				case "noteheadTriangleUpWhole": return MusicFontSymbol.NoteheadTriangleUpWhole;
				case "noteheadTriangleUpHalf": return MusicFontSymbol.NoteheadTriangleUpHalf;
				case "noteheadTriangleUpBlack": return MusicFontSymbol.NoteheadTriangleUpBlack;
				case "noteheadDiamondBlackWide": return MusicFontSymbol.NoteheadDiamondBlackWide;
				case "noteheadDiamondWhite": return MusicFontSymbol.NoteheadDiamondWhite;
				case "noteheadDiamondWhiteWide": return MusicFontSymbol.NoteheadDiamondWhiteWide;
				case "noteheadCircleX": return MusicFontSymbol.NoteheadCircleX;
				case "noteheadXWhole": return MusicFontSymbol.NoteheadXWhole;
				case "noteheadXHalf": return MusicFontSymbol.NoteheadXHalf;
				case "noteheadXBlack": return MusicFontSymbol.NoteheadXBlack;
				case "noteheadParenthesis": return MusicFontSymbol.NoteheadParenthesis;
				case "noteheadSlashedBlack2": return MusicFontSymbol.NoteheadSlashedBlack2;
				case "noteheadCircleSlash": return MusicFontSymbol.NoteheadCircleSlash;
				case "noteheadHeavyX": return MusicFontSymbol.NoteheadHeavyX;
				case "noteheadHeavyXHat": return MusicFontSymbol.NoteheadHeavyXHat;
				default:
					Logger.warning("GPIF", "Unknown notehead symbol", txt);
					return MusicFontSymbol.None;
			}
		}
		_parseStaves(track, node) {
			let staffIndex = 0;
			for (const c of node.childElements()) switch (c.localName) {
				case "Staff":
					track.ensureStaveCount(staffIndex + 1);
					const staff = track.staves[staffIndex];
					this._parseStaff(staff, c);
					staffIndex++;
					break;
			}
		}
		_parseStaff(staff, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Properties":
					this._parseStaffProperties(staff, c);
					break;
			}
		}
		_parseStaffProperties(staff, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Property":
					this._parseStaffProperty(staff, c);
					break;
			}
		}
		_parseStaffProperty(staff, node) {
			switch (node.getAttribute("name")) {
				case "Tuning":
					for (const c of node.childElements()) switch (c.localName) {
						case "Pitches":
							const tuningParts = GpifParser._splitSafe(node.findChildElement("Pitches")?.innerText);
							const tuning = new Array(tuningParts.length);
							for (let i = 0; i < tuning.length; i++) tuning[tuning.length - 1 - i] = GpifParser._parseIntSafe(tuningParts[i], 0);
							staff.stringTuning.tunings = tuning;
							break;
						case "Label":
							staff.stringTuning.name = c.innerText;
							break;
					}
					if (!staff.isPercussion) staff.showTablature = true;
					break;
				case "DiagramCollection":
				case "ChordCollection":
					this._parseDiagramCollectionForStaff(staff, node);
					break;
				case "CapoFret":
					staff.capo = GpifParser._parseIntSafe(node.findChildElement("Fret")?.innerText, 0);
					break;
			}
		}
		_parseLyrics(trackId, node) {
			const tracks = [];
			for (const c of node.childElements()) switch (c.localName) {
				case "Line":
					tracks.push(this._parseLyricsLine(c));
					break;
			}
			this._lyricsByTrack.set(trackId, tracks);
		}
		_parseLyricsLine(node) {
			const lyrics = new Lyrics();
			for (const c of node.childElements()) switch (c.localName) {
				case "Offset":
					lyrics.startBar = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "Text":
					lyrics.text = c.innerText;
					break;
			}
			return lyrics;
		}
		_parseDiagramCollectionForTrack(track, node) {
			const items = node.findChildElement("Items");
			if (items) for (const c of items.childElements()) switch (c.localName) {
				case "Item":
					this._parseDiagramItemForTrack(track, c);
					break;
			}
		}
		_parseDiagramCollectionForStaff(staff, node) {
			const items = node.findChildElement("Items");
			if (items) for (const c of items.childElements()) switch (c.localName) {
				case "Item":
					this._parseDiagramItemForStaff(staff, c);
					break;
			}
		}
		_parseDiagramItemForTrack(track, node) {
			const chord = new Chord();
			const chordId = node.getAttribute("id");
			for (const staff of track.staves) staff.addChord(chordId, chord);
			this._parseDiagramItemForChord(chord, node);
		}
		_parseDiagramItemForStaff(staff, node) {
			const chord = new Chord();
			const chordId = node.getAttribute("id");
			staff.addChord(chordId, chord);
			this._parseDiagramItemForChord(chord, node);
		}
		_parseDiagramItemForChord(chord, node) {
			chord.name = node.getAttribute("name");
			const diagram = node.findChildElement("Diagram");
			if (!diagram) {
				chord.showDiagram = false;
				chord.showFingering = false;
				return;
			}
			const stringCount = GpifParser._parseIntSafe(diagram.getAttribute("stringCount"), 6);
			const baseFret = GpifParser._parseIntSafe(diagram.getAttribute("baseFret"), 0);
			chord.firstFret = baseFret + 1;
			for (let i = 0; i < stringCount; i++) chord.strings.push(-1);
			for (const c of diagram.childElements()) switch (c.localName) {
				case "Fret":
					const guitarString = GpifParser._parseIntSafe(c.getAttribute("string"), 0);
					chord.strings[stringCount - guitarString - 1] = baseFret + GpifParser._parseIntSafe(c.getAttribute("fret"), 0);
					break;
				case "Fingering":
					const existingFingers = /* @__PURE__ */ new Map();
					for (const p of c.childElements()) switch (p.localName) {
						case "Position":
							let finger = Fingers.Unknown;
							const fret = baseFret + GpifParser._parseIntSafe(p.getAttribute("fret"), 0);
							switch (p.getAttribute("finger")) {
								case "Index":
									finger = Fingers.IndexFinger;
									break;
								case "Middle":
									finger = Fingers.MiddleFinger;
									break;
								case "Rank":
									finger = Fingers.AnnularFinger;
									break;
								case "Pinky":
									finger = Fingers.LittleFinger;
									break;
								case "Thumb":
									finger = Fingers.Thumb;
									break;
								case "None": break;
							}
							if (finger !== Fingers.Unknown) if (existingFingers.has(finger)) chord.barreFrets.push(fret);
							else existingFingers.set(finger, true);
							break;
					}
					break;
				case "Property":
					switch (c.getAttribute("name")) {
						case "ShowName":
							chord.showName = c.getAttribute("value") === "true";
							break;
						case "ShowDiagram":
							chord.showDiagram = c.getAttribute("value") === "true";
							break;
						case "ShowFingering":
							chord.showFingering = c.getAttribute("value") === "true";
							break;
					}
					break;
			}
		}
		_parseTrackProperties(track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Property":
					this._parseTrackProperty(track, c);
					break;
			}
		}
		_parseTrackProperty(track, node) {
			switch (node.getAttribute("name")) {
				case "Tuning":
					const tuningParts = GpifParser._splitSafe(node.findChildElement("Pitches")?.innerText);
					const tuning = new Array(tuningParts.length);
					for (let i = 0; i < tuning.length; i++) tuning[tuning.length - 1 - i] = GpifParser._parseIntSafe(tuningParts[i], 0);
					for (const staff of track.staves) {
						staff.stringTuning.tunings = tuning;
						staff.showStandardNotation = true;
						staff.showTablature = true;
					}
					break;
				case "DiagramCollection":
				case "ChordCollection":
					this._parseDiagramCollectionForTrack(track, node);
					break;
				case "CapoFret":
					const capo = GpifParser._parseIntSafe(node.findChildElement("Fret")?.innerText, 0);
					for (const staff of track.staves) staff.capo = capo;
					break;
			}
		}
		_parseGeneralMidi(track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Program":
					track.playbackInfo.program = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "Port":
					track.playbackInfo.port = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "PrimaryChannel":
					track.playbackInfo.primaryChannel = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "SecondaryChannel":
					track.playbackInfo.secondaryChannel = GpifParser._parseIntSafe(c.innerText, 0);
					break;
			}
			if (node.getAttribute("table") === "Percussion") for (const staff of track.staves) staff.isPercussion = true;
		}
		_parseSounds(trackId, track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Sound":
					this._parseSound(trackId, track, c);
					break;
			}
		}
		_parseSound(trackId, track, node) {
			const sound = new GpifSound();
			for (const c of node.childElements()) switch (c.localName) {
				case "Name":
					sound.name = c.innerText;
					break;
				case "Path":
					sound.path = c.innerText;
					break;
				case "Role":
					sound.role = c.innerText;
					break;
				case "MIDI":
					this._parseSoundMidi(sound, c);
					break;
			}
			if (!this._soundsByTrack.has(trackId)) {
				this._soundsByTrack.set(trackId, /* @__PURE__ */ new Map());
				track.playbackInfo.program = sound.program;
				track.playbackInfo.bank = sound.bank;
			}
			this._soundsByTrack.get(trackId).set(sound.uniqueId, sound);
		}
		_parseSoundMidi(sound, node) {
			let bankMsb = 0;
			let bankLsb = 0;
			for (const c of node.childElements()) switch (c.localName) {
				case "Program":
					sound.program = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "MSB":
					bankMsb = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "LSB":
					bankLsb = GpifParser._parseIntSafe(c.innerText, 0);
					break;
			}
			sound.bank = (bankMsb & 127) << 7 | bankLsb;
		}
		_parsePartSounding(trackId, track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "TranspositionPitch":
					for (const staff of track.staves) staff.displayTranspositionPitch = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "NominalKey":
					const transposeIndex = Math.max(0, Tuning.noteNames.indexOf(c.innerText));
					this._transposeKeySignaturePerTrack.set(trackId, transposeIndex);
					break;
			}
		}
		_transposeKeySignaturePerTrack = /* @__PURE__ */ new Map();
		_parseTranspose(trackId, track, node) {
			let octave = 0;
			let chromatic = 0;
			for (const c of node.childElements()) switch (c.localName) {
				case "Chromatic":
					chromatic = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "Octave":
					octave = GpifParser._parseIntSafe(c.innerText, 0);
					break;
			}
			const pitch = octave * 12 + chromatic;
			for (const staff of track.staves) staff.displayTranspositionPitch = pitch;
			const transposeIndex = ModelUtils.flooredDivision(pitch, 12);
			this._transposeKeySignaturePerTrack.set(trackId, transposeIndex);
		}
		_parseRSE(track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "ChannelStrip":
					this._parseChannelStrip(track, c);
					break;
			}
		}
		_parseChannelStrip(track, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Parameters":
					this._parseChannelStripParameters(track, c);
					break;
			}
		}
		_parseChannelStripParameters(track, node) {
			if (node.firstChild && node.firstChild.value) {
				const parameters = GpifParser._splitSafe(node.firstChild.value);
				if (parameters.length >= 12) {
					track.playbackInfo.balance = Math.floor(GpifParser._parseFloatSafe(parameters[11], .5) * 16);
					track.playbackInfo.volume = Math.floor(GpifParser._parseFloatSafe(parameters[12], .9) * 16);
				}
			}
		}
		_parseMasterBarsNode(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "MasterBar":
					this._parseMasterBar(c);
					break;
			}
		}
		_parseMasterBar(node) {
			const masterBar = new MasterBar();
			if (this._masterBars.length === 0 && this._hasAnacrusis) masterBar.isAnacrusis = true;
			for (const c of node.childElements()) switch (c.localName) {
				case "Time":
					const timeParts = c.innerText.split("/");
					masterBar.timeSignatureNumerator = GpifParser._parseIntSafe(timeParts[0], 4);
					masterBar.timeSignatureDenominator = GpifParser._parseIntSafe(timeParts[1], 4);
					break;
				case "FreeTime":
					masterBar.isFreeTime = true;
					break;
				case "DoubleBar":
					masterBar.isDoubleBar = true;
					this._doubleBars.add(masterBar);
					break;
				case "Section":
					masterBar.section = new Section();
					masterBar.section.marker = c.findChildElement("Letter")?.innerText ?? "";
					masterBar.section.text = c.findChildElement("Text")?.innerText ?? "";
					break;
				case "Repeat":
					if (c.getAttribute("start").toLowerCase() === "true") masterBar.isRepeatStart = true;
					if (c.getAttribute("end").toLowerCase() === "true" && c.getAttribute("count")) masterBar.repeatCount = GpifParser._parseIntSafe(c.getAttribute("count"), 1);
					break;
				case "AlternateEndings":
					const alternateEndings = GpifParser._splitSafe(c.innerText);
					let i = 0;
					for (let k = 0; k < alternateEndings.length; k++) i = i | 1 << -1 + GpifParser._parseIntSafe(alternateEndings[k], 0);
					masterBar.alternateEndings = i;
					break;
				case "Bars":
					this._barsOfMasterBar.push(GpifParser._splitSafe(c.innerText));
					break;
				case "TripletFeel":
					switch (c.innerText) {
						case "NoTripletFeel":
							masterBar.tripletFeel = TripletFeel.NoTripletFeel;
							break;
						case "Triplet8th":
							masterBar.tripletFeel = TripletFeel.Triplet8th;
							break;
						case "Triplet16th":
							masterBar.tripletFeel = TripletFeel.Triplet16th;
							break;
						case "Dotted8th":
							masterBar.tripletFeel = TripletFeel.Dotted8th;
							break;
						case "Dotted16th":
							masterBar.tripletFeel = TripletFeel.Dotted16th;
							break;
						case "Scottish8th":
							masterBar.tripletFeel = TripletFeel.Scottish8th;
							break;
						case "Scottish16th":
							masterBar.tripletFeel = TripletFeel.Scottish16th;
							break;
					}
					break;
				case "Key":
					const keySignature = GpifParser._parseIntSafe(c.findChildElement("AccidentalCount")?.innerText, 0);
					const mode = c.findChildElement("Mode");
					let keySignatureType = KeySignatureType.Major;
					if (mode) switch (mode.innerText.toLowerCase()) {
						case "major":
							keySignatureType = KeySignatureType.Major;
							break;
						case "minor":
							keySignatureType = KeySignatureType.Minor;
							break;
					}
					this._keySignatures.set(this._masterBars.length, [keySignature, keySignatureType]);
					break;
				case "Fermatas":
					this._parseFermatas(masterBar, c);
					break;
				case "XProperties":
					this._parseMasterBarXProperties(masterBar, c);
					break;
				case "Directions":
					this._parseDirections(masterBar, c);
					break;
			}
			this._masterBars.push(masterBar);
		}
		_parseDirections(masterBar, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Target":
					switch (c.innerText) {
						case "Coda":
							masterBar.addDirection(Direction.TargetCoda);
							break;
						case "DoubleCoda":
							masterBar.addDirection(Direction.TargetDoubleCoda);
							break;
						case "Segno":
							masterBar.addDirection(Direction.TargetSegno);
							break;
						case "SegnoSegno":
							masterBar.addDirection(Direction.TargetSegnoSegno);
							break;
						case "Fine":
							masterBar.addDirection(Direction.TargetFine);
							break;
					}
					break;
				case "Jump":
					switch (c.innerText) {
						case "DaCapo":
							masterBar.addDirection(Direction.JumpDaCapo);
							break;
						case "DaCapoAlCoda":
							masterBar.addDirection(Direction.JumpDaCapoAlCoda);
							break;
						case "DaCapoAlDoubleCoda":
							masterBar.addDirection(Direction.JumpDaCapoAlDoubleCoda);
							break;
						case "DaCapoAlFine":
							masterBar.addDirection(Direction.JumpDaCapoAlFine);
							break;
						case "DaSegno":
							masterBar.addDirection(Direction.JumpDalSegno);
							break;
						case "DaSegnoAlCoda":
							masterBar.addDirection(Direction.JumpDalSegnoAlCoda);
							break;
						case "DaSegnoAlDoubleCoda":
							masterBar.addDirection(Direction.JumpDalSegnoAlDoubleCoda);
							break;
						case "DaSegnoAlFine":
							masterBar.addDirection(Direction.JumpDalSegnoAlFine);
							break;
						case "DaSegnoSegno":
							masterBar.addDirection(Direction.JumpDalSegnoSegno);
							break;
						case "DaSegnoSegnoAlCoda":
							masterBar.addDirection(Direction.JumpDalSegnoSegnoAlCoda);
							break;
						case "DaSegnoSegnoAlDoubleCoda":
							masterBar.addDirection(Direction.JumpDalSegnoSegnoAlDoubleCoda);
							break;
						case "DaSegnoSegnoAlFine":
							masterBar.addDirection(Direction.JumpDalSegnoSegnoAlFine);
							break;
						case "DaCoda":
							masterBar.addDirection(Direction.JumpDaCoda);
							break;
						case "DaDoubleCoda":
							masterBar.addDirection(Direction.JumpDaDoubleCoda);
							break;
					}
					break;
			}
		}
		_parseFermatas(masterBar, node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Fermata":
					this._parseFermata(masterBar, c);
					break;
			}
		}
		_parseFermata(masterBar, node) {
			let offset = 0;
			const fermata = new Fermata();
			for (const c of node.childElements()) switch (c.localName) {
				case "Type":
					switch (c.innerText) {
						case "Short":
							fermata.type = FermataType.Short;
							break;
						case "Medium":
							fermata.type = FermataType.Medium;
							break;
						case "Long":
							fermata.type = FermataType.Long;
							break;
					}
					break;
				case "Length":
					fermata.length = GpifParser._parseFloatSafe(c.innerText, 0);
					break;
				case "Offset":
					const parts = c.innerText.split("/");
					if (parts.length === 2) offset = GpifParser._parseIntSafe(parts[0], 4) / GpifParser._parseIntSafe(parts[1], 4) * MidiUtils.QuarterTime | 0;
					break;
			}
			masterBar.addFermata(offset, fermata);
		}
		_parseBars(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Bar":
					this._parseBar(c);
					break;
			}
		}
		_parseBar(node) {
			const bar = new Bar();
			const barId = node.getAttribute("id");
			for (const c of node.childElements()) switch (c.localName) {
				case "Voices":
					this._voicesOfBar.set(barId, GpifParser._splitSafe(c.innerText));
					break;
				case "Clef":
					switch (c.innerText) {
						case "Neutral":
							bar.clef = Clef.Neutral;
							break;
						case "G2":
							bar.clef = Clef.G2;
							break;
						case "F4":
							bar.clef = Clef.F4;
							break;
						case "C4":
							bar.clef = Clef.C4;
							break;
						case "C3":
							bar.clef = Clef.C3;
							break;
					}
					break;
				case "Ottavia":
					switch (c.innerText) {
						case "8va":
							bar.clefOttava = Ottavia._8va;
							break;
						case "15ma":
							bar.clefOttava = Ottavia._15ma;
							break;
						case "8vb":
							bar.clefOttava = Ottavia._8vb;
							break;
						case "15mb":
							bar.clefOttava = Ottavia._15mb;
							break;
					}
					break;
				case "SimileMark":
					switch (c.innerText) {
						case "Simple":
							bar.simileMark = SimileMark.Simple;
							break;
						case "FirstOfDouble":
							bar.simileMark = SimileMark.FirstOfDouble;
							break;
						case "SecondOfDouble":
							bar.simileMark = SimileMark.SecondOfDouble;
							break;
					}
					break;
				case "XProperties":
					this._parseBarXProperties(c, bar);
					break;
			}
			this._barsById.set(barId, bar);
		}
		_parseVoices(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Voice":
					this._parseVoice(c);
					break;
			}
		}
		_parseVoice(node) {
			const voice = new Voice$1();
			const voiceId = node.getAttribute("id");
			for (const c of node.childElements()) switch (c.localName) {
				case "Beats":
					this._beatsOfVoice.set(voiceId, GpifParser._splitSafe(c.innerText));
					break;
			}
			this._voiceById.set(voiceId, voice);
		}
		_parseBeats(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Beat":
					this._parseBeat(c);
					break;
			}
		}
		_parseBeat(node) {
			const beat = new Beat();
			const beatId = node.getAttribute("id");
			for (const c of node.childElements()) switch (c.localName) {
				case "Notes":
					this._notesOfBeat.set(beatId, GpifParser._splitSafe(c.innerText));
					break;
				case "Rhythm":
					this._rhythmOfBeat.set(beatId, c.getAttribute("ref"));
					break;
				case "Fadding":
					switch (c.innerText) {
						case "FadeIn":
							beat.fade = FadeType.FadeIn;
							break;
						case "FadeOut":
							beat.fade = FadeType.FadeOut;
							break;
						case "VolumeSwell":
							beat.fade = FadeType.VolumeSwell;
							break;
					}
					break;
				case "Tremolo":
					const tremolo = new TremoloPickingEffect();
					beat.tremoloPicking = tremolo;
					switch (c.innerText) {
						case "1/2":
							tremolo.marks = 1;
							break;
						case "1/4":
							tremolo.marks = 2;
							break;
						case "1/8":
							tremolo.marks = 3;
							break;
					}
					break;
				case "Chord":
					beat.chordId = c.innerText;
					break;
				case "Hairpin":
					switch (c.innerText) {
						case "Crescendo":
							beat.crescendo = CrescendoType.Crescendo;
							break;
						case "Decrescendo":
							beat.crescendo = CrescendoType.Decrescendo;
							break;
					}
					break;
				case "Arpeggio":
					if (c.innerText === "Up") beat.brushType = BrushType.ArpeggioUp;
					else beat.brushType = BrushType.ArpeggioDown;
					break;
				case "Properties":
					this._parseBeatProperties(c, beat);
					break;
				case "XProperties":
					this._parseBeatXProperties(c, beat);
					break;
				case "FreeText":
					beat.text = c.innerText;
					break;
				case "TransposedPitchStemOrientation":
					switch (c.innerText) {
						case "Upward":
							beat.preferredBeamDirection = BeamDirection.Up;
							break;
						case "Downward":
							beat.preferredBeamDirection = BeamDirection.Down;
							break;
					}
					break;
				case "Dynamic":
					switch (c.innerText) {
						case "PPP":
							beat.dynamics = DynamicValue.PPP;
							break;
						case "PP":
							beat.dynamics = DynamicValue.PP;
							break;
						case "P":
							beat.dynamics = DynamicValue.P;
							break;
						case "MP":
							beat.dynamics = DynamicValue.MP;
							break;
						case "MF":
							beat.dynamics = DynamicValue.MF;
							break;
						case "F":
							beat.dynamics = DynamicValue.F;
							break;
						case "FF":
							beat.dynamics = DynamicValue.FF;
							break;
						case "FFF":
							beat.dynamics = DynamicValue.FFF;
							break;
					}
					break;
				case "GraceNotes":
					switch (c.innerText) {
						case "OnBeat":
							beat.graceType = GraceType.OnBeat;
							break;
						case "BeforeBeat":
							beat.graceType = GraceType.BeforeBeat;
							break;
					}
					break;
				case "Legato":
					if (c.getAttribute("origin") === "true") beat.isLegatoOrigin = true;
					break;
				case "Whammy":
					const whammyOrigin = new BendPoint(0, 0);
					whammyOrigin.value = this._toBendValue(GpifParser._parseFloatSafe(c.getAttribute("originValue"), 0));
					whammyOrigin.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.getAttribute("originOffset"), 0));
					beat.addWhammyBarPoint(whammyOrigin);
					const whammyMiddle1 = new BendPoint(0, 0);
					whammyMiddle1.value = this._toBendValue(GpifParser._parseFloatSafe(c.getAttribute("middleValue"), 0));
					whammyMiddle1.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.getAttribute("middleOffset1"), 0));
					beat.addWhammyBarPoint(whammyMiddle1);
					const whammyMiddle2 = new BendPoint(0, 0);
					whammyMiddle2.value = this._toBendValue(GpifParser._parseFloatSafe(c.getAttribute("middleValue"), 0));
					whammyMiddle2.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.getAttribute("middleOffset2"), 0));
					beat.addWhammyBarPoint(whammyMiddle2);
					const whammyDestination = new BendPoint(0, 0);
					whammyDestination.value = this._toBendValue(GpifParser._parseFloatSafe(c.getAttribute("destinationValue"), 0));
					whammyDestination.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.getAttribute("destinationOffset"), 0));
					beat.addWhammyBarPoint(whammyDestination);
					break;
				case "Ottavia":
					switch (c.innerText) {
						case "8va":
							beat.ottava = Ottavia._8va;
							break;
						case "8vb":
							beat.ottava = Ottavia._8vb;
							break;
						case "15ma":
							beat.ottava = Ottavia._15ma;
							break;
						case "15mb":
							beat.ottava = Ottavia._15mb;
							break;
					}
					break;
				case "Lyrics":
					beat.lyrics = this._parseBeatLyrics(c);
					this._skipApplyLyrics = true;
					break;
				case "Slashed":
					beat.slashed = true;
					break;
				case "DeadSlapped":
					beat.deadSlapped = true;
					break;
				case "Golpe":
					switch (c.innerText) {
						case "Finger":
							beat.golpe = GolpeType.Finger;
							break;
						case "Thumb":
							beat.golpe = GolpeType.Thumb;
							break;
					}
					break;
				case "Wah":
					switch (c.innerText) {
						case "Open":
							beat.wahPedal = WahPedal.Open;
							break;
						case "Closed":
							beat.wahPedal = WahPedal.Closed;
							break;
					}
					break;
				case "UserTransposedPitchStemOrientation":
					switch (c.innerText) {
						case "Downward":
							beat.preferredBeamDirection = BeamDirection.Down;
							break;
						case "Upward":
							beat.preferredBeamDirection = BeamDirection.Up;
							break;
					}
					break;
				case "Timer":
					beat.showTimer = true;
					beat.timer = GpifParser._parseIntSafe(c.innerText, -1);
					if (beat.timer < 0) beat.timer = null;
					break;
			}
			this._beatById.set(beatId, beat);
		}
		_parseBeatLyrics(node) {
			const lines = [];
			for (const c of node.childElements()) switch (c.localName) {
				case "Line":
					lines.push(c.innerText);
					break;
			}
			return lines;
		}
		_parseBeatXProperties(node, beat) {
			for (const c of node.childElements()) switch (c.localName) {
				case "XProperty":
					const id = c.getAttribute("id");
					let value = 0;
					switch (id) {
						case "1124204546":
							value = GpifParser._parseIntSafe(c.findChildElement("Int")?.innerText, 0);
							switch (value) {
								case 1:
									beat.beamingMode = BeatBeamingMode.ForceMergeWithNext;
									break;
								case 2:
									beat.beamingMode = BeatBeamingMode.ForceSplitToNext;
									break;
							}
							break;
						case "1124204552":
							value = GpifParser._parseIntSafe(c.findChildElement("Int")?.innerText, 0);
							switch (value) {
								case 1:
									if (beat.beamingMode !== BeatBeamingMode.ForceSplitToNext) beat.beamingMode = BeatBeamingMode.ForceSplitOnSecondaryToNext;
									break;
							}
							break;
						case "1124204545":
							value = GpifParser._parseIntSafe(c.findChildElement("Int")?.innerText, 0);
							beat.invertBeamDirection = value === 1;
							break;
						case "687935489":
							value = GpifParser._parseIntSafe(c.findChildElement("Int")?.innerText, 0);
							beat.brushDuration = value;
							break;
					}
					break;
			}
		}
		_parseBarXProperties(node, bar) {
			for (const c of node.childElements()) switch (c.localName) {
				case "XProperty":
					switch (c.getAttribute("id")) {
						case "1124139520":
							const childNode = c.findChildElement("Double") ?? c.findChildElement("Float");
							bar.displayScale = GpifParser._parseFloatSafe(childNode?.innerText, 1);
							break;
					}
					break;
			}
		}
		_parseMasterBarXProperties(masterBar, node) {
			let beamingRuleDuration = NaN;
			let beamingRuleGroups = void 0;
			for (const c of node.childElements()) switch (c.localName) {
				case "XProperty":
					const id = c.getAttribute("id");
					switch (id) {
						case "1124073984":
							masterBar.displayScale = GpifParser._parseFloatSafe(c.findChildElement("Double")?.innerText, 1);
							break;
						case "1124139010":
							beamingRuleDuration = GpifParser._parseIntSafe(c.findChildElement("Int")?.innerText, NaN);
							break;
						default:
							const idNumeric = GpifParser._parseIntSafe(id, 0);
							if (idNumeric >= 1124139264 && idNumeric <= 1124139295) {
								const groupIndex = idNumeric - 1124139264;
								const groupSize = GpifParser._parseIntSafe(c.findChildElement("Int")?.innerText, NaN);
								if (beamingRuleGroups === void 0) beamingRuleGroups = [];
								while (beamingRuleGroups.length < groupIndex + 1) beamingRuleGroups.push(0);
								beamingRuleGroups[groupIndex] = groupSize;
							}
							break;
					}
					break;
			}
			if (!Number.isNaN(beamingRuleDuration) && beamingRuleGroups) {
				const rules = new BeamingRules();
				rules.groups.set(beamingRuleDuration, beamingRuleGroups);
				masterBar.beamingRules = rules;
			}
		}
		_parseBeatProperties(node, beat) {
			let isWhammy = false;
			let whammyOrigin = null;
			let whammyMiddleValue = null;
			let whammyMiddleOffset1 = null;
			let whammyMiddleOffset2 = null;
			let whammyDestination = null;
			for (const c of node.childElements()) switch (c.localName) {
				case "Property":
					switch (c.getAttribute("name")) {
						case "Brush":
							if (c.findChildElement("Direction")?.innerText === "Up") beat.brushType = BrushType.BrushUp;
							else beat.brushType = BrushType.BrushDown;
							break;
						case "PickStroke":
							if (c.findChildElement("Direction")?.innerText === "Up") beat.pickStroke = PickStroke.Up;
							else beat.pickStroke = PickStroke.Down;
							break;
						case "Slapped":
							if (c.findChildElement("Enable")) beat.slap = true;
							break;
						case "Popped":
							if (c.findChildElement("Enable")) beat.pop = true;
							break;
						case "VibratoWTremBar":
							switch (c.findChildElement("Strength")?.innerText) {
								case "Wide":
									beat.vibrato = VibratoType.Wide;
									break;
								case "Slight":
									beat.vibrato = VibratoType.Slight;
									break;
							}
							break;
						case "WhammyBar":
							isWhammy = true;
							break;
						case "WhammyBarExtend": break;
						case "WhammyBarOriginValue":
							if (!whammyOrigin) whammyOrigin = new BendPoint(0, 0);
							whammyOrigin.value = this._toBendValue(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "WhammyBarOriginOffset":
							if (!whammyOrigin) whammyOrigin = new BendPoint(0, 0);
							whammyOrigin.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "WhammyBarMiddleValue":
							whammyMiddleValue = this._toBendValue(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "WhammyBarMiddleOffset1":
							whammyMiddleOffset1 = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "WhammyBarMiddleOffset2":
							whammyMiddleOffset2 = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "WhammyBarDestinationValue":
							if (!whammyDestination) whammyDestination = new BendPoint(BendPoint.MaxPosition, 0);
							whammyDestination.value = this._toBendValue(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "WhammyBarDestinationOffset":
							if (!whammyDestination) whammyDestination = new BendPoint(0, 0);
							whammyDestination.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "BarreFret":
							beat.barreFret = GpifParser._parseIntSafe(c.findChildElement("Fret")?.innerText, 0);
							break;
						case "BarreString":
							switch (c.findChildElement("String")?.innerText) {
								case "0":
									beat.barreShape = BarreShape.Full;
									break;
								case "1":
									beat.barreShape = BarreShape.Half;
									break;
							}
							break;
						case "Rasgueado":
							switch (c.findChildElement("Rasgueado")?.innerText) {
								case "ii_1":
									beat.rasgueado = Rasgueado.Ii;
									break;
								case "mi_1":
									beat.rasgueado = Rasgueado.Mi;
									break;
								case "mii_1":
									beat.rasgueado = Rasgueado.MiiTriplet;
									break;
								case "mii_2":
									beat.rasgueado = Rasgueado.MiiAnapaest;
									break;
								case "pmp_1":
									beat.rasgueado = Rasgueado.PmpTriplet;
									break;
								case "pmp_2":
									beat.rasgueado = Rasgueado.PmpAnapaest;
									break;
								case "pei_1":
									beat.rasgueado = Rasgueado.PeiTriplet;
									break;
								case "pei_2":
									beat.rasgueado = Rasgueado.PeiAnapaest;
									break;
								case "pai_1":
									beat.rasgueado = Rasgueado.PaiTriplet;
									break;
								case "pai_2":
									beat.rasgueado = Rasgueado.PaiAnapaest;
									break;
								case "ami_1":
									beat.rasgueado = Rasgueado.AmiTriplet;
									break;
								case "ami_2":
									beat.rasgueado = Rasgueado.AmiAnapaest;
									break;
								case "ppp_1":
									beat.rasgueado = Rasgueado.Ppp;
									break;
								case "amii_1":
									beat.rasgueado = Rasgueado.Amii;
									break;
								case "amip_1":
									beat.rasgueado = Rasgueado.Amip;
									break;
								case "eami_1":
									beat.rasgueado = Rasgueado.Eami;
									break;
								case "eamii_1":
									beat.rasgueado = Rasgueado.Eamii;
									break;
								case "peami_1":
									beat.rasgueado = Rasgueado.Peami;
									break;
							}
							break;
					}
					break;
			}
			if (isWhammy) {
				if (!whammyOrigin) whammyOrigin = new BendPoint(0, 0);
				if (!whammyDestination) whammyDestination = new BendPoint(BendPoint.MaxPosition, 0);
				beat.addWhammyBarPoint(whammyOrigin);
				if (whammyMiddleOffset1 && whammyMiddleValue) beat.addWhammyBarPoint(new BendPoint(whammyMiddleOffset1, whammyMiddleValue));
				if (whammyMiddleOffset2 && whammyMiddleValue) beat.addWhammyBarPoint(new BendPoint(whammyMiddleOffset2, whammyMiddleValue));
				if (!whammyMiddleOffset1 && !whammyMiddleOffset2 && whammyMiddleValue) beat.addWhammyBarPoint(new BendPoint(BendPoint.MaxPosition / 2 | 0, whammyMiddleValue));
				beat.addWhammyBarPoint(whammyDestination);
			}
		}
		_parseNotes(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Note":
					this._parseNote(c);
					break;
			}
		}
		_parseNote(node) {
			const note = new Note();
			const noteId = node.getAttribute("id");
			for (const c of node.childElements()) switch (c.localName) {
				case "Properties":
					this._parseNoteProperties(c, note, noteId);
					break;
				case "AntiAccent":
					if (c.innerText.toLowerCase() === "normal") note.isGhost = true;
					break;
				case "LetRing":
					note.isLetRing = true;
					break;
				case "Trill":
					note.trillValue = GpifParser._parseIntSafe(c.innerText, -1);
					note.trillSpeed = Duration.Sixteenth;
					break;
				case "Accent":
					const accentFlags = GpifParser._parseIntSafe(c.innerText, 0);
					if ((accentFlags & 1) !== 0) note.isStaccato = true;
					if ((accentFlags & 4) !== 0) note.accentuated = AccentuationType.Heavy;
					if ((accentFlags & 8) !== 0) note.accentuated = AccentuationType.Normal;
					if ((accentFlags & 16) !== 0) note.accentuated = AccentuationType.Tenuto;
					break;
				case "Tie":
					if (c.getAttribute("destination").toLowerCase() === "true") note.isTieDestination = true;
					break;
				case "Vibrato":
					switch (c.innerText) {
						case "Slight":
							note.vibrato = VibratoType.Slight;
							break;
						case "Wide":
							note.vibrato = VibratoType.Wide;
							break;
					}
					break;
				case "LeftFingering":
					switch (c.innerText) {
						case "P":
							note.leftHandFinger = Fingers.Thumb;
							break;
						case "I":
							note.leftHandFinger = Fingers.IndexFinger;
							break;
						case "M":
							note.leftHandFinger = Fingers.MiddleFinger;
							break;
						case "A":
							note.leftHandFinger = Fingers.AnnularFinger;
							break;
						case "C":
							note.leftHandFinger = Fingers.LittleFinger;
							break;
					}
					break;
				case "RightFingering":
					switch (c.innerText) {
						case "P":
							note.rightHandFinger = Fingers.Thumb;
							break;
						case "I":
							note.rightHandFinger = Fingers.IndexFinger;
							break;
						case "M":
							note.rightHandFinger = Fingers.MiddleFinger;
							break;
						case "A":
							note.rightHandFinger = Fingers.AnnularFinger;
							break;
						case "C":
							note.rightHandFinger = Fingers.LittleFinger;
							break;
					}
					break;
				case "InstrumentArticulation":
					note.percussionArticulation = GpifParser._parseIntSafe(c.innerText, 0);
					break;
				case "Ornament":
					switch (c.innerText) {
						case "Turn":
							note.ornament = NoteOrnament.Turn;
							break;
						case "InvertedTurn":
							note.ornament = NoteOrnament.InvertedTurn;
							break;
						case "UpperMordent":
							note.ornament = NoteOrnament.UpperMordent;
							break;
						case "LowerMordent":
							note.ornament = NoteOrnament.LowerMordent;
							break;
					}
					break;
			}
			this._noteById.set(noteId, note);
		}
		_parseNoteProperties(node, note, noteId) {
			let isBended = false;
			let bendOrigin = null;
			let bendMiddleValue = null;
			let bendMiddleOffset1 = null;
			let bendMiddleOffset2 = null;
			let bendDestination = null;
			let element = -1;
			let variation = -1;
			let hasTransposedPitch = false;
			for (const c of node.childElements()) switch (c.localName) {
				case "Property":
					switch (c.getAttribute("name")) {
						case "ShowStringNumber":
							if (c.findChildElement("Enable")) note.showStringNumber = true;
							break;
						case "String":
							note.string = GpifParser._parseIntSafe(c.findChildElement("String")?.innerText, 0) + 1;
							break;
						case "Fret":
							note.fret = GpifParser._parseIntSafe(c.findChildElement("Fret")?.innerText, 0);
							break;
						case "Element":
							element = GpifParser._parseIntSafe(c.findChildElement("Element")?.innerText, 0);
							break;
						case "Variation":
							variation = GpifParser._parseIntSafe(c.findChildElement("Variation")?.innerText, 0);
							break;
						case "Tapped":
							this._tappedNotes.set(noteId, true);
							break;
						case "HarmonicType":
							const htype = c.findChildElement("HType");
							if (htype) switch (htype.innerText.toLowerCase()) {
								case "noharmonic":
									note.harmonicType = HarmonicType.None;
									break;
								case "natural":
									note.harmonicType = HarmonicType.Natural;
									break;
								case "artificial":
									note.harmonicType = HarmonicType.Artificial;
									break;
								case "pinch":
									note.harmonicType = HarmonicType.Pinch;
									break;
								case "tap":
									note.harmonicType = HarmonicType.Tap;
									break;
								case "semi":
									note.harmonicType = HarmonicType.Semi;
									break;
								case "feedback":
									note.harmonicType = HarmonicType.Feedback;
									break;
							}
							break;
						case "HarmonicFret":
							const hfret = c.findChildElement("HFret");
							if (hfret) note.harmonicValue = GpifParser._parseFloatSafe(hfret.innerText, 0);
							break;
						case "Muted":
							if (c.findChildElement("Enable")) note.isDead = true;
							break;
						case "PalmMuted":
							if (c.findChildElement("Enable")) note.isPalmMute = true;
							break;
						case "Octave":
							note.octave = GpifParser._parseIntSafe(c.findChildElement("Number")?.innerText, 0);
							if (note.tone === -1) note.tone = 0;
							break;
						case "Tone":
							note.tone = GpifParser._parseIntSafe(c.findChildElement("Step")?.innerText, 0);
							break;
						case "ConcertPitch":
							if (!hasTransposedPitch) this._parseConcertPitch(c, note);
							break;
						case "TransposedPitch":
							note.accidentalMode = NoteAccidentalMode.Default;
							this._parseConcertPitch(c, note);
							hasTransposedPitch = true;
							break;
						case "Bended":
							isBended = true;
							break;
						case "BendOriginValue":
							if (!bendOrigin) bendOrigin = new BendPoint(0, 0);
							bendOrigin.value = this._toBendValue(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "BendOriginOffset":
							if (!bendOrigin) bendOrigin = new BendPoint(0, 0);
							bendOrigin.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "BendMiddleValue":
							bendMiddleValue = this._toBendValue(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "BendMiddleOffset1":
							bendMiddleOffset1 = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "BendMiddleOffset2":
							bendMiddleOffset2 = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "BendDestinationValue":
							if (!bendDestination) bendDestination = new BendPoint(BendPoint.MaxPosition, 0);
							bendDestination.value = this._toBendValue(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "BendDestinationOffset":
							if (!bendDestination) bendDestination = new BendPoint(0, 0);
							bendDestination.offset = this._toBendOffset(GpifParser._parseFloatSafe(c.findChildElement("Float")?.innerText, 0));
							break;
						case "HopoOrigin":
							if (c.findChildElement("Enable")) note.isHammerPullOrigin = true;
							break;
						case "HopoDestination": break;
						case "LeftHandTapped":
							note.isLeftHandTapped = true;
							break;
						case "Slide":
							const slideFlags = GpifParser._parseIntSafe(c.findChildElement("Flags")?.innerText, 0);
							if ((slideFlags & 1) !== 0) note.slideOutType = SlideOutType.Shift;
							else if ((slideFlags & 2) !== 0) note.slideOutType = SlideOutType.Legato;
							else if ((slideFlags & 4) !== 0) note.slideOutType = SlideOutType.OutDown;
							else if ((slideFlags & 8) !== 0) note.slideOutType = SlideOutType.OutUp;
							if ((slideFlags & 16) !== 0) note.slideInType = SlideInType.IntoFromBelow;
							else if ((slideFlags & 32) !== 0) note.slideInType = SlideInType.IntoFromAbove;
							if ((slideFlags & 64) !== 0) note.slideOutType = SlideOutType.PickSlideDown;
							else if ((slideFlags & 128) !== 0) note.slideOutType = SlideOutType.PickSlideUp;
							break;
					}
					break;
			}
			if (isBended) {
				if (!bendOrigin) bendOrigin = new BendPoint(0, 0);
				if (!bendDestination) bendDestination = new BendPoint(BendPoint.MaxPosition, 0);
				note.addBendPoint(bendOrigin);
				if (bendMiddleOffset1 && bendMiddleValue) note.addBendPoint(new BendPoint(bendMiddleOffset1, bendMiddleValue));
				if (bendMiddleOffset2 && bendMiddleValue) note.addBendPoint(new BendPoint(bendMiddleOffset2, bendMiddleValue));
				if (!bendMiddleOffset1 && !bendMiddleOffset2 && bendMiddleValue) note.addBendPoint(new BendPoint(BendPoint.MaxPosition / 2 | 0, bendMiddleValue));
				note.addBendPoint(bendDestination);
			}
			if (element !== -1 && variation !== -1) note.percussionArticulation = PercussionMapper.articulationFromElementVariation(element, variation);
		}
		_parseConcertPitch(node, note) {
			const pitch = node.findChildElement("Pitch");
			if (pitch) for (const c of pitch.childElements()) switch (c.localName) {
				case "Accidental":
					switch (c.innerText) {
						case "":
							note.accidentalMode = NoteAccidentalMode.ForceNatural;
							break;
						case "x":
							note.accidentalMode = NoteAccidentalMode.ForceDoubleSharp;
							break;
						case "#":
							note.accidentalMode = NoteAccidentalMode.ForceSharp;
							break;
						case "b":
							note.accidentalMode = NoteAccidentalMode.ForceFlat;
							break;
						case "bb":
							note.accidentalMode = NoteAccidentalMode.ForceDoubleFlat;
							break;
					}
					break;
			}
		}
		_toBendValue(gpxValue) {
			return gpxValue * GpifParser._bendPointValueFactor | 0;
		}
		_toBendOffset(gpxOffset) {
			return gpxOffset * GpifParser._bendPointPositionFactor;
		}
		_parseRhythms(node) {
			for (const c of node.childElements()) switch (c.localName) {
				case "Rhythm":
					this._parseRhythm(c);
					break;
			}
		}
		_parseRhythm(node) {
			const rhythm = new GpifRhythm();
			const rhythmId = node.getAttribute("id");
			rhythm.id = rhythmId;
			for (const c of node.childElements()) switch (c.localName) {
				case "NoteValue":
					switch (c.innerText) {
						case "Long":
							rhythm.value = Duration.QuadrupleWhole;
							break;
						case "DoubleWhole":
							rhythm.value = Duration.DoubleWhole;
							break;
						case "Whole":
							rhythm.value = Duration.Whole;
							break;
						case "Half":
							rhythm.value = Duration.Half;
							break;
						case "Quarter":
							rhythm.value = Duration.Quarter;
							break;
						case "Eighth":
							rhythm.value = Duration.Eighth;
							break;
						case "16th":
							rhythm.value = Duration.Sixteenth;
							break;
						case "32nd":
							rhythm.value = Duration.ThirtySecond;
							break;
						case "64th":
							rhythm.value = Duration.SixtyFourth;
							break;
						case "128th":
							rhythm.value = Duration.OneHundredTwentyEighth;
							break;
						case "256th":
							rhythm.value = Duration.TwoHundredFiftySixth;
							break;
					}
					break;
				case "PrimaryTuplet":
					rhythm.tupletNumerator = GpifParser._parseIntSafe(c.getAttribute("num"), -1);
					rhythm.tupletDenominator = GpifParser._parseIntSafe(c.getAttribute("den"), -1);
					break;
				case "AugmentationDot":
					rhythm.dots = GpifParser._parseIntSafe(c.getAttribute("count"), 0);
					break;
			}
			this._rhythmById.set(rhythmId, rhythm);
		}
		_buildModel() {
			for (let i = 0, j = this._masterBars.length; i < j; i++) {
				const masterBar = this._masterBars[i];
				this.score.addMasterBar(masterBar);
			}
			const lastMasterBar = this._masterBars[this._masterBars.length - 1];
			if (this._doubleBars.has(lastMasterBar)) {
				this._doubleBars.delete(lastMasterBar);
				lastMasterBar.isDoubleBar = false;
			}
			const trackIndexToTrackId = [];
			for (const trackId of this._tracksMapping) {
				if (!trackId) continue;
				const track = this._tracksById.get(trackId);
				this.score.addTrack(track);
				trackIndexToTrackId.push(trackId);
			}
			let keySignature;
			for (const barIds of this._barsOfMasterBar) {
				let staffIndex = 0;
				let trackIndex = 0;
				keySignature = [KeySignature.C, KeySignatureType.Major];
				if (this._transposeKeySignaturePerTrack.has(trackIndexToTrackId[0])) keySignature = [ModelUtils.transposeKey(keySignature[0], this._transposeKeySignaturePerTrack.get(trackIndexToTrackId[0])), keySignature[1]];
				for (let barIndex = 0; barIndex < barIds.length && trackIndex < this.score.tracks.length; barIndex++) {
					const barId = barIds[barIndex];
					if (barId !== GpifParser._invalidId) {
						const bar = this._barsById.get(barId);
						const track = this.score.tracks[trackIndex];
						const staff = track.staves[staffIndex];
						staff.addBar(bar);
						const masterBarIndex = staff.bars.length - 1;
						if (this._keySignatures.has(masterBarIndex)) {
							keySignature = this._keySignatures.get(masterBarIndex);
							if (this._transposeKeySignaturePerTrack.has(trackIndexToTrackId[trackIndex])) keySignature = [ModelUtils.transposeKey(keySignature[0], this._transposeKeySignaturePerTrack.get(trackIndexToTrackId[trackIndex])), keySignature[1]];
						}
						bar.keySignature = keySignature[0];
						bar.keySignatureType = keySignature[1];
						if (this._doubleBars.has(bar.masterBar)) bar.barLineRight = BarLineStyle.LightLight;
						if (this._voicesOfBar.has(barId)) for (const voiceId of this._voicesOfBar.get(barId)) if (voiceId !== GpifParser._invalidId) {
							const voice = this._voiceById.get(voiceId);
							bar.addVoice(voice);
							if (this._beatsOfVoice.has(voiceId)) {
								for (const beatId of this._beatsOfVoice.get(voiceId)) if (beatId !== GpifParser._invalidId) {
									const beat = BeatCloner.clone(this._beatById.get(beatId));
									voice.addBeat(beat);
									const rhythmId = this._rhythmOfBeat.get(beatId);
									const rhythm = this._rhythmById.get(rhythmId);
									beat.duration = rhythm.value;
									beat.dots = rhythm.dots;
									beat.tupletNumerator = rhythm.tupletNumerator;
									beat.tupletDenominator = rhythm.tupletDenominator;
									if (this._notesOfBeat.has(beatId)) {
										for (const noteId of this._notesOfBeat.get(beatId)) if (noteId !== GpifParser._invalidId) {
											const note = NoteCloner.clone(this._noteById.get(noteId));
											if (staff.isPercussion) {
												note.fret = -1;
												note.string = -1;
											} else note.percussionArticulation = -1;
											beat.addNote(note);
											if (this._tappedNotes.has(noteId)) beat.tap = true;
										}
									}
								}
							}
						} else {
							const voice = new Voice$1();
							bar.addVoice(voice);
							const beat = new Beat();
							beat.isEmpty = true;
							beat.duration = Duration.Quarter;
							voice.addBeat(beat);
						}
						if (staffIndex === track.staves.length - 1) {
							trackIndex++;
							staffIndex = 0;
						} else staffIndex++;
						keySignature = [KeySignature.C, KeySignatureType.Major];
						if (trackIndex < trackIndexToTrackId.length && this._transposeKeySignaturePerTrack.has(trackIndexToTrackId[trackIndex])) keySignature = [ModelUtils.transposeKey(keySignature[0], this._transposeKeySignaturePerTrack.get(trackIndexToTrackId[trackIndex])), keySignature[1]];
					} else trackIndex++;
				}
			}
			for (const trackId of this._tracksMapping) {
				if (!trackId) continue;
				const track = this._tracksById.get(trackId);
				let hasPercussion = false;
				for (const staff of track.staves) if (staff.isPercussion) {
					hasPercussion = true;
					break;
				}
				if (!hasPercussion) track.percussionArticulations = [];
				if (this._automationsPerTrackIdAndBarIndex.has(trackId)) {
					const trackAutomations = this._automationsPerTrackIdAndBarIndex.get(trackId);
					for (const [barNumber, automations] of trackAutomations) if (track.staves.length > 0 && barNumber < track.staves[0].bars.length) {
						const bar = track.staves[0].bars[barNumber];
						if (bar.voices.length > 0 && bar.voices[0].beats.length > 0) {
							const beat = bar.voices[0].beats[0];
							for (const a of automations) if (!(a.type === AutomationType.Bank && a.value === 0 && bar.index === 0)) beat.automations.push(a);
						}
					}
				}
				if (this._sustainPedalsPerTrackIdAndBarIndex.has(trackId)) {
					const sustainPedals = this._sustainPedalsPerTrackIdAndBarIndex.get(trackId);
					for (const [barNumber, markers] of sustainPedals) if (track.staves.length > 0 && barNumber < track.staves[0].bars.length) {
						const bar = track.staves[0].bars[barNumber];
						bar.sustainPedals = markers;
					}
				}
			}
			for (const [barNumber, automations] of this._masterTrackAutomations) {
				if (barNumber < 0 || barNumber >= this.score.masterBars.length) continue;
				const masterBar = this.score.masterBars[barNumber];
				for (let i = 0, j = automations.length; i < j; i++) {
					const automation = automations[i];
					switch (automation.type) {
						case AutomationType.Tempo:
							masterBar.tempoAutomations.push(automation);
							break;
						case AutomationType.SyncPoint:
							automation.syncPointValue.millisecondOffset -= this._backingTrackPadding;
							masterBar.addSyncPoint(automation);
							break;
					}
				}
			}
		}
	};
	//#endregion
	//#region src/importer/PartConfiguration.ts
	/**
	* @internal
	*/
	var PartConfigurationScoreView = class {
		isMultiRest = false;
		trackViewGroups = [];
	};
	/**
	* @internal
	*/
	var PartConfigurationTrackViewGroup = class {
		showNumbered = false;
		showSlash = false;
		showStandardNotation = false;
		showTablature = false;
	};
	/**
	* @internal
	*/
	var PartConfiguration = class {
		scoreViews = [];
		apply(score) {
			if (this.scoreViews.length > 0) {
				let trackIndex = 0;
				score.stylesheet.multiTrackMultiBarRest = this.scoreViews[0].isMultiRest;
				for (const trackConfig of this.scoreViews[0].trackViewGroups) {
					if (trackIndex < score.tracks.length) {
						const track = score.tracks[trackIndex];
						for (const staff of track.staves) {
							if (!staff.isPercussion) staff.showTablature = trackConfig.showTablature;
							staff.showStandardNotation = trackConfig.showStandardNotation;
							staff.showSlash = trackConfig.showSlash;
							staff.showNumbered = trackConfig.showNumbered;
						}
					}
					trackIndex++;
				}
				for (let scoreViewIndex = 1; scoreViewIndex < this.scoreViews.length; scoreViewIndex++) if (this.scoreViews[scoreViewIndex].isMultiRest) {
					if (!score.stylesheet.perTrackMultiBarRest) score.stylesheet.perTrackMultiBarRest = /* @__PURE__ */ new Set();
					trackIndex = scoreViewIndex - 1;
					score.stylesheet.perTrackMultiBarRest.add(trackIndex);
				}
			}
		}
		constructor(partConfigurationData) {
			const readable = ByteBuffer.fromBuffer(partConfigurationData);
			const scoreViewCount = IOHelper.readInt32BE(readable);
			for (let i = 0; i < scoreViewCount; i++) {
				const scoreView = new PartConfigurationScoreView();
				this.scoreViews.push(scoreView);
				scoreView.isMultiRest = GpBinaryHelpers.gpReadBool(readable);
				const trackViewGroupCount = IOHelper.readInt32BE(readable);
				for (let j = 0; j < trackViewGroupCount; j++) {
					let flags = readable.readByte();
					if (flags === 0) flags = 1;
					const trackConfiguration = new PartConfigurationTrackViewGroup();
					trackConfiguration.showStandardNotation = (flags & 1) !== 0;
					trackConfiguration.showTablature = (flags & 2) !== 0;
					trackConfiguration.showSlash = (flags & 4) !== 0;
					trackConfiguration.showNumbered = (flags & 8) !== 0;
					scoreView.trackViewGroups.push(trackConfiguration);
				}
			}
		}
		static writeForScore(score) {
			const writer = ByteBuffer.withCapacity(128);
			const scoreViews = [new PartConfigurationScoreView()];
			scoreViews[0].isMultiRest = score.stylesheet.multiTrackMultiBarRest;
			for (const track of score.tracks) {
				const trackConfiguration = new PartConfigurationTrackViewGroup();
				trackConfiguration.showStandardNotation = track.staves[0].showStandardNotation;
				trackConfiguration.showTablature = track.staves[0].showTablature;
				trackConfiguration.showSlash = track.staves[0].showSlash;
				trackConfiguration.showNumbered = track.staves[0].showNumbered;
				scoreViews[0].trackViewGroups.push(trackConfiguration);
				const singleTrackScoreView = new PartConfigurationScoreView();
				singleTrackScoreView.isMultiRest = score.stylesheet.perTrackMultiBarRest?.has(track.index) === true;
				singleTrackScoreView.trackViewGroups.push(trackConfiguration);
				scoreViews.push(singleTrackScoreView);
			}
			IOHelper.writeInt32BE(writer, scoreViews.length);
			for (const part of scoreViews) {
				writer.writeByte(part.isMultiRest ? 1 : 0);
				IOHelper.writeInt32BE(writer, part.trackViewGroups.length);
				for (const track of part.trackViewGroups) {
					let flags = 0;
					if (track.showStandardNotation) flags = flags | 1;
					if (track.showTablature) flags = flags | 2;
					if (track.showSlash) flags = flags | 4;
					if (track.showNumbered) flags = flags | 8;
					writer.writeByte(flags);
				}
			}
			IOHelper.writeInt32BE(writer, 1);
			return writer.toArray();
		}
	};
	//#endregion
	//#region src/importer/LayoutConfiguration.ts
	/**
	* @internal
	*/
	var LayoutConfigurationScoreView = class {
		trackViewGroups = [];
	};
	/**
	* @internal
	*/
	var LayoutConfigurationTrackViewGroup = class {
		isVisible = false;
	};
	/**
	* @internal
	*/
	var LayoutConfiguration = class {
		zoomLevel = 4;
		view = 0;
		muiltiVoiceCursor = false;
		scoreViews = [];
		constructor(partConfiguration, layoutConfigurationData) {
			const readable = ByteBuffer.fromBuffer(layoutConfigurationData);
			this.zoomLevel = IOHelper.readInt32BE(readable);
			this.view = readable.readByte();
			this.muiltiVoiceCursor = readable.readByte() !== 0;
			const scoreViewCount = partConfiguration.scoreViews.length;
			for (let i = 0; i < scoreViewCount; i++) {
				const scoreView = new LayoutConfigurationScoreView();
				this.scoreViews.push(scoreView);
				const partScoreView = partConfiguration.scoreViews[i];
				for (let j = 0; j < partScoreView.trackViewGroups.length; j++) {
					const trackViewGroup = new LayoutConfigurationTrackViewGroup();
					trackViewGroup.isVisible = readable.readByte() !== 0;
					scoreView.trackViewGroups.push(trackViewGroup);
				}
			}
		}
		apply(score) {
			if (this.scoreViews.length > 0) {
				let trackIndex = 0;
				for (const trackConfig of this.scoreViews[0].trackViewGroups) {
					if (trackIndex < score.tracks.length) {
						const track = score.tracks[trackIndex];
						track.isVisibleOnMultiTrack = trackConfig.isVisible;
					}
					trackIndex++;
				}
			}
		}
		static writeForScore(score) {
			const writer = ByteBuffer.withCapacity(128);
			IOHelper.writeInt32BE(writer, 4);
			writer.writeByte(0);
			const isMultiVoice = score.tracks.length > 0 && score.tracks[0].staves[0].bars[0].isMultiVoice;
			writer.writeByte(isMultiVoice ? 255 : 0);
			for (const track of score.tracks) writer.writeByte(track.isVisibleOnMultiTrack ? 255 : 0);
			for (const _track of score.tracks) writer.writeByte(255);
			return writer.toArray();
		}
	};
	//#endregion
	//#region src/importer/Gp7To8Importer.ts
	/**
	* This ScoreImporter can read Guitar Pro 7 and 8 (gp) files.
	* @internal
	*/
	var Gp7To8Importer = class extends ScoreImporter {
		get name() {
			return "Guitar Pro 7-8";
		}
		readScore() {
			Logger.debug(this.name, "Loading ZIP entries");
			const fileSystem = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
			let entries;
			try {
				entries = fileSystem.read();
			} catch (e) {
				throw new UnsupportedFormatError("No Zip archive", e);
			}
			Logger.debug(this.name, "Zip entries loaded");
			let xml = null;
			let binaryStylesheetData = null;
			let partConfigurationData = null;
			let layoutConfigurationData = null;
			const entryLookup = /* @__PURE__ */ new Map();
			for (const entry of entries) {
				entryLookup.set(entry.fullName, entry);
				switch (entry.fileName) {
					case "score.gpif":
						xml = IOHelper.toString(entry.data, this.settings.importer.encoding);
						break;
					case "BinaryStylesheet":
						binaryStylesheetData = entry.data;
						break;
					case "PartConfiguration":
						partConfigurationData = entry.data;
						break;
					case "LayoutConfiguration":
						layoutConfigurationData = entry.data;
						break;
				}
			}
			if (!xml) throw new UnsupportedFormatError("No score.gpif found in zip archive");
			Logger.debug(this.name, "Start Parsing score.gpif");
			const gpifParser = new GpifParser();
			gpifParser.loadAsset = (fileName) => {
				if (entryLookup.has(fileName)) return entryLookup.get(fileName).data;
			};
			gpifParser.parseXml(xml, this.settings);
			Logger.debug(this.name, "score.gpif parsed");
			const score = gpifParser.score;
			if (binaryStylesheetData) {
				Logger.debug(this.name, "Start Parsing BinaryStylesheet");
				new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize).apply(score);
				Logger.debug(this.name, "BinaryStylesheet parsed");
			}
			let partConfigurationParser = null;
			if (partConfigurationData) {
				Logger.debug(this.name, "Start Parsing Part Configuration");
				partConfigurationParser = new PartConfiguration(partConfigurationData);
				partConfigurationParser.apply(score);
				Logger.debug(this.name, "Part Configuration parsed");
			}
			if (layoutConfigurationData && partConfigurationParser != null) {
				Logger.debug(this.name, "Start Parsing Layout Configuration");
				new LayoutConfiguration(partConfigurationParser, layoutConfigurationData).apply(score);
				Logger.debug(this.name, "Layout Configuration parsed");
			}
			return score;
		}
	};
	//#endregion
	//#region src/io/BitReader.ts
	/**
	* This utility public class allows bitwise reading of a stream
	* @internal
	*/
	var BitReader = class BitReader {
		static _byteSize = 8;
		_currentByte = 0;
		_position = BitReader._byteSize;
		_source;
		constructor(source) {
			this._source = source;
		}
		readByte() {
			return this.readBits(8);
		}
		readBytes(count) {
			const bytes = new Uint8Array(count);
			for (let i = 0; i < count; i++) bytes[i] = this.readByte() & 255;
			return bytes;
		}
		readBits(count) {
			let bits = 0;
			let i = count - 1;
			while (i >= 0) {
				bits = bits | this.readBit() << i;
				i--;
			}
			return bits;
		}
		readBitsReversed(count) {
			let bits = 0;
			for (let i = 0; i < count; i++) bits = bits | this.readBit() << i;
			return bits;
		}
		readBit() {
			if (this._position >= 8) {
				this._currentByte = this._source.readByte();
				if (this._currentByte === -1) throw new EndOfReaderError();
				this._position = 0;
			}
			const value = this._currentByte >> BitReader._byteSize - this._position - 1 & 1;
			this._position++;
			return value;
		}
		readAll() {
			const all = ByteBuffer.empty();
			try {
				while (true) all.writeByte(this.readByte() & 255);
			} catch (e) {
				if (!(e instanceof EndOfReaderError)) throw e;
			}
			return all.toArray();
		}
	};
	//#endregion
	//#region src/importer/GpxFileSystem.ts
	/**
	* this public class represents a file within the GpxFileSystem
	* @internal
	*/
	var GpxFile = class {
		fileName = "";
		fileSize = 0;
		data = null;
	};
	/**
	* This public class represents the file system structure
	* stored within a GPX container file.
	* @internal
	*/
	var GpxFileSystem = class {
		static HeaderBcFs = "BCFS";
		static HeaderBcFz = "BCFZ";
		/**
		* You can set a file filter method using this setter. On parsing
		* the filestructure this function can determine based on the filename
		* whether this file will be available after loading.
		* This way we can reduce the amount of memory we store.
		*/
		fileFilter;
		/**
		* Gets the list of files stored in this FileSystem.
		*/
		files = [];
		/**
		* Creates a new GpxFileSystem instance
		*/
		constructor() {
			this.files = [];
			this.fileFilter = (_) => {
				return true;
			};
		}
		/**
		* Load a complete FileSystem to the memory.
		* @param s the binary source to read from.
		* @returns
		*/
		load(s) {
			const src = new BitReader(s);
			this._readBlock(src);
		}
		/**
		* Reads the 4 byte header as a string.
		* @param src the BitInput to read from
		* @returns a string with 4 characters representing the header.
		*/
		readHeader(src) {
			return this._getString(src.readBytes(4), 0, 4);
		}
		/**
		* Decompresses the given bitinput using the GPX compression format. Only use this method
		* if you are sure the binary data is compressed using the GPX format. Otherwise unexpected
		* behavior can occure.
		* @param src the bitInput to read the data from
		* @param skipHeader true if the header should NOT be included in the result byteset, otherwise false
		* @returns the decompressed byte data. if skipHeader is set to false the BCFS header is included.
		*/
		decompress(src, skipHeader = false) {
			const uncompressed = ByteBuffer.empty();
			let buffer;
			const expectedLength = this._getInteger(src.readBytes(4), 0);
			try {
				while (uncompressed.length < expectedLength) if (src.readBits(1) === 1) {
					const wordSize = src.readBits(4);
					const offset = src.readBitsReversed(wordSize);
					const size = src.readBitsReversed(wordSize);
					const sourcePosition = uncompressed.length - offset;
					const toRead = Math.min(offset, size);
					buffer = uncompressed.getBuffer();
					uncompressed.write(buffer, sourcePosition, toRead);
				} else {
					const size = src.readBitsReversed(2);
					for (let i = 0; i < size; i++) uncompressed.writeByte(src.readByte());
				}
			} catch (e) {
				if (!(e instanceof EndOfReaderError)) throw e;
			}
			buffer = uncompressed.getBuffer();
			const resultOffset = skipHeader ? 4 : 0;
			const resultSize = uncompressed.length - resultOffset;
			const result = new Uint8Array(resultSize);
			const count = resultSize;
			result.set(buffer.subarray(resultOffset, resultOffset + count), 0);
			return result;
		}
		/**
		* Reads a block from the given data source.
		* @param data the data source
		* @returns
		*/
		_readBlock(data) {
			const header = this.readHeader(data);
			if (header === "BCFZ") this._readUncompressedBlock(this.decompress(data, true));
			else if (header === "BCFS") this._readUncompressedBlock(data.readAll());
			else throw new UnsupportedFormatError("Unsupported format");
		}
		/**
		* Reads an uncompressed data block into the model.
		* @param data the data store to read from.
		*/
		_readUncompressedBlock(data) {
			const sectorSize = 4096;
			let offset = sectorSize;
			while (offset + 3 < data.length) {
				if (this._getInteger(data, offset) === 2) {
					const file = new GpxFile();
					file.fileName = this._getString(data, offset + 4, 127);
					file.fileSize = this._getInteger(data, offset + 140);
					const storeFile = !this.fileFilter || this.fileFilter(file.fileName);
					if (storeFile) this.files.push(file);
					const dataPointerOffset = offset + 148;
					let sector = 0;
					let sectorCount = 0;
					const fileData = storeFile ? ByteBuffer.withCapacity(file.fileSize) : null;
					while (true) {
						sector = this._getInteger(data, dataPointerOffset + 4 * sectorCount++);
						if (sector !== 0) {
							offset = sector * sectorSize;
							if (storeFile) fileData.write(data, offset, sectorSize);
						} else break;
					}
					if (storeFile) {
						file.data = new Uint8Array(Math.min(file.fileSize, fileData.length));
						const raw = fileData.toArray();
						file.data.set(raw.subarray(0, 0 + file.data.length), 0);
					}
				}
				offset += sectorSize;
			}
		}
		/**
		* Reads a zeroterminated ascii string from the given source
		* @param data the data source to read from
		* @param offset the offset to start reading from
		* @param length the max length to read
		* @returns the ascii string read from the datasource.
		*/
		_getString(data, offset, length) {
			let buf = "";
			for (let i = 0; i < length; i++) {
				const code = data[offset + i] & 255;
				if (code === 0) break;
				buf += String.fromCharCode(code);
			}
			return buf;
		}
		/**
		* Reads an 4 byte signed integer from the given source
		* @param data the data source to read from
		* @param offset offset the offset to start reading from
		* @returns
		*/
		_getInteger(data, offset) {
			return data[offset + 3] << 24 | data[offset + 2] << 16 | data[offset + 1] << 8 | data[offset];
		}
	};
	//#endregion
	//#region src/importer/GpxImporter.ts
	/**
	* This ScoreImporter can read Guitar Pro 6 (gpx) files.
	* @internal
	*/
	var GpxImporter = class extends ScoreImporter {
		get name() {
			return "Guitar Pro 6";
		}
		readScore() {
			Logger.debug(this.name, "Loading GPX filesystem");
			const fileSystem = new GpxFileSystem();
			fileSystem.fileFilter = (s) => {
				return s.endsWith("score.gpif") || s.endsWith("BinaryStylesheet") || s.endsWith("PartConfiguration") || s.endsWith("LayoutConfiguration");
			};
			fileSystem.load(this.data);
			Logger.debug(this.name, "GPX filesystem loaded");
			let xml = null;
			let binaryStylesheetData = null;
			let partConfigurationData = null;
			let layoutConfigurationData = null;
			for (const entry of fileSystem.files) switch (entry.fileName) {
				case "score.gpif":
					xml = IOHelper.toString(entry.data, this.settings.importer.encoding);
					break;
				case "BinaryStylesheet":
					binaryStylesheetData = entry.data;
					break;
				case "PartConfiguration":
					partConfigurationData = entry.data;
					break;
				case "LayoutConfiguration":
					layoutConfigurationData = entry.data;
					break;
			}
			if (!xml) throw new UnsupportedFormatError("No score.gpif found in GPX");
			Logger.debug(this.name, "Start Parsing score.gpif");
			const gpifParser = new GpifParser();
			gpifParser.parseXml(xml, this.settings);
			Logger.debug(this.name, "score.gpif parsed");
			const score = gpifParser.score;
			if (binaryStylesheetData) {
				Logger.debug(this.name, "Start Parsing BinaryStylesheet");
				new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize).apply(score);
				Logger.debug(this.name, "BinaryStylesheet parsed");
			}
			let partConfigurationParser = null;
			if (partConfigurationData) {
				Logger.debug(this.name, "Start Parsing Part Configuration");
				partConfigurationParser = new PartConfiguration(partConfigurationData);
				partConfigurationParser.apply(score);
				Logger.debug(this.name, "Part Configuration parsed");
			}
			if (layoutConfigurationData && partConfigurationParser != null) {
				Logger.debug(this.name, "Start Parsing Layout Configuration");
				new LayoutConfiguration(partConfigurationParser, layoutConfigurationData).apply(score);
				Logger.debug(this.name, "Layout Configuration parsed");
			}
			return score;
		}
	};
	//#endregion
	//#region src/rendering/utils/AccidentalHelper.ts
	/**
	* @internal
	*/
	var BeatSteps = class {
		maxSteps = -1e3;
		maxStepsNote = null;
		minSteps = -1e3;
		minStepsNote = null;
	};
	/**
	* This small utilty public class allows the assignment of accidentals within a
	* desired scope.
	* @internal
	*/
	var AccidentalHelper = class AccidentalHelper {
		_bar;
		_barRenderer;
		/**
		* We always have 7 steps per octave.
		* (by a step the offsets inbetween score lines is meant,
		*      0 steps is on the first line (counting from top)
		*      1 steps is on the space inbetween the first and the second line
		*/
		static _stepsPerOctave = 7;
		/**
		* Those are the amount of steps for the different clefs in case of a note value 0
		* [Neutral, C3, C4, F4, G2]
		*/
		static _octaveSteps = [
			38,
			32,
			30,
			26,
			38
		];
		/**
		* Diatonic step offsets within an octave.
		*/
		static _diatonicSteps = [
			0,
			1,
			2,
			3,
			4,
			5,
			6
		];
		_registeredAccidentals = /* @__PURE__ */ new Map();
		_appliedScoreSteps = /* @__PURE__ */ new Map();
		_appliedScoreStepsByValue = /* @__PURE__ */ new Map();
		_notesByValue = /* @__PURE__ */ new Map();
		_beatSteps = /* @__PURE__ */ new Map();
		/**
		* The beat on which the highest note of this helper was added.
		* Used together with beaming helper to calculate overflow.
		*/
		maxStepsBeat = null;
		/**
		* The beat on which the lowest note of this helper was added.
		* Used together with beaming helper to calculate overflow.
		*/
		minStepsBeat = null;
		/**
		* The steps of the highest note added to this helper.
		*/
		maxSteps = -1e3;
		/**
		* The steps of the lowest note added to this helper.
		*/
		minSteps = -1e3;
		constructor(barRenderer) {
			this._barRenderer = barRenderer;
			this._bar = barRenderer.bar;
		}
		static getPercussionSteps(note) {
			return PercussionMapper.getArticulation(note)?.staffLine ?? 0;
		}
		static getNoteValue(note) {
			return note.displayValue;
		}
		/**
		* Calculates the accidental for the given note and assignes the value to it.
		* The new accidental type is also registered within the current scope
		* @param note
		* @returns
		*/
		applyAccidental(note) {
			const noteValue = AccidentalHelper.getNoteValue(note);
			const quarterBend = note.hasQuarterToneOffset;
			return this._getAccidental(noteValue, quarterBend, note.beat, false, note);
		}
		/**
		* Calculates the accidental for the given note value and assignes the value to it.
		* The new accidental type is also registered within the current scope
		* @param relatedBeat
		* @param noteValue
		* @param quarterBend
		* @param isHelperNote true if the note registered via this call, is a small helper note (e.g. for bends) or false if it is a main note head (e.g. for harmonics)
		* @returns
		*/
		applyAccidentalForValue(relatedBeat, noteValue, quarterBend, isHelperNote) {
			return this._getAccidental(noteValue, quarterBend, relatedBeat, isHelperNote, null);
		}
		static computeStepsWithoutAccidentals(bar, note) {
			let steps = 0;
			const noteValue = AccidentalHelper.getNoteValue(note);
			if (note.isPercussion) steps = AccidentalHelper.getPercussionSteps(note);
			else {
				const spelling = ModelUtils.resolveSpelling(bar.keySignature, noteValue, note.accidentalMode);
				steps = AccidentalHelper.calculateNoteSteps(bar.clef, spelling);
			}
			return steps;
		}
		_getAccidental(noteValue, quarterBend, relatedBeat, isHelperNote, note = null) {
			let steps = 0;
			let accidentalToSet = AccidentalType.None;
			if (note != null ? note.isPercussion : false) steps = AccidentalHelper.getPercussionSteps(note);
			else {
				const accidentalMode = note ? note.accidentalMode : NoteAccidentalMode.Default;
				const spelling = ModelUtils.resolveSpelling(this._bar.keySignature, noteValue, accidentalMode);
				steps = AccidentalHelper.calculateNoteSteps(this._bar.clef, spelling);
				const currentAccidentalOffset = this._registeredAccidentals.has(steps) ? this._registeredAccidentals.get(steps) : null;
				accidentalToSet = ModelUtils.computeAccidentalForSpelling(this._bar.keySignature, accidentalMode, spelling, quarterBend, currentAccidentalOffset);
				let skipAccidental = false;
				switch (accidentalToSet) {
					case AccidentalType.NaturalQuarterNoteUp:
					case AccidentalType.SharpQuarterNoteUp:
					case AccidentalType.FlatQuarterNoteUp: break;
					default:
						if (note && note.isTieDestination && note.beat.index === 0) {
							const tieOriginBarRenderer = this._barRenderer.scoreRenderer.layout?.getRendererForBar(this._barRenderer.staff.staffId, note.tieOrigin.beat.voice.bar);
							if (tieOriginBarRenderer && tieOriginBarRenderer.staff === this._barRenderer.staff) {
								if (tieOriginBarRenderer.accidentalHelper.getNoteSteps(note.tieOrigin) === steps) skipAccidental = true;
							}
						}
						if (skipAccidental) accidentalToSet = AccidentalType.None;
						break;
				}
				if (!quarterBend && accidentalToSet !== AccidentalType.None) this._registeredAccidentals.set(steps, spelling.accidentalOffset);
			}
			if (note) {
				this._appliedScoreSteps.set(note.id, steps);
				this._notesByValue.set(noteValue, note);
			} else this._appliedScoreStepsByValue.set(noteValue, steps);
			if (this.minSteps === -1e3 || this.minSteps < steps) {
				this.minSteps = steps;
				this.minStepsBeat = relatedBeat;
			}
			if (this.maxSteps === -1e3 || this.maxSteps > steps) {
				this.maxSteps = steps;
				this.maxStepsBeat = relatedBeat;
			}
			if (!isHelperNote) this._registerSteps(relatedBeat, steps, note);
			return accidentalToSet;
		}
		_registerSteps(relatedBeat, steps, note) {
			let beatSteps;
			if (this._beatSteps.has(relatedBeat.id)) beatSteps = this._beatSteps.get(relatedBeat.id);
			else {
				beatSteps = new BeatSteps();
				this._beatSteps.set(relatedBeat.id, beatSteps);
			}
			if (beatSteps.minSteps === -1e3 || steps < beatSteps.minSteps) {
				beatSteps.minSteps = steps;
				beatSteps.minStepsNote = note;
			}
			if (beatSteps.minSteps === -1e3 || steps > beatSteps.maxSteps) {
				beatSteps.maxSteps = steps;
				beatSteps.maxStepsNote = note;
			}
		}
		getMaxSteps(b) {
			return this._beatSteps.has(b.id) ? this._beatSteps.get(b.id).maxSteps : 0;
		}
		getMaxStepsNote(b) {
			return this._beatSteps.has(b.id) ? this._beatSteps.get(b.id).maxStepsNote : null;
		}
		getMinSteps(b) {
			return this._beatSteps.has(b.id) ? this._beatSteps.get(b.id).minSteps : 0;
		}
		getMinStepsNote(b) {
			return this._beatSteps.has(b.id) ? this._beatSteps.get(b.id).minStepsNote : null;
		}
		static calculateNoteSteps(clef, spelling) {
			const clefValue = clef;
			let steps = AccidentalHelper._octaveSteps[clefValue];
			steps -= spelling.octave * AccidentalHelper._stepsPerOctave;
			steps -= AccidentalHelper._diatonicSteps[spelling.degree];
			return steps;
		}
		getNoteSteps(n) {
			return this._appliedScoreSteps.get(n.id);
		}
		getNoteStepsForValue(rawValue, searchForNote = false) {
			if (this._appliedScoreStepsByValue.has(rawValue)) return this._appliedScoreStepsByValue.get(rawValue);
			if (searchForNote && this._notesByValue.has(rawValue)) return this.getNoteSteps(this._notesByValue.get(rawValue));
			return 0;
		}
	};
	//#endregion
	//#region src/importer/MusicXmlImporter.ts
	/**
	* @internal
	*/
	var StaffContext = class {
		slurStarts;
		currentDynamics = DynamicValue.F;
		tieStarts;
		tieStartIds;
		slideOrigins = /* @__PURE__ */ new Map();
		transpose = 0;
		isExplicitlyBeamed = false;
		constructor() {
			this.tieStarts = /* @__PURE__ */ new Set();
			this.tieStartIds = /* @__PURE__ */ new Map();
			this.slideOrigins = /* @__PURE__ */ new Map();
			this.slurStarts = /* @__PURE__ */ new Map();
		}
	};
	/**
	* @internal
	*/
	var InstrumentArticulationWithPlaybackInfo = class extends InstrumentArticulation {
		/**
		* The midi channel number to use when playing the note (-1 if using the default track channels).
		*/
		outputMidiChannel = -1;
		/**
		* The midi channel program to use when playing the note (-1 if using the default track program).
		*/
		outputMidiProgram = -1;
		/**
		* The midi bank to use when playing the note (-1 if using the default track bank).
		*/
		outputMidiBank = -1;
		/**
		* The volume to use when playing the note (-1 if using the default track volume).
		*/
		outputVolume = -1;
		/**
		* The balance to use when playing the note (-1 if using the default track balance).
		*/
		outputBalance = -1;
	};
	/**
	* @internal
	*/
	var TrackInfo = class TrackInfo {
		track;
		firstArticulation;
		instruments = /* @__PURE__ */ new Map();
		_instrumentIdToArticulationIndex = /* @__PURE__ */ new Map();
		_lyricsLine = 0;
		_lyricsLines = /* @__PURE__ */ new Map();
		constructor(track) {
			this.track = track;
		}
		getLyricLine(number) {
			if (this._lyricsLines.has(number)) return this._lyricsLines.get(number);
			const line = this._lyricsLine;
			this._lyricsLines.set(number, line);
			this._lyricsLine++;
			return line;
		}
		static _defaultNoteArticulation = InstrumentArticulation.create(0, "Default", 0, 0, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadWhole);
		getOrCreateArticulation(instrumentId, note) {
			const noteValue = note.octave * 12 + note.tone;
			const lookup = `${instrumentId}_${noteValue}`;
			if (this._instrumentIdToArticulationIndex.has(lookup)) return this._instrumentIdToArticulationIndex.get(lookup);
			let articulation;
			if (this.instruments.has(instrumentId)) articulation = this.instruments.get(instrumentId);
			else articulation = TrackInfo._defaultNoteArticulation;
			const index = this.track.percussionArticulations.length;
			const bar = note.beat.voice.bar;
			let musicXmlStaffSteps;
			if (noteValue === 0) musicXmlStaffSteps = 4;
			else {
				const spelling = ModelUtils.resolveSpelling(bar.keySignature, noteValue, NoteAccidentalMode.Default);
				musicXmlStaffSteps = AccidentalHelper.calculateNoteSteps(bar.clef, spelling);
			}
			const stepDifference = 9 - (note.beat.voice.bar.staff.standardNotationLineCount * 2 - 1);
			const staffLine = musicXmlStaffSteps - stepDifference;
			const newArticulation = InstrumentArticulation.create(articulation.id, articulation.elementType, staffLine, articulation.outputMidiNumber, articulation.noteHeadDefault, articulation.noteHeadHalf, articulation.noteHeadWhole, articulation.techniqueSymbol, articulation.techniqueSymbolPlacement);
			this._instrumentIdToArticulationIndex.set(lookup, index);
			this.track.percussionArticulations.push(newArticulation);
			return index;
		}
	};
	/**
	* @internal
	*/
	var MusicXmlImporter = class MusicXmlImporter extends ScoreImporter {
		_score;
		_idToTrackInfo = /* @__PURE__ */ new Map();
		_indexToTrackInfo = /* @__PURE__ */ new Map();
		_staffToContext = /* @__PURE__ */ new Map();
		_currentBarNumberDisplayPart;
		_currentBarNumberDisplayBar;
		_divisionsPerQuarterNote = 1;
		_currentDynamics = DynamicValue.F;
		get name() {
			return "MusicXML";
		}
		readScore() {
			const xml = this._extractMusicXml();
			const dom = new XmlDocument();
			try {
				dom.parse(xml);
			} catch (e) {
				throw new UnsupportedFormatError("Unsupported format", e);
			}
			this._score = new Score();
			this._score.stylesheet.hideDynamics = true;
			this._parseDom(dom);
			ModelUtils.consolidate(this._score);
			this._score.finish(this.settings);
			this._score.rebuildRepeatGroups();
			return this._score;
		}
		_extractMusicXml() {
			const zip = new ZipReader(this.data, this.settings.importer.maxDecodingBufferSize);
			let entries;
			try {
				entries = zip.read();
			} catch {
				entries = [];
			}
			if (entries.length === 0) {
				this.data.reset();
				return IOHelper.toString(this.data.readAll(), this.settings.importer.encoding);
			}
			const container = entries.find((e) => e.fullName === "META-INF/container.xml");
			if (!container) throw new UnsupportedFormatError("No compressed MusicXML");
			const containerDom = new XmlDocument();
			try {
				containerDom.parse(IOHelper.toString(container.data, this.settings.importer.encoding));
			} catch (e) {
				throw new UnsupportedFormatError("Malformed container.xml, could not parse as XML", e);
			}
			const root = containerDom.firstElement;
			if (!root || root.localName !== "container") throw new UnsupportedFormatError("Malformed container.xml, root element not 'container'");
			const rootFiles = root.findChildElement("rootfiles");
			if (!rootFiles) throw new UnsupportedFormatError("Malformed container.xml, 'container/rootfiles' not found");
			let uncompressedFileFullPath = "";
			for (const c of rootFiles.childElements()) if (c.localName === "rootfile") {
				uncompressedFileFullPath = c.getAttribute("full-path");
				break;
			}
			if (!uncompressedFileFullPath) throw new UnsupportedFormatError("Unsupported compressed MusicXML, missing rootfile");
			const file = entries.find((e) => e.fullName === uncompressedFileFullPath);
			if (!file) throw new UnsupportedFormatError(`Malformed container.xml, '${uncompressedFileFullPath}' not contained in zip`);
			return IOHelper.toString(file.data, this.settings.importer.encoding);
		}
		_parseDom(dom) {
			const root = dom.firstElement;
			if (!root) throw new UnsupportedFormatError("Unsupported format");
			switch (root.localName) {
				case "score-partwise":
					this._parsePartwise(root);
					break;
				case "score-timewise":
					this._parseTimewise(root);
					break;
				default: throw new UnsupportedFormatError("Unsupported format");
			}
		}
		_parsePartwise(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "credit":
					this._parseCredit(c);
					break;
				case "identification":
					this._parseIdentification(c);
					break;
				case "movement-title":
					this._parseMovementTitle(c);
					break;
				case "part":
					this._parsePartwisePart(c);
					break;
				case "part-list":
					this._parsePartList(c);
					break;
				case "work":
					this._parseWork(c);
					break;
			}
		}
		_parseTimewise(element) {
			let index = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "credit":
					this._parseCredit(c);
					break;
				case "identification":
					this._parseIdentification(c);
					break;
				case "movement-title":
					this._parseMovementTitle(c);
					break;
				case "part-list":
					this._parsePartList(c);
					break;
				case "work":
					this._parseWork(c);
					break;
				case "measure":
					this._parseTimewiseMeasure(c, index);
					index++;
					break;
			}
		}
		_parseCredit(element) {
			if (element.getAttribute("page", "1") !== "1") return;
			const creditTypes = [];
			let firstWords = null;
			let fullText = "";
			for (const c of element.childElements()) switch (c.localName) {
				case "credit-type":
					creditTypes.push(c.innerText);
					break;
				case "credit-words":
					if (firstWords === null) firstWords = c;
					fullText += c.innerText;
					break;
			}
			if (creditTypes.length > 0) for (const type of creditTypes) switch (type) {
				case "title":
					this._score.title = MusicXmlImporter._sanitizeDisplay(fullText);
					break;
				case "subtitle":
					this._score.subTitle = MusicXmlImporter._sanitizeDisplay(fullText);
					break;
				case "composer":
					this._score.artist = MusicXmlImporter._sanitizeDisplay(fullText);
					break;
				case "arranger":
					this._score.artist = MusicXmlImporter._sanitizeDisplay(fullText);
					break;
				case "lyricist":
					this._score.words = MusicXmlImporter._sanitizeDisplay(fullText);
					break;
				case "rights":
					this._score.copyright = MusicXmlImporter._sanitizeDisplay(fullText);
					break;
				case "part name": break;
			}
			else if (firstWords) {
				const justify = firstWords.getAttribute("font-size", "0");
				const valign = firstWords.getAttribute("font-size", "top");
				const halign = firstWords.getAttribute("halign", "left");
				if (valign === "top") {
					if (fullText.includes("copyright") || fullText.includes("Copyright") || fullText.includes("©") || fullText.includes("(c)") || fullText.includes("(C)")) {
						this._score.copyright = MusicXmlImporter._sanitizeDisplay(fullText);
						return;
					}
					if (halign === "center" || justify === "center") {
						if (this._score.title.length === 0) {
							this._score.title = MusicXmlImporter._sanitizeDisplay(fullText);
							return;
						}
						if (this._score.subTitle.length === 0) {
							this._score.subTitle = MusicXmlImporter._sanitizeDisplay(fullText);
							return;
						}
						if (this._score.album.length === 0) {
							this._score.album = MusicXmlImporter._sanitizeDisplay(fullText);
							return;
						}
					} else if (halign === "right" || justify === "right") {
						if (this._score.music.length === 0) {
							this._score.music = MusicXmlImporter._sanitizeDisplay(fullText);
							return;
						}
					}
					if (this._score.artist.length === 0) {
						this._score.artist = MusicXmlImporter._sanitizeDisplay(fullText);
						return;
					}
					if (this._score.words.length === 0) {
						this._score.words = MusicXmlImporter._sanitizeDisplay(fullText);
						return;
					}
				}
			}
		}
		static _sanitizeDisplay(text) {
			return text.replaceAll("\r", "").replaceAll("\n", " ").replaceAll("	", "\xA0\xA0").replaceAll(" ", "\xA0");
		}
		_parseIdentification(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "creator":
					if (c.attributes.has("type")) switch (c.attributes.get("type")) {
						case "composer":
							this._score.artist = MusicXmlImporter._sanitizeDisplay(c.innerText);
							break;
						case "lyricist":
							this._score.words = MusicXmlImporter._sanitizeDisplay(c.innerText);
							break;
						case "arranger":
							this._score.music = MusicXmlImporter._sanitizeDisplay(c.innerText);
							break;
					}
					else this._score.artist = MusicXmlImporter._sanitizeDisplay(c.innerText);
					break;
				case "rights":
					if (this._score.copyright.length > 0) this._score.copyright += ", ";
					this._score.copyright += c.innerText;
					if (c.attributes.has("type")) this._score.copyright += ` (${c.attributes.get("type")})`;
					break;
				case "encoding":
					this._parseEncoding(c);
					break;
			}
		}
		_parseEncoding(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "encoder":
					if (this._score.tab.length > 0) this._score.tab += ", ";
					this._score.tab += c.innerText;
					if (c.attributes.has("type")) this._score.tab += ` (${c.attributes.get("type")})`;
					break;
				case "encoding-description":
					this._score.notices += MusicXmlImporter._sanitizeDisplay(c.innerText);
					break;
			}
		}
		_parseMovementTitle(element) {
			if (this._score.title.length === 0) this._score.title = MusicXmlImporter._sanitizeDisplay(element.innerText);
			else this._score.subTitle = MusicXmlImporter._sanitizeDisplay(element.innerText);
		}
		_parsePartList(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "score-part":
					this._parseScorePart(c);
					break;
			}
		}
		_parseScorePart(element) {
			const track = new Track();
			track.ensureStaveCount(1);
			this._score.addTrack(track);
			const id = element.attributes.get("id");
			const trackInfo = new TrackInfo(track);
			this._idToTrackInfo.set(id, trackInfo);
			this._indexToTrackInfo.set(track.index, trackInfo);
			for (const c of element.childElements()) switch (c.localName) {
				case "part-name":
					track.name = MusicXmlImporter._sanitizeDisplay(c.innerText);
					break;
				case "part-name-display":
					track.name = this._parsePartDisplayAsText(c);
					break;
				case "part-abbreviation":
					track.shortName = MusicXmlImporter._sanitizeDisplay(c.innerText);
					break;
				case "part-abbreviation-display":
					track.shortName = this._parsePartDisplayAsText(c);
					break;
				case "score-instrument":
					this._parseScoreInstrument(c, trackInfo);
					break;
				case "midi-device":
					if (c.attributes.has("port")) track.playbackInfo.port = Number.parseInt(c.attributes.get("port"), 10);
					break;
				case "midi-instrument":
					this._parseScorePartMidiInstrument(c, trackInfo);
					break;
			}
			if (trackInfo.firstArticulation) {
				if (trackInfo.firstArticulation.outputMidiProgram >= 0) track.playbackInfo.program = trackInfo.firstArticulation.outputMidiProgram;
				if (trackInfo.firstArticulation.outputMidiBank >= 0) track.playbackInfo.bank = trackInfo.firstArticulation.outputMidiBank;
				if (trackInfo.firstArticulation.outputBalance >= 0) track.playbackInfo.balance = trackInfo.firstArticulation.outputBalance;
				if (trackInfo.firstArticulation.outputVolume >= 0) track.playbackInfo.volume = trackInfo.firstArticulation.outputVolume;
				if (trackInfo.firstArticulation.outputMidiChannel >= 0) {
					track.playbackInfo.primaryChannel = trackInfo.firstArticulation.outputMidiChannel;
					track.playbackInfo.secondaryChannel = trackInfo.firstArticulation.outputMidiChannel;
				}
			}
		}
		_parseScoreInstrument(element, trackInfo) {
			const articulation = new InstrumentArticulationWithPlaybackInfo();
			if (!trackInfo.firstArticulation) trackInfo.firstArticulation = articulation;
			trackInfo.instruments.set(element.getAttribute("id", ""), articulation);
		}
		_parseScorePartMidiInstrument(element, trackInfo) {
			const id = element.getAttribute("id", "");
			if (!trackInfo.instruments.has(id)) return;
			const articulation = trackInfo.instruments.get(id);
			for (const c of element.childElements()) switch (c.localName) {
				case "midi-channel":
					articulation.outputMidiChannel = Number.parseInt(c.innerText, 10) - 1;
					break;
				case "midi-bank":
					articulation.outputMidiBank = Number.parseInt(c.innerText, 10) - 1;
					break;
				case "midi-program":
					articulation.outputMidiProgram = Number.parseInt(c.innerText, 10) - 1;
					break;
				case "midi-unpitched":
					articulation.outputMidiNumber = Number.parseInt(c.innerText, 10) - 1;
					break;
				case "volume":
					articulation.outputVolume = MusicXmlImporter._interpolatePercent(Number.parseFloat(c.innerText));
					break;
				case "pan":
					articulation.outputBalance = MusicXmlImporter._interpolatePan(Number.parseFloat(c.innerText));
					break;
			}
			articulation.id = PercussionMapper.tryMatchKnownArticulation(articulation);
			if (articulation.id < 0) articulation.id = 0;
		}
		static _interpolatePercent(value) {
			return MusicXmlImporter._interpolate(0, 100, 0, 16, value) | 0;
		}
		static _interpolatePan(value) {
			return MusicXmlImporter._interpolate(-90, 90, 0, 16, value) | 0;
		}
		static _interpolate(inputStart, inputEnd, outputStart, outputEnd, value) {
			const t = (value - inputStart) / (inputEnd - inputStart);
			return outputStart + (outputEnd - outputStart) * t;
		}
		_parsePartDisplayAsText(element) {
			let text = "";
			for (const c of element.childElements()) switch (c.localName) {
				case "display-text":
					text += c.innerText;
					break;
				case "accidental-text":
					switch (c.innerText) {
						case "sharp":
							text += "♯";
							break;
						case "natural":
							text += "♮";
							break;
						case "flat":
							text += "♭";
							break;
						case "double-sharp":
							text += "𝄪";
							break;
						case "sharp-sharp":
							text += "♯♯";
							break;
						case "flat-flat":
							text += "𝄫";
							break;
						case "natural-sharp":
							text += "♮♯";
							break;
						case "natural-flat":
							text += "♮♭";
							break;
						case "sharp-down":
							text += "𝄱";
							break;
						case "sharp-up":
							text += "𝄰";
							break;
						case "natural-down":
							text += "𝄯";
							break;
						case "natural-up":
							text += "𝄮";
							break;
						case "flat-down":
							text += "𝄭";
							break;
						case "flat-up":
							text += "𝄬";
							break;
						case "arrow-down":
							text += "↓";
							break;
						case "arrow-up":
							text += "↑";
							break;
						case "triple-sharp":
							text += "♯𝄪";
							break;
						case "triple-flat":
							text += "𝄬𝄬𝄬";
							break;
						case "sharp-1":
							text += "♯¹";
							break;
						case "sharp-2":
							text += "♯²";
							break;
						case "sharp-3":
							text += "♯³";
							break;
						case "sharp-4":
							text += "♯⁴";
							break;
						case "sharp-5":
							text += "♯⁵";
							break;
						case "flat-1":
							text += "♭¹";
							break;
						case "flat-2":
							text += "♭²";
							break;
						case "flat-3":
							text += "♭³";
							break;
						case "flat-4":
							text += "♭⁴";
							break;
						case "flat-5":
							text += "♭⁵";
							break;
					}
					break;
			}
			return MusicXmlImporter._sanitizeDisplay(text);
		}
		_parseWork(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "work-title":
					this._score.title = MusicXmlImporter._sanitizeDisplay(c.innerText);
					break;
			}
		}
		_parsePartwisePart(element) {
			const id = element.attributes.get("id");
			if (!id || !this._idToTrackInfo.has(id)) return;
			const track = this._idToTrackInfo.get(id).track;
			let index = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "measure":
					this._parsePartwiseMeasure(c, track, index);
					index++;
					break;
			}
			this._currentBarNumberDisplayPart = void 0;
		}
		_parsePartwiseMeasure(element, track, index) {
			const masterBar = this._getOrCreateMasterBar(element, index);
			const implicit = element.attributes.get("implicit") === "yes";
			this._parsePartMeasure(element, masterBar, track, implicit, true);
			this._currentBarNumberDisplayBar = void 0;
		}
		_parseTimewiseMeasure(element, index) {
			const masterBar = this._getOrCreateMasterBar(element, index);
			const implicit = element.attributes.get("implicit") === "yes";
			for (const c of element.childElements()) switch (c.localName) {
				case "part":
					this._parseTimewisePart(c, masterBar, implicit);
					this._currentBarNumberDisplayPart = void 0;
					break;
				case "print":
					this._parsePrint(c, masterBar, void 0, true);
					break;
			}
			this._currentBarNumberDisplayBar = void 0;
		}
		_getOrCreateMasterBar(element, index) {
			const implicit = element.attributes.get("implicit") === "yes";
			while (this._score.masterBars.length <= index) {
				const newMasterBar = new MasterBar();
				if (implicit) newMasterBar.isAnacrusis = true;
				this._score.addMasterBar(newMasterBar);
				if (newMasterBar.index > 0) {
					newMasterBar.timeSignatureDenominator = newMasterBar.previousMasterBar.timeSignatureDenominator;
					newMasterBar.timeSignatureNumerator = newMasterBar.previousMasterBar.timeSignatureNumerator;
					newMasterBar.tripletFeel = newMasterBar.previousMasterBar.tripletFeel;
				}
			}
			return this._score.masterBars[index];
		}
		_parseTimewisePart(element, masterBar, implicit) {
			const id = element.attributes.get("id");
			if (!id || !this._idToTrackInfo.has(id)) return;
			const track = this._idToTrackInfo.get(id).track;
			this._parsePartMeasure(element, masterBar, track, implicit, false);
		}
		/**
		* The current musical position within the bar.
		*/
		_musicalPosition = 0;
		/**
		* The last known beat which was parsed. Might be used
		* to access the current voice/staff (e.g. on rests when we don't have notes)
		*/
		_lastBeat = null;
		_parsePartMeasure(element, masterBar, track, implicit, isPartwise) {
			this._musicalPosition = 0;
			this._lastBeat = null;
			masterBar.alternateEndings = this._nextMasterBarRepeatEnding;
			const barLines = [];
			for (const c of element.childElements()) switch (c.localName) {
				case "note":
					this._parseNote(c, masterBar, track);
					break;
				case "backup":
					this._parseBackup(c);
					break;
				case "forward":
					this._parseForward(c);
					break;
				case "direction":
					this._parseDirection(c, masterBar, track);
					break;
				case "attributes":
					this._parseAttributes(c, masterBar, track);
					break;
				case "harmony":
					this._parseHarmony(c, track);
					break;
				case "print":
					this._parsePrint(c, masterBar, track, true);
					break;
				case "sound":
					this._parseSound(c, masterBar, track);
					break;
				case "barline":
					barLines.push(c);
					break;
			}
			for (const barLine of barLines) this._parseBarLine(barLine, masterBar, track);
			this._applySimileMarks(masterBar, track);
			const staff = this._getOrCreateStaff(track, 0);
			const bar = this._getOrCreateBar(staff, masterBar);
			if (implicit) bar.barNumberDisplay = BarNumberDisplay.Hide;
			else if (isPartwise) bar.barNumberDisplay = this._currentBarNumberDisplayBar ?? this._currentBarNumberDisplayPart;
			else bar.barNumberDisplay = this._currentBarNumberDisplayPart ?? this._currentBarNumberDisplayBar;
			this._keyAllStaves = null;
		}
		_parsePrint(element, masterBar, track, isMeasurePrint) {
			if (track !== void 0) {
				if (element.getAttribute("new-system", "no") === "yes") track.addLineBreaks(masterBar.index);
				else if (element.getAttribute("new-page", "no") === "yes") track.addLineBreaks(masterBar.index);
			}
			let newDisplay = void 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "measure-numbering":
					switch (c.innerText) {
						case "none":
							newDisplay = BarNumberDisplay.Hide;
							break;
						case "measure":
							newDisplay = BarNumberDisplay.AllBars;
							break;
						case "system":
							newDisplay = BarNumberDisplay.FirstOfSystem;
							break;
					}
					break;
			}
			if (isMeasurePrint) this._currentBarNumberDisplayBar = newDisplay;
			else this._currentBarNumberDisplayPart = newDisplay;
		}
		_applySimileMarks(masterBar, track) {
			if (this._simileMarkAllStaves !== null) {
				for (const s of track.staves) {
					const bar = this._getOrCreateBar(s, masterBar);
					bar.simileMark = this._simileMarkAllStaves;
					if (bar.simileMark !== SimileMark.None) this._clearBar(bar);
				}
				if (this._simileMarkAllStaves === SimileMark.FirstOfDouble) this._simileMarkAllStaves = SimileMark.SecondOfDouble;
				else this._simileMarkAllStaves = null;
			}
			if (this._simileMarkPerStaff !== null) {
				const keys = Array.from(this._simileMarkPerStaff.keys());
				for (const i of keys) {
					const s = this._getOrCreateStaff(track, i);
					const bar = this._getOrCreateBar(s, masterBar);
					bar.simileMark = this._simileMarkPerStaff.get(i);
					if (bar.simileMark !== SimileMark.None) this._clearBar(bar);
					if (bar.simileMark === SimileMark.FirstOfDouble) this._simileMarkPerStaff.set(i, SimileMark.SecondOfDouble);
					else this._simileMarkPerStaff.delete(i);
				}
				if (this._simileMarkPerStaff.size === 0) this._simileMarkPerStaff = null;
			}
		}
		_clearBar(bar) {
			for (const v of bar.voices) {
				const emptyBeat = new Beat();
				emptyBeat.isEmpty = true;
				v.addBeat(emptyBeat);
			}
		}
		_parseBarLine(element, masterBar, track) {
			for (const c of element.childElements()) switch (c.localName) {
				case "bar-style":
					this._parseBarStyle(c, masterBar, track, element.getAttribute("location", "right"));
					break;
				case "ending":
					this._parseEnding(c, masterBar);
					break;
				case "repeat":
					this._parseRepeat(c, masterBar);
					break;
			}
		}
		_parseRepeat(element, masterBar) {
			const direction = element.getAttribute("direction");
			let times = Number.parseInt(element.getAttribute("times"), 10);
			if (times < 0 || Number.isNaN(times)) times = 2;
			if (direction === "backward") masterBar.repeatCount = times;
			else if (direction === "forward") masterBar.isRepeatStart = true;
		}
		_nextMasterBarRepeatEnding = 0;
		_parseEnding(element, masterBar) {
			const numbers = element.getAttribute("number").split(",").map((v) => Number.parseInt(v, 10));
			let flags = 0;
			for (const num of numbers) flags = flags | 1 << num - 1 & 255;
			masterBar.alternateEndings = flags;
			switch (element.getAttribute("type", "")) {
				case "start":
					this._nextMasterBarRepeatEnding = this._nextMasterBarRepeatEnding | flags;
					break;
				case "stop":
				case "discontinue":
					this._nextMasterBarRepeatEnding = this._nextMasterBarRepeatEnding & ~flags;
					break;
				case "continue": break;
			}
		}
		_parseBarStyle(element, masterBar, track, location) {
			let style = BarLineStyle.Automatic;
			switch (element.innerText) {
				case "dashed":
					style = BarLineStyle.Dashed;
					break;
				case "dotted":
					style = BarLineStyle.Dotted;
					break;
				case "heavy":
					style = BarLineStyle.Heavy;
					break;
				case "heavy-heavy":
					style = BarLineStyle.HeavyHeavy;
					break;
				case "heavy-light":
					style = BarLineStyle.HeavyLight;
					break;
				case "light-heavy":
					style = BarLineStyle.LightHeavy;
					break;
				case "light-light":
					style = BarLineStyle.LightLight;
					break;
				case "none":
					style = BarLineStyle.None;
					break;
				case "regular":
					style = BarLineStyle.Regular;
					break;
				case "short":
					style = BarLineStyle.Short;
					break;
				case "tick":
					style = BarLineStyle.Tick;
					break;
			}
			for (const s of track.staves) {
				const bar = this._getOrCreateBar(s, masterBar);
				switch (location) {
					case "left":
						bar.barLineLeft = style;
						break;
					case "right":
						bar.barLineRight = style;
						break;
				}
			}
		}
		_parseSound(element, masterBar, _track) {
			for (const c of element.childElements()) switch (c.localName) {
				case "midi-instrument":
					this._parseSoundMidiInstrument(c, masterBar);
					break;
				case "swing":
					this._parseSwing(c, masterBar);
					break;
				case "offset": break;
			}
			if (element.attributes.has("coda")) masterBar.addDirection(Direction.TargetCoda);
			if (element.attributes.has("tocoda")) masterBar.addDirection(Direction.JumpDaCoda);
			if (element.attributes.has("dacapo")) masterBar.addDirection(Direction.JumpDaCapo);
			if (element.attributes.has("dalsegno")) masterBar.addDirection(Direction.JumpDalSegno);
			if (element.attributes.has("fine")) masterBar.addDirection(Direction.TargetFine);
			if (element.attributes.has("segno")) masterBar.addDirection(Direction.TargetSegno);
			if (element.attributes.has("pan")) {
				if (!this._nextBeatAutomations) this._nextBeatAutomations = [];
				const automation = new Automation();
				automation.type = AutomationType.Balance;
				automation.value = MusicXmlImporter._interpolatePan(Number.parseFloat(element.attributes.get("pan")));
				this._nextBeatAutomations.push(automation);
			}
			if (element.attributes.has("tempo")) {
				if (!this._nextBeatAutomations) this._nextBeatAutomations = [];
				const automation = new Automation();
				automation.type = AutomationType.Tempo;
				automation.value = MusicXmlImporter._interpolatePercent(Number.parseFloat(element.attributes.get("tempo")));
				this._nextBeatAutomations.push(automation);
			}
		}
		_parseSwing(element, masterBar) {
			let first = 0;
			let second = 0;
			let swingType = null;
			for (const c of element.childElements()) switch (c.localName) {
				case "straight":
					masterBar.tripletFeel = TripletFeel.NoTripletFeel;
					return;
				case "first":
					first = Number.parseInt(c.innerText, 10);
					break;
				case "second":
					second = Number.parseInt(c.innerText, 10);
					break;
				case "swing-type":
					swingType = this._parseBeatDuration(c);
					break;
			}
			if (!swingType) swingType = Duration.Eighth;
			if (swingType === Duration.Eighth) {
				if (first === 2 && second === 1) masterBar.tripletFeel = TripletFeel.Triplet8th;
				else if (first === 3 && second === 1) masterBar.tripletFeel = TripletFeel.Dotted8th;
				else if (first === 1 && second === 3) masterBar.tripletFeel = TripletFeel.Scottish8th;
			} else if (swingType === Duration.Sixteenth) {
				if (first === 2 && second === 1) masterBar.tripletFeel = TripletFeel.Triplet16th;
				else if (first === 3 && second === 1) masterBar.tripletFeel = TripletFeel.Dotted16th;
				else if (first === 1 && second === 3) masterBar.tripletFeel = TripletFeel.Scottish16th;
			}
		}
		_nextBeatAutomations = null;
		_nextBeatChord = null;
		_nextBeatCrescendo = null;
		_nextBeatLetRing = false;
		_nextBeatPalmMute = false;
		_nextBeatOttavia = null;
		_nextBeatText = null;
		_parseSoundMidiInstrument(element, _masterBar) {
			let automation;
			for (const c of element.childElements()) switch (c.localName) {
				case "midi-bank":
					if (!this._nextBeatAutomations) this._nextBeatAutomations = [];
					automation = new Automation();
					automation.type = AutomationType.Bank;
					automation.value = Number.parseInt(c.innerText, 10) - 1;
					this._nextBeatAutomations.push(automation);
					break;
				case "midi-program":
					if (!this._nextBeatAutomations) this._nextBeatAutomations = [];
					automation = new Automation();
					automation.type = AutomationType.Instrument;
					automation.value = Number.parseInt(c.innerText, 10) - 1;
					this._nextBeatAutomations.push(automation);
					break;
				case "volume":
					if (!this._nextBeatAutomations) this._nextBeatAutomations = [];
					automation = new Automation();
					automation.type = AutomationType.Volume;
					automation.value = MusicXmlImporter._interpolatePercent(Number.parseFloat(c.innerText));
					this._nextBeatAutomations.push(automation);
					break;
				case "pan":
					if (!this._nextBeatAutomations) this._nextBeatAutomations = [];
					automation = new Automation();
					automation.type = AutomationType.Balance;
					automation.value = MusicXmlImporter._interpolatePan(Number.parseFloat(c.innerText));
					this._nextBeatAutomations.push(automation);
					break;
			}
		}
		_parseHarmony(element, _track) {
			const chord = new Chord();
			let degreeParenthesis = false;
			let degree = "";
			for (const childNode of element.childElements()) switch (childNode.localName) {
				case "root":
					chord.name = this._parseHarmonyRoot(childNode);
					break;
				case "kind":
					chord.name = chord.name + this._parseHarmonyKind(childNode);
					if (childNode.getAttribute("parentheses-degrees", "no") === "yes") degreeParenthesis = true;
					break;
				case "frame":
					this._parseHarmonyFrame(childNode, chord);
					break;
				case "degree":
					degree += this._parseDegree(childNode);
					break;
			}
			if (degree) chord.name += degreeParenthesis ? `(${degree})` : degree;
			if (element.getAttribute("print-frame", "no") === "yes") {
				chord.showDiagram = true;
				this._score.stylesheet.globalDisplayChordDiagramsInScore = true;
			}
			if (element.getAttribute("print-object", "yes") === "yes") chord.showDiagram = true;
			if (this._nextBeatChord === null) this._nextBeatChord = chord;
		}
		_parseDegree(element) {
			let value = "";
			let alter = "";
			let type = "";
			for (const c of element.childElements()) switch (c.localName) {
				case "degree-value":
					value = c.innerText;
					break;
				case "degree-alter":
					switch (c.innerText) {
						case "-1":
							alter = "♭";
							break;
						case "1":
							alter = "♯";
							break;
					}
					break;
				case "degree-type":
					type += c.getAttribute("text", "");
					break;
			}
			return `${type}${alter}${value}`;
		}
		_parseHarmonyRoot(element) {
			let rootStep = "";
			let rootAlter = "";
			for (const c of element.childElements()) switch (c.localName) {
				case "root-step":
					rootStep = c.innerText;
					break;
				case "root-alter":
					switch (Number.parseFloat(c.innerText)) {
						case -2:
							rootAlter = "bb";
							break;
						case -1:
							rootAlter = "b";
							break;
						case 0:
							rootAlter = "";
							break;
						case 1:
							rootAlter = "#";
							break;
						case 2:
							rootAlter = "##";
							break;
					}
					break;
			}
			return rootStep + rootAlter;
		}
		_parseHarmonyKind(xmlNode) {
			const kindText = xmlNode.getAttribute("text");
			let resultKind = "";
			if (kindText) resultKind = kindText;
			else {
				const kindContent = xmlNode.innerText;
				switch (kindContent) {
					case "major":
						resultKind = "";
						break;
					case "minor":
						resultKind = "m";
						break;
					case "augmented":
						resultKind = "+";
						break;
					case "diminished":
						resultKind = "○";
						break;
					case "dominant":
						resultKind = "7";
						break;
					case "major-seventh":
						resultKind = "7M";
						break;
					case "minor-seventh":
						resultKind = "m7";
						break;
					case "diminished-seventh":
						resultKind = "○7";
						break;
					case "augmented-seventh":
						resultKind = "+7";
						break;
					case "half-diminished":
						resultKind = "⍉";
						break;
					case "major-minor":
						resultKind = "mMaj";
						break;
					case "major-sixth":
						resultKind = "maj6";
						break;
					case "minor-sixth":
						resultKind = "m6";
						break;
					case "dominant-ninth":
						resultKind = "9";
						break;
					case "major-ninth":
						resultKind = "maj9";
						break;
					case "minor-ninth":
						resultKind = "m9";
						break;
					case "dominant-11th":
						resultKind = "11";
						break;
					case "major-11th":
						resultKind = "maj11";
						break;
					case "minor-11th":
						resultKind = "m11";
						break;
					case "dominant-13th":
						resultKind = "13";
						break;
					case "major-13th":
						resultKind = "maj13";
						break;
					case "minor-13th":
						resultKind = "m13";
						break;
					case "suspended-second":
						resultKind = "sus2";
						break;
					case "suspended-fourth":
						resultKind = "sus4";
						break;
					case "Neapolitan":
						resultKind = "♭II";
						break;
					case "Italian":
						resultKind = "It⁺⁶";
						break;
					case "French":
						resultKind = "Fr⁺⁶";
						break;
					case "German":
						resultKind = "Fr⁺⁶";
						break;
					default:
						resultKind = kindContent;
						break;
				}
			}
			return resultKind;
		}
		_parseHarmonyFrame(xmlNode, chord) {
			for (const frameChild of xmlNode.childElements()) switch (frameChild.localName) {
				case "frame-strings":
					const stringsCount = Number.parseInt(frameChild.innerText, 10);
					chord.strings = new Array(stringsCount);
					for (let i = 0; i < stringsCount; i++) chord.strings[i] = -1;
					break;
				case "first-fret":
					chord.firstFret = Number.parseInt(frameChild.innerText, 10);
					break;
				case "frame-note":
					let stringNo = null;
					let fretNo = null;
					for (const noteChild of frameChild.childElements()) switch (noteChild.localName) {
						case "string":
							stringNo = Number.parseInt(noteChild.innerText, 10);
							break;
						case "fret":
							fretNo = Number.parseInt(noteChild.innerText, 10);
							if (stringNo && fretNo >= 0) chord.strings[stringNo - 1] = fretNo;
							break;
						case "barre":
							if (stringNo && fretNo && noteChild.getAttribute("type") === "start") chord.barreFrets.push(fretNo);
							break;
					}
					break;
			}
		}
		_parseAttributes(element, masterBar, track) {
			let staffIndex;
			let staff;
			let bar;
			if (this._lastBeat == null) for (const c of element.childElements()) switch (c.localName) {
				case "divisions":
					this._divisionsPerQuarterNote = Number.parseFloat(c.innerText);
					break;
				case "key":
					this._parseKey(c, masterBar, track);
					break;
				case "time":
					this._parseTime(c, masterBar);
					break;
				case "staves":
					track.ensureStaveCount(Number.parseInt(c.innerText, 10));
					break;
				case "clef":
					staffIndex = Number.parseInt(c.getAttribute("number", "1"), 10) - 1;
					staff = this._getOrCreateStaff(track, staffIndex);
					bar = this._getOrCreateBar(staff, masterBar);
					this._parseClef(c, bar);
					break;
				case "staff-details":
					staffIndex = Number.parseInt(c.getAttribute("number", "1"), 10) - 1;
					staff = this._getOrCreateStaff(track, staffIndex);
					this._parseStaffDetails(c, staff);
					break;
				case "transpose":
					this._parseTranspose(c, track);
					break;
				case "measure-style":
					this._parseMeasureStyle(c, track, false);
					break;
			}
			else for (const c of element.childElements()) switch (c.localName) {
				case "divisions":
					this._divisionsPerQuarterNote = Number.parseFloat(c.innerText);
					break;
				case "measure-style":
					this._parseMeasureStyle(c, track, true);
					break;
			}
		}
		_simileMarkAllStaves = null;
		_simileMarkPerStaff = null;
		_isBeatSlash = false;
		_parseMeasureStyle(element, _track, midBar) {
			for (const c of element.childElements()) switch (c.localName) {
				case "measure-repeat":
					if (!midBar) {
						let simileMark = null;
						switch (c.getAttribute("type")) {
							case "start":
								switch (Number.parseInt(c.getAttribute("slashes", "1"), 10)) {
									case 1:
										simileMark = SimileMark.Simple;
										break;
									case 2:
										simileMark = SimileMark.FirstOfDouble;
										break;
									default: break;
								}
								break;
							case "stop":
								simileMark = null;
								break;
						}
						if (element.attributes.has("number")) {
							this._simileMarkPerStaff = this._simileMarkPerStaff ?? /* @__PURE__ */ new Map();
							const staff = Number.parseInt(element.attributes.get("number"), 10) - 1;
							if (simileMark == null) this._simileMarkPerStaff.delete(staff);
							else this._simileMarkPerStaff.set(staff, simileMark);
						} else this._simileMarkAllStaves = simileMark;
					}
					break;
				case "slash":
					switch (c.getAttribute("type")) {
						case "start":
							this._isBeatSlash = true;
							break;
						case "stop":
							this._isBeatSlash = false;
							break;
					}
					break;
			}
		}
		_parseTranspose(element, track) {
			let semitones = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "chromatic":
					semitones += Number.parseFloat(c.innerText);
					break;
				case "octave-change":
					semitones += Number.parseFloat(c.innerText) * 12;
					break;
			}
			if (element.attributes.has("number")) {
				const staff = this._getOrCreateStaff(track, Number.parseInt(element.attributes.get("number"), 10) - 1);
				this._getStaffContext(staff).transpose = semitones;
				staff.displayTranspositionPitch = semitones;
			} else for (const staff of track.staves) {
				this._getStaffContext(staff).transpose = semitones;
				staff.displayTranspositionPitch = semitones;
			}
		}
		_parseStaffDetails(element, staff) {
			for (const c of element.childElements()) switch (c.localName) {
				case "staff-lines":
					staff.standardNotationLineCount = Number.parseInt(c.innerText, 10);
					break;
				case "staff-tuning":
					this._parseStaffTuning(c, staff);
					break;
				case "capo":
					staff.capo = Number.parseInt(c.innerText, 10);
					break;
			}
		}
		_parseStaffTuning(element, staff) {
			if (staff.stringTuning.tunings.length === 0) {
				staff.showTablature = true;
				staff.showStandardNotation = false;
				staff.stringTuning.tunings = new Array(staff.standardNotationLineCount).fill(0);
			}
			const line = Number.parseInt(element.getAttribute("line"), 10);
			let tuningStep = "C";
			let tuningOctave = "";
			let tuningAlter = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "tuning-step":
					tuningStep = c.innerText;
					break;
				case "tuning-alter":
					tuningAlter = Number.parseFloat(c.innerText);
					break;
				case "tuning-octave":
					tuningOctave = c.innerText;
					break;
			}
			const tuning = ModelUtils.getTuningForText(tuningStep + tuningOctave) + tuningAlter;
			staff.tuning[staff.tuning.length - line] = tuning;
		}
		_parseClef(element, bar) {
			let sign = "s";
			let line = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "sign":
					sign = c.innerText.toLowerCase();
					break;
				case "line":
					line = Number.parseInt(c.innerText, 10);
					break;
				case "clef-octave-change":
					switch (Number.parseInt(c.innerText, 10)) {
						case -2:
							bar.clefOttava = Ottavia._15mb;
							break;
						case -1:
							bar.clefOttava = Ottavia._8vb;
							break;
						case 1:
							bar.clefOttava = Ottavia._8va;
							break;
						case 2:
							bar.clefOttava = Ottavia._15mb;
							break;
					}
					break;
			}
			switch (sign) {
				case "g":
					bar.clef = Clef.G2;
					break;
				case "f":
					bar.clef = Clef.F4;
					break;
				case "c":
					if (line === 3) bar.clef = Clef.C3;
					else bar.clef = Clef.C4;
					break;
				case "percussion":
					bar.clef = Clef.Neutral;
					if (bar.index === 0) bar.staff.isPercussion = true;
					break;
				case "tab":
					bar.clef = Clef.G2;
					bar.staff.showTablature = true;
					break;
				default:
					bar.clef = Clef.G2;
					break;
			}
		}
		_parseTime(element, masterBar) {
			let beatsParsed = false;
			let beatTypeParsed = false;
			for (const c of element.childElements()) {
				const v = c.innerText;
				switch (c.localName) {
					case "beats":
						if (!beatsParsed) {
							if (v.indexOf("+") === -1) masterBar.timeSignatureNumerator = Number.parseInt(v, 10);
							else masterBar.timeSignatureNumerator = v.split("+").map((v) => Number.parseInt(v, 10)).reduce((sum, v) => v + sum, 0);
							beatsParsed = true;
						}
						break;
					case "beat-type":
						if (!beatTypeParsed) {
							if (v.indexOf("+") === -1) masterBar.timeSignatureDenominator = Number.parseInt(v, 10);
							else masterBar.timeSignatureDenominator = v.split("+").map((v) => Number.parseInt(v, 10)).reduce((sum, v) => v + sum, 0);
							beatTypeParsed = true;
						}
						break;
				}
			}
			switch (element.getAttribute("symbol", "")) {
				case "common":
				case "cut":
					masterBar.timeSignatureCommon = true;
					break;
			}
		}
		_keyAllStaves = null;
		_parseKey(element, masterBar, track) {
			let fifths = -KeySignature.C;
			let mode = "";
			for (const c of element.childElements()) switch (c.localName) {
				case "fifths":
					fifths = Number.parseInt(c.innerText, 10);
					break;
				case "mode":
					mode = c.innerText;
					break;
			}
			let keySignature;
			if (-7 <= fifths && fifths <= 7) keySignature = fifths;
			else keySignature = KeySignature.C;
			let keySignatureType;
			if (mode === "minor") keySignatureType = KeySignatureType.Minor;
			else keySignatureType = KeySignatureType.Major;
			if (element.attributes.has("number")) {
				const staff = this._getOrCreateStaff(track, Number.parseInt(element.attributes.get("number"), 10) - 1);
				const bar = this._getOrCreateBar(staff, masterBar);
				bar.keySignature = keySignature;
				bar.keySignatureType = keySignatureType;
			} else {
				this._keyAllStaves = [keySignature, keySignatureType];
				for (const s of track.staves) if (s.bars.length > masterBar.index) {
					s.bars[masterBar.index].keySignature = keySignature;
					s.bars[masterBar.index].keySignatureType = keySignatureType;
				}
			}
		}
		_parseDirection(element, masterBar, track) {
			const directionTypes = [];
			let offset = null;
			let staffIndex = -1;
			let tempo = -1;
			for (const c of element.childElements()) switch (c.localName) {
				case "direction-type":
					const type = c.firstElement;
					if (type) directionTypes.push(type);
					break;
				case "offset":
					offset = Number.parseFloat(c.innerText);
					break;
				case "voice": break;
				case "staff":
					staffIndex = Number.parseInt(c.innerText, 10) - 1;
					break;
				case "sound":
					if (c.attributes.has("tempo")) tempo = Number.parseFloat(c.attributes.get("tempo"));
					break;
			}
			let staff = null;
			if (staffIndex >= 0) staff = this._getOrCreateStaff(track, staffIndex);
			else if (this._lastBeat !== null) staff = this._lastBeat.voice.bar.staff;
			else staff = this._getOrCreateStaff(track, 0);
			const bar = staff ? this._getOrCreateBar(staff, masterBar) : null;
			const getRatioPosition = () => {
				let timelyPosition = this._musicalPosition;
				if (offset !== null) timelyPosition += offset;
				const totalDuration = masterBar.calculateDuration(false);
				return timelyPosition / totalDuration;
			};
			if (tempo > 0) {
				const tempoAutomation = new Automation();
				tempoAutomation.type = AutomationType.Tempo;
				tempoAutomation.value = tempo;
				tempoAutomation.ratioPosition = getRatioPosition();
				if (!this._hasSameTempo(masterBar, tempoAutomation)) masterBar.tempoAutomations.push(tempoAutomation);
			}
			let previousWords = "";
			for (const direction of directionTypes) switch (direction.localName) {
				case "rehearsal":
					masterBar.section = new Section();
					masterBar.section.marker = direction.innerText;
					break;
				case "segno":
					masterBar.addDirection(Direction.TargetSegno);
					break;
				case "coda":
					masterBar.addDirection(Direction.TargetCoda);
					break;
				case "words":
					previousWords = direction.innerText;
					break;
				case "wedge":
					switch (direction.getAttribute("type")) {
						case "crescendo":
							this._nextBeatCrescendo = CrescendoType.Crescendo;
							break;
						case "diminuendo":
							this._nextBeatCrescendo = CrescendoType.Decrescendo;
							break;
						case "stop":
							this._nextBeatCrescendo = null;
							break;
					}
					break;
				case "dynamics":
					const newDynamics = this._parseDynamics(direction);
					if (newDynamics !== null) {
						this._currentDynamics = newDynamics;
						this._score.stylesheet.hideDynamics = false;
					}
					break;
				case "dashes":
					const type = direction.getAttribute("type", "start");
					switch (previousWords) {
						case "LetRing":
							this._nextBeatLetRing = type === "start" || type === "continue";
							break;
						case "P.M.":
							this._nextBeatPalmMute = type === "start" || type === "continue";
							break;
					}
					previousWords = "";
					break;
				case "pedal":
					const pedal = this._parsePedal(direction);
					if (pedal && bar) {
						pedal.ratioPosition = getRatioPosition();
						const canHaveUp = bar.sustainPedals.length > 0 && bar.sustainPedals[bar.sustainPedals.length - 1].pedalType !== SustainPedalMarkerType.Up;
						if (pedal.pedalType !== SustainPedalMarkerType.Up || canHaveUp) bar.sustainPedals.push(pedal);
					}
					break;
				case "metronome":
					this._parseMetronome(direction, masterBar, getRatioPosition());
					break;
				case "octave-shift":
					this._nextBeatOttavia = this._parseOctaveShift(direction);
					break;
			}
			if (previousWords) this._nextBeatText = previousWords;
		}
		_parseOctaveShift(element) {
			const type = element.getAttribute("type");
			switch (Number.parseInt(element.getAttribute("size", "8"), 10)) {
				case 15:
					switch (type) {
						case "up": return Ottavia._15mb;
						case "down": return Ottavia._15ma;
						case "stop": return Ottavia.Regular;
						case "continue": return this._nextBeatOttavia;
					}
					break;
				case 8:
					switch (type) {
						case "up": return Ottavia._8vb;
						case "down": return Ottavia._8va;
						case "stop": return Ottavia.Regular;
						case "continue": return this._nextBeatOttavia;
					}
					break;
			}
			return null;
		}
		_parseMetronome(element, masterBar, ratioPosition) {
			let unit = null;
			let perMinute = -1;
			for (const c of element.childElements()) switch (c.localName) {
				case "beat-unit":
					unit = this._parseBeatDuration(c);
					break;
				case "per-minute":
					perMinute = Number.parseFloat(c.innerText);
					break;
			}
			if (unit !== null && perMinute > 0) {
				const tempoAutomation = new Automation();
				tempoAutomation.type = AutomationType.Tempo;
				tempoAutomation.value = perMinute * (unit / 4);
				tempoAutomation.ratioPosition = ratioPosition;
				if (!this._hasSameTempo(masterBar, tempoAutomation)) masterBar.tempoAutomations.push(tempoAutomation);
			}
		}
		_hasSameTempo(masterBar, tempoAutomation) {
			for (const existing of masterBar.tempoAutomations) if (tempoAutomation.ratioPosition === existing.ratioPosition && tempoAutomation.value === existing.value) return true;
			return false;
		}
		_parsePedal(element) {
			const marker = new SustainPedalMarker();
			switch (element.getAttribute("type")) {
				case "start":
					marker.pedalType = SustainPedalMarkerType.Down;
					break;
				case "stop":
					marker.pedalType = SustainPedalMarkerType.Up;
					break;
				case "continue":
					marker.pedalType = SustainPedalMarkerType.Hold;
					break;
				default: return null;
			}
			return marker;
		}
		_parseDynamics(element) {
			for (const c of element.childElements()) {
				const dynamicString = c.localName.toUpperCase();
				switch (dynamicString) {
					case "PPP":
					case "PP":
					case "P":
					case "MP":
					case "MF":
					case "F":
					case "FF":
					case "FFF":
					case "PPPP":
					case "PPPPP":
					case "PPPPPP":
					case "FFFF":
					case "FFFFF":
					case "FFFFFF":
					case "SF":
					case "SFP":
					case "SFPP":
					case "FP":
					case "RF":
					case "RFZ":
					case "SFZ":
					case "SFFZ":
					case "FZ":
					case "N":
					case "PF":
					case "SFZP": return DynamicValue[dynamicString];
				}
			}
			return null;
		}
		_parseForward(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "duration":
					this._musicalPosition += this._musicXmlDivisionsToAlphaTabTicks(Number.parseFloat(c.innerText));
					break;
			}
		}
		_parseBackup(element) {
			for (const c of element.childElements()) switch (c.localName) {
				case "duration":
					if (this._lastBeat) {
						let musicalPosition = this._musicalPosition;
						musicalPosition -= this._musicXmlDivisionsToAlphaTabTicks(Number.parseFloat(c.innerText));
						if (musicalPosition < 0) musicalPosition = 0;
						this._musicalPosition = musicalPosition;
					}
					break;
			}
		}
		_getOrCreateStaff(track, staffIndex) {
			while (track.staves.length <= staffIndex) {
				const staff = new Staff();
				track.addStaff(staff);
				if (this._score.masterBars.length > 0) this._getOrCreateBar(staff, this._score.masterBars[this._score.masterBars.length - 1]);
			}
			return track.staves[staffIndex];
		}
		_getOrCreateBar(staff, masterBar) {
			const voiceCount = staff.bars.length === 0 ? 1 : staff.bars[0].voices.length;
			while (staff.bars.length <= masterBar.index) {
				const newBar = new Bar();
				staff.addBar(newBar);
				if (newBar.previousBar) {
					newBar.clef = newBar.previousBar.clef;
					newBar.clefOttava = newBar.previousBar.clefOttava;
					newBar.keySignature = newBar.previousBar.keySignature;
					newBar.keySignatureType = newBar.previousBar.keySignatureType;
				}
				if (this._keyAllStaves != null) {
					newBar.keySignature = this._keyAllStaves[0];
					newBar.keySignatureType = this._keyAllStaves[1];
				}
				for (let i = 0; i < voiceCount; i++) {
					const voice = new Voice$1();
					newBar.addVoice(voice);
				}
			}
			return staff.bars[masterBar.index];
		}
		_getOrCreateVoice(bar, voiceIndex) {
			let voicesCreated = false;
			while (bar.voices.length <= voiceIndex) {
				bar.addVoice(new Voice$1());
				voicesCreated = true;
			}
			if (voicesCreated) for (const b of bar.staff.bars) while (b.voices.length <= voiceIndex) b.addVoice(new Voice$1());
			return bar.voices[voiceIndex];
		}
		_parseNote(element, masterBar, track) {
			let beat = null;
			let graceType = GraceType.None;
			let graceDurationInDivisions = 0;
			let beamMode = null;
			let isChord = false;
			let staffIndex = 0;
			let voiceIndex = 0;
			let durationInTicks = -1;
			let beatDuration = null;
			let dots = 0;
			let tupletNumerator = -1;
			let tupletDenominator = -1;
			let preferredBeamDirection = null;
			let note = null;
			let isPitched = false;
			let instrumentId = null;
			const noteIsVisible = element.getAttribute("print-object", "yes") !== "no";
			const ensureBeat = () => {
				if (beat !== null) return;
				if (isChord && !this._lastBeat) {
					Logger.warning("MusicXML", "Malformed MusicXML, <chord /> cannot be set on the first note of a measure");
					isChord = false;
				}
				if (isChord && !note) {
					Logger.warning("MusicXML", "Cannot mix <chord /> and <rest />");
					isChord = false;
				}
				const staff = this._getOrCreateStaff(track, staffIndex);
				if (isChord) {
					beat = this._lastBeat;
					beat.addNote(note);
					return;
				}
				const bar = this._getOrCreateBar(staff, masterBar);
				const voice = this._getOrCreateVoice(bar, voiceIndex);
				const actualMusicalPosition = voice.beats.length === 0 ? 0 : voice.beats[voice.beats.length - 1].displayEnd;
				let gap = this._musicalPosition - actualMusicalPosition;
				if (gap > 0) {
					if (this._lastBeat && this._lastBeat.beamingMode === BeatBeamingMode.ForceMergeWithNext && this._lastBeat.voice.bar.staff.index !== staffIndex && voice.beats.length > 0 && voice.beats[voice.beats.length - 1].beamingMode === BeatBeamingMode.ForceMergeWithNext) {
						const preferredDuration = voice.beats[voice.beats.length - 1].duration;
						while (gap > 0) {
							const restGap = this._createRestForGap(gap, preferredDuration);
							if (restGap !== null) {
								this._insertBeatToVoice(restGap, voice);
								gap -= restGap.playbackDuration;
							} else break;
						}
					}
					if (gap > 0) {
						const placeholder = new Beat();
						placeholder.dynamics = this._currentDynamics;
						placeholder.isEmpty = true;
						placeholder.duration = Duration.TwoHundredFiftySixth;
						placeholder.overrideDisplayDuration = gap;
						placeholder.updateDurations();
						this._insertBeatToVoice(placeholder, voice);
					}
				} else if (gap < 0) Logger.error("MusicXML", "Unsupported forward/backup detected. Cannot fill new beats into already filled area of voice");
				if (durationInTicks < 0 && beatDuration !== null) {
					durationInTicks = MidiUtils.toTicks(beatDuration);
					if (dots > 0) durationInTicks = MidiUtils.applyDot(durationInTicks, dots === 2);
				}
				const newBeat = new Beat();
				beat = newBeat;
				if (beamMode === null) newBeat.beamingMode = this._getStaffContext(staff).isExplicitlyBeamed ? BeatBeamingMode.ForceSplitToNext : BeatBeamingMode.Auto;
				else {
					newBeat.beamingMode = beamMode;
					this._getStaffContext(staff).isExplicitlyBeamed = true;
				}
				newBeat.isEmpty = false;
				newBeat.dynamics = this._currentDynamics;
				if (this._isBeatSlash) newBeat.slashed = true;
				const automations = this._nextBeatAutomations;
				this._nextBeatAutomations = null;
				if (automations !== null) for (const automation of automations) newBeat.automations.push(automation);
				const chord = this._nextBeatChord;
				this._nextBeatChord = null;
				if (chord !== null) {
					newBeat.chordId = chord.uniqueId;
					if (!voice.bar.staff.hasChord(chord.uniqueId)) voice.bar.staff.addChord(newBeat.chordId, chord);
				}
				const crescendo = this._nextBeatCrescendo;
				if (crescendo !== null) newBeat.crescendo = crescendo;
				const ottavia = this._nextBeatOttavia;
				if (ottavia !== null) newBeat.ottava = ottavia;
				newBeat.isLetRing = this._nextBeatLetRing;
				newBeat.isPalmMute = this._nextBeatPalmMute;
				if (this._nextBeatText) {
					newBeat.text = this._nextBeatText;
					this._nextBeatText = null;
				}
				if (note !== null) newBeat.addNote(note);
				this._insertBeatToVoice(newBeat, voice);
				if (graceType !== GraceType.None) {
					newBeat.graceType = graceType;
					this._applyBeatDurationFromTicks(newBeat, graceDurationInDivisions, null, false);
				} else {
					newBeat.tupletNumerator = tupletNumerator;
					newBeat.tupletDenominator = tupletDenominator;
					newBeat.dots = dots;
					newBeat.preferredBeamDirection = preferredBeamDirection;
					this._applyBeatDurationFromTicks(newBeat, durationInTicks, beatDuration, true);
				}
				this._musicalPosition = newBeat.displayEnd;
				this._lastBeat = newBeat;
			};
			for (const c of element.childElements()) switch (c.localName) {
				case "grace":
					const makeTime = Number.parseFloat(c.getAttribute("make-time", "-1"));
					if (makeTime >= 0) {
						graceDurationInDivisions = this._musicXmlDivisionsToAlphaTabTicks(makeTime);
						graceType = GraceType.BeforeBeat;
					} else graceType = GraceType.OnBeat;
					if (c.getAttribute("slash") === "yes") graceType = GraceType.BeforeBeat;
					break;
				case "chord":
					isChord = true;
					break;
				case "cue": return;
				case "pitch":
					note = this._parsePitch(c);
					isPitched = true;
					break;
				case "unpitched":
					note = this._parseUnpitched(c, track);
					break;
				case "rest":
					note = null;
					if (beatDuration === null) beatDuration = Duration.Whole;
					break;
				case "duration":
					durationInTicks = this._parseDuration(c);
					break;
				case "instrument":
					instrumentId = c.getAttribute("id", "");
					break;
				case "voice":
					voiceIndex = Number.parseInt(c.innerText, 10);
					if (Number.isNaN(voiceIndex)) {
						Logger.warning("MusicXML", "Voices need to be specified as numbers");
						voiceIndex = 0;
					} else voiceIndex = voiceIndex - 1;
					break;
				case "type":
					beatDuration = this._parseBeatDuration(c);
					break;
				case "dot":
					dots++;
					break;
				case "accidental":
					if (note === null) Logger.warning("MusicXML", "Malformed MusicXML, missing pitch or unpitched for note");
					else this._parseAccidental(c, note);
					break;
				case "time-modification":
					for (const tmc of c.childElements()) switch (tmc.localName) {
						case "actual-notes":
							tupletNumerator = Number.parseInt(tmc.innerText, 10);
							break;
						case "normal-notes":
							tupletDenominator = Number.parseInt(tmc.innerText, 10);
							break;
					}
					break;
				case "stem":
					preferredBeamDirection = this._parseStem(c);
					break;
				case "notehead":
					if (note === null) Logger.warning("MusicXML", "Malformed MusicXML, missing pitch or unpitched for note");
					else this._parseNoteHead(c, note, beatDuration ?? Duration.Quarter, preferredBeamDirection ?? this._estimateBeamDirection(note));
					break;
				case "staff":
					staffIndex = Number.parseInt(c.innerText, 10) - 1;
					break;
				case "beam":
					if (c.getAttribute("number", "1") === "1") switch (c.innerText) {
						case "begin":
							beamMode = BeatBeamingMode.ForceMergeWithNext;
							break;
						case "continue":
							beamMode = BeatBeamingMode.ForceMergeWithNext;
							break;
						case "end":
							beamMode = BeatBeamingMode.ForceSplitToNext;
							break;
					}
					break;
				case "notations":
					ensureBeat();
					this._parseNotations(c, note, beat);
					break;
				case "lyric":
					ensureBeat();
					this._parseLyric(c, beat, track);
					break;
				case "play":
					this._parsePlay(c, note);
					break;
			}
			if (isPitched) {
				const staff = this._getOrCreateStaff(track, staffIndex);
				const transpose = this._getStaffContext(staff).transpose;
				if (transpose !== 0) {
					const value = note.octave * 12 + note.tone + transpose;
					note.octave = value / 12 | 0;
					note.tone = value - note.octave * 12;
				}
			}
			ensureBeat();
			if (note !== null) this._finalizeImportedNote(note, track, instrumentId, isPitched, noteIsVisible);
		}
		/**
		* Applies note-level post-processing that requires the fully resolved parse context.
		*
		* Purpose:
		* - Set final visibility.
		* - Resolve percussion articulation consistently in one place.
		*
		* Why this is called at the end of _parseNote:
		* - The logic relies on final note context (attached beat/voice/bar/staff), especially
		*   staff percussion state, and on the final display value after transposition.
		* - Running this earlier could use incomplete or wrong context and produce wrong
		*   articulation mapping.
		*/
		_finalizeImportedNote(note, track, instrumentId, isPitched, noteIsVisible) {
			note.isVisible = noteIsVisible;
			if (note.percussionArticulation >= 0) return;
			const trackInfo = this._indexToTrackInfo.get(track.index);
			if (instrumentId !== null) note.percussionArticulation = trackInfo.getOrCreateArticulation(instrumentId, note);
			else if (note.beat.voice.bar.staff.isPercussion && isPitched) {
				const knownArticulation = PercussionMapper.getArticulationById(note.displayValue);
				if (knownArticulation) note.percussionArticulation = knownArticulation.id;
			} else if (!isPitched) note.percussionArticulation = trackInfo.getOrCreateArticulation("", note);
		}
		_parsePlay(element, note) {
			for (const c of element.childElements()) switch (c.localName) {
				case "mute":
					if (note && c.innerText === "palm") note.isPalmMute = true;
					break;
				case "semi-pitched": break;
			}
		}
		static _b4Value = 71;
		_estimateBeamDirection(note) {
			return note.calculateRealValue(false, false) < MusicXmlImporter._b4Value ? BeamDirection.Down : BeamDirection.Up;
		}
		_parseNoteHead(element, note, beatDuration, beamDirection) {
			if (element.getAttribute("parentheses", "no") === "yes") note.isGhost = true;
			const filled = element.getAttribute("filled", "");
			let forceFill = void 0;
			if (filled === "yes") forceFill = true;
			else if (filled === "no") forceFill = false;
			note.style = new NoteStyle();
			switch (element.innerText) {
				case "arrow down":
					note.style.noteHeadCenterOnStem = true;
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadTriangleDownDoubleWhole, MusicFontSymbol.NoteheadTriangleDownWhole, MusicFontSymbol.NoteheadTriangleDownHalf, MusicFontSymbol.NoteheadTriangleDownBlack);
					break;
				case "arrow up":
					note.style.noteHeadCenterOnStem = true;
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadTriangleUpDoubleWhole, MusicFontSymbol.NoteheadTriangleUpWhole, MusicFontSymbol.NoteheadTriangleUpHalf, MusicFontSymbol.NoteheadTriangleUpBlack);
					break;
				case "back slashed":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadSlashedDoubleWhole2, MusicFontSymbol.NoteheadSlashedWhole2, MusicFontSymbol.NoteheadSlashedHalf2, MusicFontSymbol.NoteheadSlashedBlack2);
					break;
				case "circle dot":
					note.style.noteHead = MusicFontSymbol.NoteheadRoundWhiteWithDot;
					break;
				case "circle-x":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadCircleXDoubleWhole, MusicFontSymbol.NoteheadCircleXWhole, MusicFontSymbol.NoteheadCircleXHalf, MusicFontSymbol.NoteheadCircleX);
					break;
				case "circled":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadCircledDoubleWhole, MusicFontSymbol.NoteheadCircledWhole, MusicFontSymbol.NoteheadCircledHalf, MusicFontSymbol.NoteheadCircledBlack);
					break;
				case "cluster":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadClusterDoubleWhole3rd, MusicFontSymbol.NoteheadClusterWhole3rd, MusicFontSymbol.NoteheadClusterHalf3rd, MusicFontSymbol.NoteheadClusterQuarter3rd);
					break;
				case "cross":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadPlusDoubleWhole, MusicFontSymbol.NoteheadPlusWhole, MusicFontSymbol.NoteheadPlusHalf, MusicFontSymbol.NoteheadPlusBlack);
					break;
				case "diamond":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadDiamondDoubleWhole, MusicFontSymbol.NoteheadDiamondWhole, MusicFontSymbol.NoteheadDiamondHalf, MusicFontSymbol.NoteheadDiamondBlack);
					break;
				case "do":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeTriangleUpWhite, MusicFontSymbol.NoteShapeTriangleUpWhite, MusicFontSymbol.NoteShapeTriangleUpWhite, MusicFontSymbol.NoteShapeTriangleUpBlack);
					break;
				case "fa":
					if (beamDirection === BeamDirection.Up) this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeTriangleRightWhite, MusicFontSymbol.NoteShapeTriangleRightWhite, MusicFontSymbol.NoteShapeTriangleRightWhite, MusicFontSymbol.NoteShapeTriangleRightBlack);
					else this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeTriangleLeftWhite, MusicFontSymbol.NoteShapeTriangleLeftWhite, MusicFontSymbol.NoteShapeTriangleLeftWhite, MusicFontSymbol.NoteShapeTriangleLeftBlack);
					break;
				case "fa up":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeTriangleLeftWhite, MusicFontSymbol.NoteShapeTriangleLeftWhite, MusicFontSymbol.NoteShapeTriangleLeftWhite, MusicFontSymbol.NoteShapeTriangleLeftBlack);
					break;
				case "inverted triangle":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadTriangleDownDoubleWhole, MusicFontSymbol.NoteheadTriangleDownWhole, MusicFontSymbol.NoteheadTriangleDownHalf, MusicFontSymbol.NoteheadTriangleDownBlack);
					break;
				case "la":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeSquareWhite, MusicFontSymbol.NoteShapeSquareWhite, MusicFontSymbol.NoteShapeSquareWhite, MusicFontSymbol.NoteShapeSquareBlack);
					break;
				case "left triangle":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadTriangleRightWhite, MusicFontSymbol.NoteheadTriangleRightWhite, MusicFontSymbol.NoteheadTriangleRightWhite, MusicFontSymbol.NoteheadTriangleRightBlack);
					break;
				case "mi":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeDiamondWhite, MusicFontSymbol.NoteShapeDiamondWhite, MusicFontSymbol.NoteShapeDiamondWhite, MusicFontSymbol.NoteShapeDiamondBlack);
					break;
				case "none":
					note.style.noteHead = MusicFontSymbol.NoteheadNull;
					break;
				case "normal":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadDoubleWhole, MusicFontSymbol.NoteheadWhole, MusicFontSymbol.NoteheadHalf, MusicFontSymbol.NoteheadBlack);
					break;
				case "re":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeMoonWhite, MusicFontSymbol.NoteShapeMoonWhite, MusicFontSymbol.NoteShapeMoonWhite, MusicFontSymbol.NoteShapeMoonBlack);
					break;
				case "rectangle":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadSquareWhite, MusicFontSymbol.NoteheadSquareWhite, MusicFontSymbol.NoteheadSquareWhite, MusicFontSymbol.NoteheadSquareBlack);
					break;
				case "slash":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadSlashWhiteWhole, MusicFontSymbol.NoteheadSlashWhiteWhole, MusicFontSymbol.NoteheadSlashWhiteHalf, MusicFontSymbol.NoteheadSlashHorizontalEnds);
					break;
				case "slashed":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadSlashedDoubleWhole1, MusicFontSymbol.NoteheadSlashedWhole1, MusicFontSymbol.NoteheadSlashedHalf1, MusicFontSymbol.NoteheadSlashedBlack1);
					break;
				case "so":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeRoundWhite, MusicFontSymbol.NoteShapeRoundWhite, MusicFontSymbol.NoteShapeRoundWhite, MusicFontSymbol.NoteShapeRoundBlack);
					break;
				case "square":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeSquareWhite, MusicFontSymbol.NoteShapeSquareWhite, MusicFontSymbol.NoteShapeSquareWhite, MusicFontSymbol.NoteShapeSquareBlack);
					break;
				case "ti":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteShapeTriangleRoundWhite, MusicFontSymbol.NoteShapeTriangleRoundWhite, MusicFontSymbol.NoteShapeTriangleRoundWhite, MusicFontSymbol.NoteShapeTriangleRoundBlack);
					break;
				case "triangle":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadTriangleUpDoubleWhole, MusicFontSymbol.NoteheadTriangleUpWhole, MusicFontSymbol.NoteheadTriangleUpHalf, MusicFontSymbol.NoteheadTriangleUpBlack);
					break;
				case "x":
					this._applyNoteHead(note, beatDuration, forceFill, MusicFontSymbol.NoteheadXDoubleWhole, MusicFontSymbol.NoteheadXWhole, MusicFontSymbol.NoteheadXHalf, MusicFontSymbol.NoteheadXBlack);
					break;
			}
		}
		_createRestForGap(gap, preferredDuration) {
			let preferredDurationTicks = MidiUtils.toTicks(preferredDuration);
			while (preferredDurationTicks > gap) {
				if (preferredDuration === Duration.TwoHundredFiftySixth) return null;
				preferredDuration = preferredDuration * 2;
				preferredDurationTicks = MidiUtils.toTicks(preferredDuration);
			}
			const placeholder = new Beat();
			placeholder.dynamics = this._currentDynamics;
			placeholder.isEmpty = false;
			placeholder.duration = preferredDuration;
			placeholder.overrideDisplayDuration = preferredDurationTicks;
			placeholder.updateDurations();
			return placeholder;
		}
		_insertBeatToVoice(newBeat, voice) {
			if (voice.beats.length > 0) {
				const lastBeat = voice.beats[voice.beats.length - 1];
				lastBeat.nextBeat = newBeat;
				newBeat.previousBeat = lastBeat;
				let previousNonGraceBeat = lastBeat;
				while (previousNonGraceBeat !== null) {
					if (previousNonGraceBeat.graceType === GraceType.None) break;
					if (previousNonGraceBeat.index > 0) previousNonGraceBeat = previousNonGraceBeat.previousBeat;
					else previousNonGraceBeat = null;
				}
				if (previousNonGraceBeat !== null) newBeat.displayStart = previousNonGraceBeat.displayEnd;
			}
			voice.addBeat(newBeat);
		}
		_musicXmlDivisionsToAlphaTabTicks(divisions) {
			return divisions * MidiUtils.QuarterTime / this._divisionsPerQuarterNote;
		}
		_parseBeatDuration(element) {
			switch (element.innerText) {
				case "1024th": return Duration.TwoHundredFiftySixth;
				case "512th": return Duration.TwoHundredFiftySixth;
				case "256th": return Duration.TwoHundredFiftySixth;
				case "128th": return Duration.OneHundredTwentyEighth;
				case "64th": return Duration.SixtyFourth;
				case "32nd": return Duration.ThirtySecond;
				case "16th": return Duration.Sixteenth;
				case "eighth": return Duration.Eighth;
				case "quarter": return Duration.Quarter;
				case "half": return Duration.Half;
				case "whole": return Duration.Whole;
				case "breve": return Duration.DoubleWhole;
				case "long": return Duration.QuadrupleWhole;
			}
			return null;
		}
		static _allDurations = [
			Duration.TwoHundredFiftySixth,
			Duration.OneHundredTwentyEighth,
			Duration.SixtyFourth,
			Duration.ThirtySecond,
			Duration.Sixteenth,
			Duration.Eighth,
			Duration.Quarter,
			Duration.Half,
			Duration.Whole,
			Duration.DoubleWhole,
			Duration.QuadrupleWhole
		];
		static _allDurationTicks = MusicXmlImporter._allDurations.map((d) => MidiUtils.toTicks(d));
		_applyBeatDurationFromTicks(newBeat, ticks, beatDuration, applyDisplayDuration) {
			if (!beatDuration) for (let i = 0; i < MusicXmlImporter._allDurations.length; i++) if (ticks >= MusicXmlImporter._allDurationTicks[i]) beatDuration = MusicXmlImporter._allDurations[i];
			else break;
			newBeat.duration = beatDuration ?? Duration.Sixteenth;
			if (applyDisplayDuration) newBeat.overrideDisplayDuration = ticks;
			newBeat.updateDurations();
		}
		_parseLyric(element, beat, track) {
			const index = this._indexToTrackInfo.get(track.index).getLyricLine(element.getAttribute("number", ""));
			if (beat.lyrics === null) beat.lyrics = [];
			while (beat.lyrics.length <= index) beat.lyrics.push("");
			for (const c of element.childElements()) switch (c.localName) {
				case "text":
					if (beat.lyrics[index]) beat.lyrics[index] += ` ${c.innerText}`;
					else beat.lyrics[index] = c.innerText;
					break;
				case "elision":
					beat.lyrics[index] += c.innerText;
					break;
			}
		}
		_parseNotations(element, note, beat) {
			for (const c of element.childElements()) switch (c.localName) {
				case "tied":
					if (note) this._parseTied(c, note, beat.voice.bar.staff);
					break;
				case "slur":
					if (note) this._parseSlur(c, note);
					break;
				case "glissando":
					if (note) this._parseGlissando(c, note);
					break;
				case "slide":
					if (note) this._parseSlide(c, note);
					break;
				case "ornaments":
					if (note) this._parseOrnaments(c, note);
					break;
				case "technical":
					this._parseTechnical(c, note, beat);
					break;
				case "articulations":
					if (note) this._parseArticulations(c, note);
					break;
				case "dynamics":
					const dynamics = this._parseDynamics(c);
					if (dynamics !== null) {
						beat.dynamics = dynamics;
						this._currentDynamics = dynamics;
					}
					break;
				case "fermata":
					this._parseFermata(c, beat);
					break;
				case "arpeggiate":
					this._parseArpeggiate(c, beat);
					break;
			}
		}
		_getStaffContext(staff) {
			if (!this._staffToContext.has(staff)) {
				const context = new StaffContext();
				this._staffToContext.set(staff, context);
				return context;
			}
			return this._staffToContext.get(staff);
		}
		_parseGlissando(element, note) {
			const type = element.getAttribute("type");
			const number = element.getAttribute("number", "1");
			const context = this._getStaffContext(note.beat.voice.bar.staff);
			switch (type) {
				case "start":
					context.slideOrigins.set(number, note);
					break;
				case "stop":
					if (context.slideOrigins.has(number)) {
						const origin = context.slideOrigins.get(number);
						origin.slideTarget = note;
						note.slideOrigin = origin;
						origin.slideOutType = SlideOutType.Shift;
					}
					break;
			}
		}
		_parseSlur(element, note) {
			const slurNumber = element.getAttribute("number", "1");
			const context = this._getStaffContext(note.beat.voice.bar.staff);
			switch (element.getAttribute("type")) {
				case "start":
					context.slurStarts.set(slurNumber, note);
					break;
				case "stop":
					if (context.slurStarts.has(slurNumber)) {
						note.isSlurDestination = true;
						const slurStart = context.slurStarts.get(slurNumber);
						slurStart.slurDestination = note;
						note.slurOrigin = slurStart;
						context.slurStarts.delete(slurNumber);
					}
					break;
			}
		}
		_parseArpeggiate(element, beat) {
			switch (element.getAttribute("direction", "down")) {
				case "down":
					beat.brushType = BrushType.ArpeggioDown;
					break;
				case "up":
					beat.brushType = BrushType.ArpeggioUp;
					break;
			}
		}
		_parseFermata(element, beat) {
			let fermata;
			switch (element.innerText) {
				case "normal":
					fermata = FermataType.Medium;
					break;
				case "angled":
					fermata = FermataType.Short;
					break;
				case "square":
					fermata = FermataType.Long;
					break;
				default:
					fermata = FermataType.Medium;
					break;
			}
			beat.fermata = new Fermata();
			beat.fermata.type = fermata;
		}
		_parseArticulations(element, note) {
			for (const c of element.childElements()) switch (c.localName) {
				case "accent":
					note.accentuated = AccentuationType.Normal;
					break;
				case "strong-accent":
					note.accentuated = AccentuationType.Heavy;
					break;
				case "staccato":
					note.isStaccato = true;
					break;
				case "tenuto":
					note.accentuated = AccentuationType.Tenuto;
					break;
			}
		}
		_parseTechnical(element, note, beat) {
			const bends = [];
			for (const c of element.childElements()) switch (c.localName) {
				case "up-bow":
					beat.pickStroke = PickStroke.Up;
					break;
				case "down-bow":
					beat.pickStroke = PickStroke.Down;
					break;
				case "harmonic": break;
				case "fingering":
					if (note) note.leftHandFinger = this._parseFingering(c);
					break;
				case "pluck":
					if (note) note.rightHandFinger = this._parseFingering(c);
					break;
				case "fret":
					if (note) note.fret = Number.parseInt(c.innerText, 10);
					break;
				case "string":
					if (note) note.string = beat.voice.bar.staff.tuning.length - Number.parseInt(c.innerText, 10) + 1;
					break;
				case "hammer-on":
				case "pull-off":
					if (note) note.isHammerPullOrigin = true;
					break;
				case "bend":
					bends.push(c);
					break;
				case "tap":
					beat.tap = true;
					break;
				case "smear":
					if (note) note.vibrato = VibratoType.Slight;
					break;
				case "golpe":
					switch (c.getAttribute("placement", "above")) {
						case "above":
							beat.golpe = GolpeType.Finger;
							break;
						case "below":
							beat.golpe = GolpeType.Thumb;
							break;
					}
					break;
			}
			if (note && bends.length > 0) this._parseBends(bends, note);
		}
		_parseBends(elements, note) {
			const baseOffset = BendPoint.MaxPosition / elements.length;
			let currentValue = 0;
			let currentOffset = 0;
			let isFirstBend = true;
			for (const bend of elements) {
				const bendAlterElement = bend.findChildElement("bend-alter");
				if (bendAlterElement) {
					const absValue = Math.round(Math.abs(Number.parseFloat(bendAlterElement.innerText)) * 2);
					if (bend.findChildElement("pre-bend")) if (isFirstBend) {
						currentValue += absValue;
						note.addBendPoint(new BendPoint(currentOffset, currentValue));
						currentOffset += baseOffset;
						note.addBendPoint(new BendPoint(currentOffset, currentValue));
						isFirstBend = false;
					} else currentOffset += baseOffset;
					else if (bend.findChildElement("release")) {
						if (isFirstBend) currentValue += absValue;
						note.addBendPoint(new BendPoint(currentOffset, currentValue));
						currentOffset += baseOffset;
						currentValue -= absValue;
						note.addBendPoint(new BendPoint(currentOffset, currentValue));
						isFirstBend = false;
					} else {
						note.addBendPoint(new BendPoint(currentOffset, currentValue));
						currentValue += absValue;
						currentOffset += baseOffset;
						note.addBendPoint(new BendPoint(currentOffset, currentValue));
						isFirstBend = false;
					}
				}
			}
		}
		_parseFingering(c) {
			switch (c.innerText) {
				case "0": return Fingers.NoOrDead;
				case "1":
				case "p":
				case "t": return Fingers.Thumb;
				case "2":
				case "i": return Fingers.IndexFinger;
				case "3":
				case "m": return Fingers.MiddleFinger;
				case "4":
				case "a": return Fingers.AnnularFinger;
				case "5":
				case "c": return Fingers.LittleFinger;
			}
			return Fingers.Unknown;
		}
		_currentTrillStep = -1;
		_parseOrnaments(element, note) {
			let currentTrillStep = -1;
			for (const c of element.childElements()) switch (c.localName) {
				case "trill-mark":
					currentTrillStep = Number.parseInt(c.getAttribute("trill-step", "2"), 10);
					if (note.isStringed) note.trillValue = note.stringTuning + currentTrillStep;
					else if (!note.isPercussion) note.trillValue = note.calculateRealValue(false, false) + currentTrillStep;
					break;
				case "turn":
					note.ornament = NoteOrnament.Turn;
					break;
				case "inverted-turn":
					note.ornament = NoteOrnament.InvertedTurn;
					break;
				case "wavy-line":
					if (currentTrillStep > 0) {
						if (c.getAttribute("type") === "start") this._currentTrillStep = currentTrillStep;
					} else if (this._currentTrillStep > 0) {
						if (c.getAttribute("type") === "stop") this._currentTrillStep = -1;
						else if (note.isStringed) note.trillValue = note.stringTuning + this._currentTrillStep;
						else if (!note.isPercussion) note.trillValue = note.calculateRealValue(false, false) + this._currentTrillStep;
					} else note.vibrato = VibratoType.Slight;
					break;
				case "mordent":
					note.ornament = NoteOrnament.LowerMordent;
					break;
				case "inverted-mordent":
					note.ornament = NoteOrnament.UpperMordent;
					break;
				case "tremolo":
					const tremolo = new TremoloPickingEffect();
					note.beat.tremoloPicking = tremolo;
					tremolo.marks = Number.parseInt(c.innerText, 10);
					if (c.getAttribute("type", "") === "unmeasured" && tremolo.marks === 0 || c.getAttribute("smufl", "") === "buzzRoll") tremolo.style = TremoloPickingStyle.BuzzRoll;
					break;
			}
		}
		_parseSlide(element, note) {
			const type = element.getAttribute("type");
			const number = element.getAttribute("number", "1");
			const context = this._getStaffContext(note.beat.voice.bar.staff);
			switch (type) {
				case "start":
					context.slideOrigins.set(number, note);
					break;
				case "stop":
					if (context.slideOrigins.has(number)) {
						const origin = context.slideOrigins.get(number);
						origin.slideTarget = note;
						note.slideOrigin = origin;
						origin.slideOutType = SlideOutType.Shift;
					}
					break;
			}
		}
		_parseTied(element, note, staff) {
			const type = element.getAttribute("type");
			const number = element.getAttribute("number", "");
			const context = this._getStaffContext(staff);
			if (type === "start") {
				if (number) {
					if (context.tieStartIds.has(number)) {
						const unclosed = context.tieStartIds.get(number);
						context.tieStarts.delete(unclosed);
					}
					context.tieStartIds.set(number, note);
				}
				context.tieStarts.add(note);
			} else if (type === "stop" && !note.isTieDestination) {
				let tieOrigin = null;
				if (number) {
					if (!context.tieStartIds.has(number)) return;
					tieOrigin = context.tieStartIds.get(number);
					context.tieStartIds.delete(number);
					context.tieStarts.delete(note);
				} else {
					const realValue = this._calculatePitchedNoteValue(note);
					for (const t of context.tieStarts) if (this._calculatePitchedNoteValue(t) === realValue) {
						tieOrigin = t;
						context.tieStarts.delete(tieOrigin);
						break;
					}
				}
				if (!tieOrigin) return;
				note.isTieDestination = true;
				note.tieOrigin = tieOrigin;
			}
		}
		_parseStem(element) {
			switch (element.innerText) {
				case "down": return BeamDirection.Down;
				case "up": return BeamDirection.Up;
				default: return null;
			}
		}
		_parseAccidental(element, note) {
			switch (element.innerText) {
				case "sharp":
					note.accidentalMode = NoteAccidentalMode.ForceSharp;
					break;
				case "natural":
					note.accidentalMode = NoteAccidentalMode.ForceNatural;
					break;
				case "flat":
					note.accidentalMode = NoteAccidentalMode.ForceFlat;
					break;
				case "double-sharp":
					note.accidentalMode = NoteAccidentalMode.ForceDoubleSharp;
					break;
				case "flat-flat":
					note.accidentalMode = NoteAccidentalMode.ForceDoubleFlat;
					break;
			}
		}
		_calculatePitchedNoteValue(note) {
			return note.octave * 12 + note.tone;
		}
		_parseDuration(element) {
			return this._musicXmlDivisionsToAlphaTabTicks(Number.parseFloat(element.innerText));
		}
		_parseUnpitched(element, _track) {
			let step = "";
			let octave = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "display-step":
					step = c.innerText;
					break;
				case "display-octave":
					octave = Number.parseInt(c.innerText, 10) + 1;
					break;
			}
			const note = new Note();
			if (step === "") {
				note.octave = 0;
				note.tone = 0;
			} else {
				const value = octave * 12 + (ModelUtils.getToneForText(step)?.noteValue ?? 0);
				note.octave = value / 12 | 0;
				note.tone = value - note.octave * 12;
			}
			return note;
		}
		_parsePitch(element) {
			let step = "";
			let semitones = 0;
			let octave = 0;
			for (const c of element.childElements()) switch (c.localName) {
				case "step":
					step = c.innerText;
					break;
				case "alter":
					semitones = Number.parseFloat(c.innerText);
					if (Number.isNaN(semitones)) semitones = 0;
					break;
				case "octave":
					octave = Number.parseInt(c.innerText, 10) + 1;
					break;
			}
			semitones = semitones | 0;
			const value = octave * 12 + (ModelUtils.getToneForText(step)?.noteValue ?? 0) + semitones;
			const note = new Note();
			note.octave = value / 12 | 0;
			note.tone = value - note.octave * 12;
			return note;
		}
		_applyNoteHead(note, beatDuration, forceFill, doubleWhole, whole, half, filled) {
			if (forceFill === void 0) switch (beatDuration) {
				case Duration.QuadrupleWhole:
				case Duration.DoubleWhole:
					note.style.noteHead = doubleWhole;
					break;
				case Duration.Whole:
					note.style.noteHead = whole;
					break;
				case Duration.Half:
					note.style.noteHead = half;
					break;
				default:
					note.style.noteHead = filled;
					break;
			}
			else if (forceFill === true) note.style.noteHead = filled;
			else switch (beatDuration) {
				case Duration.QuadrupleWhole:
				case Duration.DoubleWhole:
					note.style.noteHead = doubleWhole;
					break;
				case Duration.Whole:
					note.style.noteHead = whole;
					break;
				case Duration.Half:
					note.style.noteHead = half;
					break;
				default:
					note.style.noteHead = half;
					break;
			}
		}
	};
	//#endregion
	//#region src/LayoutMode.ts
	/**
	* Lists all layout modes that are supported.
	* @public
	*/
	var LayoutMode = /* @__PURE__ */ 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)
		*
		* alphaTab holds following information in the data model and developers can change those values (e.g. by tapping into the `scoreLoaded`) event.
		* These widths are respected when using this layout.
		*
		* **Used when single tracks are rendered:**
		*
		* * `score.tracks[index].staves[index].bars[index].displayWidth` - The absolute size of this bar when displayed.
		*
		* **Used when multiple tracks are rendered:**
		*
		* * `score.masterBars[index].displayWidth` - Like the `displayWidth` on bar level.
		*/
		LayoutMode[LayoutMode["Horizontal"] = 1] = "Horizontal";
		/**
		* The bars are aligned in an [vertically endless page-style fashion](https://alphatab.net/docs/showcase/layouts#parchment)
		* respecting the configured systems layout.
		* 
		* The parchment layout uses the `systemsLayout` and `defaultSystemsLayout` to decide how many bars go into a single system (row).
		* Additionally when sizing the bars within the system the `displayScale` is used. This scale is rather a ratio than an absolute percentage value but percentages work also:
		*
		* ![Parchment Layout](https://alphatab.net/img/reference/property/systems-layout-page-examples.png)
		*
		* File formats like Guitar Pro embed information about the layout in the file and alphaTab can read and use this information.
		*
		* alphaTab holds following information in the data model and developers can change those values (e.g. by tapping into the `scoreLoaded`) event.
		*
		* **Used when single tracks are rendered:**
		*
		* * `score.tracks[index].systemsLayout` - An array of numbers describing how many bars should be placed within each system (row).
		* * `score.tracks[index].defaultSystemsLayout` - The number of bars to place in a system (row) when no value is defined in the `systemsLayout`.
		* * `score.tracks[index].staves[index].bars[index].displayScale` - The relative size of this bar in the system it is placed. Note that this is not directly a percentage value. e.g. if there are 3 bars and all define scale 1, they are sized evenly.
		*
		* **Used when multiple tracks are rendered:**
		*
		* * `score.systemsLayout` - Like the `systemsLayout` on track level.
		* * `score.defaultSystemsLayout` - Like the `defaultSystemsLayout` on track level.
		* * `score.masterBars[index].displayScale` - Like the `displayScale` on bar level.
		*/
		LayoutMode[LayoutMode["Parchment"] = 2] = "Parchment";
		return LayoutMode;
	}({});
	//#endregion
	//#region src/EventEmitter.ts
	/**
	* @internal
	*/
	var EventEmitter = class {
		_listeners = [];
		_fireOnRegister;
		constructor(fireOnRegister = void 0) {
			this._fireOnRegister = fireOnRegister;
		}
		on(value) {
			this._listeners.push(value);
			if (this._fireOnRegister?.()) value();
			return () => {
				this.off(value);
			};
		}
		off(value) {
			this._listeners = this._listeners.filter((l) => l !== value);
		}
		trigger() {
			for (const l of this._listeners) l();
		}
	};
	/**
	* @partial
	* @internal
	*/
	var EventEmitterOfT = class {
		_listeners = [];
		_fireOnRegister;
		constructor(fireOnRegister = void 0) {
			this._fireOnRegister = fireOnRegister;
		}
		on(value) {
			this._listeners.push(value);
			if (this._fireOnRegister) {
				const arg = this._fireOnRegister();
				if (arg !== null) value(arg);
			}
			return () => {
				this.off(value);
			};
		}
		off(value) {
			this._listeners = this._listeners.filter((l) => l !== value);
		}
		trigger(arg) {
			for (const l of this._listeners) l(arg);
		}
	};
	//#endregion
	//#region src/platform/javascript/AlphaSynthWebAudioOutputBase.ts
	/**
	* @target 
	* @internal
	*/
	var AlphaSynthWebAudioSynthOutputDevice = class {
		device;
		constructor(device) {
			this.device = device;
		}
		get deviceId() {
			return this.device.deviceId;
		}
		get label() {
			return this.device.label;
		}
		isDefault = false;
	};
	/**
	* Some shared web audio stuff.
	* @target web
	* @internal
	*/
	var WebAudioHelper = class WebAudioHelper {
		static _knownDevices = [];
		static findKnownDevice(sinkId) {
			return WebAudioHelper._knownDevices.find((d) => d.deviceId === sinkId);
		}
		static createAudioContext() {
			if ("AudioContext" in Environment.globalThis) return new AudioContext();
			if ("webkitAudioContext" in Environment.globalThis) return new webkitAudioContext();
			throw new AlphaTabError(AlphaTabErrorType.General, "AudioContext not found");
		}
		static async checkSinkIdSupport() {
			if (!("setSinkId" in WebAudioHelper.createAudioContext())) {
				Logger.warning("WebAudio", "Browser does not support changing the output device");
				return false;
			}
			return true;
		}
		static async enumerateOutputDevices() {
			try {
				if (!await WebAudioHelper.checkSinkIdSupport()) return [];
				try {
					await navigator.mediaDevices.getUserMedia({ audio: true });
				} catch (e) {
					Logger.warning("WebAudio", "Output device permission rejected", e);
				}
				const devices = await navigator.mediaDevices.enumerateDevices();
				let defaultDeviceGroupId = "";
				let defaultDeviceId = "";
				const realDevices = /* @__PURE__ */ new Map();
				for (const device of devices) if (device.kind === "audiooutput") {
					realDevices.set(device.groupId, new AlphaSynthWebAudioSynthOutputDevice(device));
					if (device.deviceId === "default" || device.deviceId === "") {
						defaultDeviceGroupId = device.groupId;
						defaultDeviceId = device.deviceId;
					}
				}
				const final = Array.from(realDevices.values());
				let defaultDevice = final.find((d) => d.deviceId === defaultDeviceId);
				if (!defaultDevice) defaultDevice = final.find((d) => d.device.groupId === defaultDeviceGroupId);
				if (!defaultDevice && final.length > 0) defaultDevice = final[0];
				if (defaultDevice) defaultDevice.isDefault = true;
				WebAudioHelper._knownDevices = final;
				return final;
			} catch (e) {
				Logger.error("WebAudio", "Failed to enumerate output devices", e);
				return [];
			}
		}
	};
	/**
	* @target web
	* @internal
	*/
	var AlphaSynthWebAudioOutputBase = class AlphaSynthWebAudioOutputBase {
		static BufferSize = 4096;
		static PreferredSampleRate = 44100;
		context = null;
		buffer = null;
		source = null;
		_resumeHandler;
		get sampleRate() {
			return this.context ? this.context.sampleRate : AlphaSynthWebAudioOutputBase.PreferredSampleRate;
		}
		activate(resumedCallback) {
			if (!this.context) this.context = WebAudioHelper.createAudioContext();
			if (this.context.state === "suspended" || this.context.state === "interrupted") {
				Logger.debug("WebAudio", "Audio Context is suspended, trying resume");
				this.context.resume().then(() => {
					Logger.debug("WebAudio", `Audio Context resume success: state=${this.context?.state}, sampleRate:${this.context?.sampleRate}`);
					if (resumedCallback) resumedCallback();
				}, (reason) => {
					Logger.warning("WebAudio", `Audio Context resume failed: state=${this.context?.state}, sampleRate:${this.context?.sampleRate}, reason=${reason}`);
				});
			}
		}
		_patchIosSampleRate() {
			const ua = navigator.userAgent;
			if (ua.indexOf("iPhone") !== -1 || ua.indexOf("iPad") !== -1) {
				const context = WebAudioHelper.createAudioContext();
				const buffer = context.createBuffer(1, 1, AlphaSynthWebAudioOutputBase.PreferredSampleRate);
				const dummy = context.createBufferSource();
				dummy.buffer = buffer;
				dummy.connect(context.destination);
				dummy.start(0);
				dummy.disconnect(0);
				context.close();
			}
		}
		open(_bufferTimeInMilliseconds) {
			this._patchIosSampleRate();
			this.context = WebAudioHelper.createAudioContext();
			if (this.context.state === "suspended") this._registerResumeHandler();
		}
		_registerResumeHandler() {
			this._resumeHandler = (() => {
				this.activate(() => {
					this._unregisterResumeHandler();
				});
			}).bind(this);
			document.body.addEventListener("touchend", this._resumeHandler, false);
			document.body.addEventListener("click", this._resumeHandler, false);
		}
		_unregisterResumeHandler() {
			const resumeHandler = this._resumeHandler;
			if (resumeHandler) {
				document.body.removeEventListener("touchend", resumeHandler, false);
				document.body.removeEventListener("click", resumeHandler, false);
			}
		}
		play() {
			const ctx = this.context;
			this.activate();
			this.buffer = ctx.createBuffer(2, AlphaSynthWebAudioOutputBase.BufferSize, ctx.sampleRate);
			this.source = ctx.createBufferSource();
			this.source.buffer = this.buffer;
			this.source.loop = true;
		}
		pause() {
			if (this.source) {
				this.source.stop(0);
				this.source.disconnect();
			}
			this.source = null;
		}
		destroy() {
			this.pause();
			this.context?.close();
			this.context = null;
			this._unregisterResumeHandler();
		}
		ready = new EventEmitter();
		samplesPlayed = new EventEmitterOfT();
		sampleRequest = new EventEmitter();
		onSamplesPlayed(numberOfSamples) {
			this.samplesPlayed.trigger(numberOfSamples);
		}
		onSampleRequest() {
			this.sampleRequest.trigger();
		}
		onReady() {
			this.ready.trigger();
		}
		enumerateOutputDevices() {
			return WebAudioHelper.enumerateOutputDevices();
		}
		async setOutputDevice(device) {
			if (!await WebAudioHelper.checkSinkIdSupport()) return;
			if (!device) await this.context.setSinkId("");
			else await this.context.setSinkId(device.deviceId);
		}
		async getOutputDevice() {
			if (!await WebAudioHelper.checkSinkIdSupport()) return null;
			const sinkId = this.context.sinkId;
			if (typeof sinkId !== "string" || sinkId === "" || sinkId === "default") return null;
			let device = WebAudioHelper.findKnownDevice(sinkId);
			if (device) return device;
			const allDevices = await this.enumerateOutputDevices();
			device = allDevices.find((d) => d.deviceId === sinkId);
			if (device) return device;
			Logger.warning("WebAudio", "Could not find output device in device list", sinkId, allDevices);
			return null;
		}
	};
	//#endregion
	//#region src/FileLoadError.ts
	/**
	* @target web
	* @public
	*/
	var FileLoadError = class extends AlphaTabError {
		xhr;
		constructor(message, xhr) {
			super(AlphaTabErrorType.General, message);
			this.xhr = xhr;
		}
	};
	//#endregion
	//#region src/generated/EngravingSettingsCloner.ts
	/**
	* @internal
	*/
	var EngravingSettingsCloner = class {
		static clone(original) {
			const clone = new EngravingSettings();
			clone.musicFontSize = original.musicFontSize;
			clone.oneStaffSpace = original.oneStaffSpace;
			clone.tabLineSpacing = original.tabLineSpacing;
			clone.arrowShaftThickness = original.arrowShaftThickness;
			clone.barlineSeparation = original.barlineSeparation;
			clone.beamSpacing = original.beamSpacing;
			clone.beamThickness = original.beamThickness;
			clone.bracketThickness = original.bracketThickness;
			clone.dashedBarlineDashLength = original.dashedBarlineDashLength;
			clone.dashedBarlineGapLength = original.dashedBarlineGapLength;
			clone.dashedBarlineThickness = original.dashedBarlineThickness;
			clone.hairpinThickness = original.hairpinThickness;
			clone.legerLineThickness = original.legerLineThickness;
			clone.legerLineExtension = original.legerLineExtension;
			clone.octaveLineThickness = original.octaveLineThickness;
			clone.pedalLineThickness = original.pedalLineThickness;
			clone.repeatBarlineDotSeparation = original.repeatBarlineDotSeparation;
			clone.repeatEndingLineThickness = original.repeatEndingLineThickness;
			clone.slurMidpointThickness = original.slurMidpointThickness;
			clone.staffLineThickness = original.staffLineThickness;
			clone.stemThickness = original.stemThickness;
			clone.thickBarlineThickness = original.thickBarlineThickness;
			clone.thinBarlineThickness = original.thinBarlineThickness;
			clone.thinThickBarlineSeparation = original.thinThickBarlineSeparation;
			clone.tieMidpointThickness = original.tieMidpointThickness;
			clone.tupletBracketThickness = original.tupletBracketThickness;
			clone.stemUp = new Map(original.stemUp);
			clone.stemDown = new Map(original.stemDown);
			clone.repeatOffsetX = new Map(original.repeatOffsetX);
			clone.standardStemLength = original.standardStemLength;
			clone.stemFlagOffsets = new Map(original.stemFlagOffsets);
			clone.glyphTop = new Map(original.glyphTop);
			clone.glyphBottom = new Map(original.glyphBottom);
			clone.glyphWidths = new Map(original.glyphWidths);
			clone.glyphHeights = new Map(original.glyphHeights);
			clone.numberedBarRendererBarSize = original.numberedBarRendererBarSize;
			clone.numberedBarRendererBarSpacing = original.numberedBarRendererBarSpacing;
			clone.numberedDashGlyphPadding = original.numberedDashGlyphPadding;
			clone.numberedDashGlyphWidth = original.numberedDashGlyphWidth;
			clone.lineRangedGlyphDashGap = original.lineRangedGlyphDashGap;
			clone.lineRangedGlyphDashSize = original.lineRangedGlyphDashSize;
			clone.preNoteEffectPadding = original.preNoteEffectPadding;
			clone.postNoteEffectPadding = original.postNoteEffectPadding;
			clone.onNoteEffectPadding = original.onNoteEffectPadding;
			clone.stringNumberCirclePadding = original.stringNumberCirclePadding;
			clone.rowContainerPadding = original.rowContainerPadding;
			clone.rowContainerGap = original.rowContainerGap;
			clone.alternateEndingsPadding = original.alternateEndingsPadding;
			clone.sustainPedalLinePadding = original.sustainPedalLinePadding;
			clone.tieHeight = original.tieHeight;
			clone.beatTimerPadding = original.beatTimerPadding;
			clone.bendNoteHeadElementPadding = original.bendNoteHeadElementPadding;
			clone.ghostParenthesisWidth = original.ghostParenthesisWidth;
			clone.ghostParenthesisPadding = original.ghostParenthesisPadding;
			clone.brokenBeamWidth = original.brokenBeamWidth;
			clone.tabWhammyTextPadding = original.tabWhammyTextPadding;
			clone.tabWhammyPerHalfHeight = original.tabWhammyPerHalfHeight;
			clone.tabWhammyDashSize = original.tabWhammyDashSize;
			clone.songBookWhammyDipHeight = original.songBookWhammyDipHeight;
			clone.deadSlappedLineWidth = original.deadSlappedLineWidth;
			clone.leftHandTabTieWidth = original.leftHandTabTieWidth;
			clone.tabBendDashSize = original.tabBendDashSize;
			clone.tabBendStaffPadding = original.tabBendStaffPadding;
			clone.tabBendPerValueHeight = original.tabBendPerValueHeight;
			clone.tabBendLabelPadding = original.tabBendLabelPadding;
			clone.simpleSlideWidth = original.simpleSlideWidth;
			clone.simpleSlideHeight = original.simpleSlideHeight;
			clone.chordDiagramPaddingX = original.chordDiagramPaddingX;
			clone.chordDiagramPaddingY = original.chordDiagramPaddingY;
			clone.chordDiagramStringSpacing = original.chordDiagramStringSpacing;
			clone.chordDiagramFretSpacing = original.chordDiagramFretSpacing;
			clone.chordDiagramNutHeight = original.chordDiagramNutHeight;
			clone.chordDiagramFretHeight = original.chordDiagramFretHeight;
			clone.chordDiagramLineWidth = original.chordDiagramLineWidth;
			clone.tripletFeelBracketPadding = original.tripletFeelBracketPadding;
			clone.accidentalPadding = original.accidentalPadding;
			clone.preBeatGlyphSpacing = original.preBeatGlyphSpacing;
			clone.tempoNoteScale = original.tempoNoteScale;
			clone.tuningGlyphCircleNumberScale = original.tuningGlyphCircleNumberScale;
			clone.tuningGlyphStringColumnScale = original.tuningGlyphStringColumnScale;
			clone.tuningGlyphStringRowPadding = original.tuningGlyphStringRowPadding;
			clone.directionsScale = original.directionsScale;
			clone.multiVoiceDisplacedNoteHeadSpacing = original.multiVoiceDisplacedNoteHeadSpacing;
			clone.stemFlagHeight = new Map(original.stemFlagHeight);
			return clone;
		}
	};
	//#endregion
	//#region src/io/JsonHelper.ts
	/**
	* @partial
	* @internal
	*/
	var JsonHelper = class {
		/**
		* @target web
		* @partial
		*/
		static parseEnum(s, enumType) {
			switch (typeof s) {
				case "string":
					const num = Number.parseInt(s, 10);
					return Number.isNaN(num) ? enumType[Object.keys(enumType).find((k) => k.toLowerCase() === s.toLowerCase())] : num;
				case "number": return s;
				case "undefined":
				case "object": return;
			}
			throw new AlphaTabError(AlphaTabErrorType.Format, `Could not parse enum value '${s}'`);
		}
		/**
		* @target web
		* @partial
		*/
		static parseEnumExact(s, enumType) {
			if (s in enumType) return enumType[s];
		}
		/**
		* @target web
		* @partial
		*/
		static forEach(s, func) {
			if (s instanceof Map) s.forEach(func);
			else if (typeof s === "object") for (const k in s) func(s[k], k);
		}
		/**
		* @target web
		* @partial
		*/
		static getValue(s, key) {
			if (s instanceof Map) return s.get(key);
			if (typeof s === "object") return s[key];
			return null;
		}
	};
	//#endregion
	//#region src/EngravingSettings.ts
	/**
	* @json
	* @json_declaration
	* @public
	*/
	var EngravingStemInfo = class {
		/**
		* The top Y coordinate where the stem should start/end.
		*/
		topY = 0;
		/**
		* The bottom Y coordinate where the stem should start/end.
		*/
		bottomY = 0;
		/**
		* The x-coordinate of the stem.
		*/
		x = 0;
	};
	/**
	* This class holds all all spacing, thickness and scaling metrics
	* related to engraving the music notation.
	*
	* @remarks
	* While general layout settings are configurable via the display settings,
	* these settings go deeper into how the individual music symbols are scaled and aligned targeting
	* specification compliance with the Standard Music Font Layout (SMuFL).
	*
	* Unless specified differently the settings here are available {@since 1.7.0}
	*
	* If properties are marked with a SMuFl tag, it means that the values are part of the SMuFL specification
	* and should be filled from the respective metadata files shipped with the fonts or aligned generally with the specification.
	* Other properties are custom to alphaTab.
	*
	* In SmuFL Sizes and coordinates are expressed in "staff space" units which is 1/4 of the configured font size. In this data structure
	* the values are converted to pixels.
	*
	* @json
	* @json_declaration
	* @cloneable
	* @public
	*/
	var EngravingSettings = class EngravingSettings {
		static _bravuraDefaults;
		/**
		* @internal
		*/
		static GraceScale = .75;
		/**
		* A {@link EngravingSettings} copy filled with the settings of the Bravura font used by default in alphaTab.
		*/
		static get bravuraDefaults() {
			let bravuraDefaults = EngravingSettings._bravuraDefaults;
			if (!bravuraDefaults) {
				bravuraDefaults = new EngravingSettings();
				bravuraDefaults.fillFromSmufl(EngravingSettings.bravuraMetadata);
				EngravingSettings._bravuraDefaults = bravuraDefaults;
			}
			return EngravingSettingsCloner.clone(bravuraDefaults);
		}
		/**
		* The font size of the music font in pixel.
		*/
		musicFontSize = 0;
		/**
		* The staff space in pixel
		* @smufl 1.4
		*/
		oneStaffSpace = 0;
		/**
		* The staff space in pixel for tablature fonts. This is typically 1.5 of the standard staff space.
		* @smufl 1.4
		*/
		tabLineSpacing = 0;
		/**
		* The thickness of the line used for the shaft of an arrow
		* @smufl 1.4
		*/
		arrowShaftThickness = 0;
		/**
		* The default distance between multiple thin barlines when locked together, e.g. between two thin barlines making a double barline, measured from the right-hand edge of the left barline to the left-hand edge of the right barline.
		* @smufl 1.4
		*/
		barlineSeparation = 0;
		/**
		* The distance between the inner edge of the primary and outer edge of subsequent secondary beams
		* @smufl 1.4
		*/
		beamSpacing = 0;
		/**
		* The thickness of a beam
		* @smufl 1.4
		*/
		beamThickness = 0;
		/**
		* The thickness of the vertical line of a bracket grouping staves together
		* @smufl 1.4
		*/
		bracketThickness = 0;
		/**
		* The length of the dashes to be used in a dashed barline
		* @smufl 1.4
		*/
		dashedBarlineDashLength = 0;
		/**
		* The length of the gap between dashes in a dashed barline
		*/
		dashedBarlineGapLength = 0;
		/**
		* The thickness of a dashed barline
		* @smufl 1.4
		*/
		dashedBarlineThickness = 0;
		/**
		* The thickness of a crescendo/diminuendo hairpin
		* @smufl 1.4
		*/
		hairpinThickness = 0;
		/**
		* The thickness of a leger line (normally somewhat thicker than a staff line)
		* @smufl 1.4
		*/
		legerLineThickness = 0;
		/**
		* The amount by which a leger line should extend either side of a notehead, scaled proportionally with the notehead's size, e.g. when scaled down as a grace note
		* @smufl 1.4
		*/
		legerLineExtension = 0;
		/**
		* The thickness of the dashed line used for an octave line
		* @smufl 1.4
		*/
		octaveLineThickness = 0;
		/**
		* The thickness of the line used for piano pedaling
		* @smufl 1.4
		*/
		pedalLineThickness = 0;
		/**
		* The default horizontal distance between the dots and the inner barline of a repeat barline, measured from the edge of the dots to the edge of the barline.
		* @smufl 1.4
		*/
		repeatBarlineDotSeparation = 0;
		/**
		* The thickness of the brackets drawn to indicate repeat endings
		* @smufl 1.4
		*/
		repeatEndingLineThickness = 0;
		/**
		* The thickness of the mid-point of a slur (i.e. its thickest point)
		* @smufl 1.4
		*/
		slurMidpointThickness = 0;
		/**
		* The thickness of each staff line
		* @smufl 1.4
		*/
		staffLineThickness = 0;
		/**
		* The thickness of a stem
		* @smufl 1.4
		*/
		stemThickness = 0;
		/**
		* The thickness of a thick barline, e.g. in a final barline or a repeat barline
		* @smufl 1.4
		*/
		thickBarlineThickness = 0;
		/**
		* The thickness of a dashed barline
		* @smufl 1.4
		*/
		thinBarlineThickness = 0;
		/**
		* The default distance between a pair of thin and thick barlines when locked together, e.g. between the thin and thick barlines making a final barline, or between the thick and thin barlines making a start repeat barline.
		* @smufl 1.4
		*/
		thinThickBarlineSeparation = 0;
		/**
		* The thickness of the mid-point of a tie
		* @smufl 1.4
		*/
		tieMidpointThickness = 0;
		/**
		* The thickness of the brackets drawn either side of tuplet numbers
		* @smufl 1.4
		*/
		tupletBracketThickness = 0;
		/**
		* Holds information about where to place upwards pointing stems on glyphs.
		* @smufl 1.4
		*/
		stemUp = /* @__PURE__ */ new Map();
		/**
		* Holds information about where to place downwards pointing stems on glyphs.
		* @smufl 1.4
		*/
		stemDown = /* @__PURE__ */ new Map();
		/**
		* Holds the x-coordinate offsets for glyphs which are drawn repeatedly (like vibrato waves).
		* @smufl 1.4
		*/
		repeatOffsetX = /* @__PURE__ */ new Map();
		/**
		* The standard stem length of a quarter note.
		* @smufl 1.4
		*/
		standardStemLength = 0;
		/**
		* The additional offsets stems need to have enough space for flags.
		* @smufl 1.4
		*/
		stemFlagOffsets = /* @__PURE__ */ new Map();
		/**
		* A lookup containing the offset from the visual top to the glyph center.
		* The glyph center is the origin coordinate at which the glyph paths start when drawn on the alphabetic baseline.
		* @smufl 1.4
		*/
		glyphTop = /* @__PURE__ */ new Map();
		/**
		* A lookup containing the offset from the glyph center to the visual bottom of the glyph.
		* The glyph center is the origin coordinate at which the glyph paths start when drawn on the alphabetic baseline.
		* @smufl 1.4
		*/
		glyphBottom = /* @__PURE__ */ new Map();
		/**
		* A lookup for the widths of the visual bounding box for the glyphs.
		* @smufl 1.4
		*/
		glyphWidths = /* @__PURE__ */ new Map();
		/**
		* A lookup for the heights of the visual bounding box for the glyphs.
		* @smufl 1.4
		*/
		glyphHeights = /* @__PURE__ */ new Map();
		/**
		* Checks whether a certain glyph is registered in the currently loaded engraving settings.
		* @param symbol The symbol to check
		* @returns true if the glyph is registered and available for use.
		* @internal
		*/
		hasSymbol(symbol) {
			return this.glyphWidths.get(symbol) > 0 && this.glyphHeights.get(symbol) > 0;
		}
		/**
		* Fills the engraving settings from the provided smufl metdata.
		* @param smufl The metadata shipped together with the SMuFL fonts.
		* @param musicFontSize The font size to configure in alphaTab for the music font.
		*/
		fillFromSmufl(smufl, musicFontSize = 36) {
			this.musicFontSize = musicFontSize;
			this.oneStaffSpace = musicFontSize / 4;
			this.tabLineSpacing = Math.floor(this.oneStaffSpace * 1.5);
			this.arrowShaftThickness = smufl.engravingDefaults.arrowShaftThickness * this.oneStaffSpace;
			this.barlineSeparation = smufl.engravingDefaults.barlineSeparation * this.oneStaffSpace;
			this.beamSpacing = smufl.engravingDefaults.beamSpacing * this.oneStaffSpace;
			this.beamThickness = smufl.engravingDefaults.beamThickness * this.oneStaffSpace;
			this.bracketThickness = smufl.engravingDefaults.bracketThickness * this.oneStaffSpace;
			this.dashedBarlineDashLength = smufl.engravingDefaults.dashedBarlineDashLength * this.oneStaffSpace;
			this.dashedBarlineGapLength = smufl.engravingDefaults.dashedBarlineGapLength * this.oneStaffSpace;
			this.dashedBarlineThickness = smufl.engravingDefaults.dashedBarlineThickness * this.oneStaffSpace;
			this.hairpinThickness = smufl.engravingDefaults.hairpinThickness * this.oneStaffSpace;
			this.legerLineExtension = smufl.engravingDefaults.legerLineExtension * this.oneStaffSpace;
			this.legerLineThickness = smufl.engravingDefaults.legerLineThickness * this.oneStaffSpace;
			this.octaveLineThickness = smufl.engravingDefaults.octaveLineThickness * this.oneStaffSpace;
			this.pedalLineThickness = smufl.engravingDefaults.pedalLineThickness * this.oneStaffSpace;
			this.repeatBarlineDotSeparation = smufl.engravingDefaults.repeatBarlineDotSeparation * this.oneStaffSpace;
			this.repeatEndingLineThickness = smufl.engravingDefaults.repeatEndingLineThickness * this.oneStaffSpace;
			this.slurMidpointThickness = smufl.engravingDefaults.slurMidpointThickness * this.oneStaffSpace;
			this.staffLineThickness = smufl.engravingDefaults.staffLineThickness * this.oneStaffSpace;
			this.stemThickness = smufl.engravingDefaults.stemThickness * this.oneStaffSpace;
			this.thickBarlineThickness = smufl.engravingDefaults.thickBarlineThickness * this.oneStaffSpace;
			this.thinBarlineThickness = smufl.engravingDefaults.thinBarlineThickness * this.oneStaffSpace;
			if (typeof smufl.engravingDefaults.thinThickBarlineSeparation === "number") this.thinThickBarlineSeparation = smufl.engravingDefaults.thinThickBarlineSeparation * this.oneStaffSpace;
			else this.thinThickBarlineSeparation = smufl.engravingDefaults.barlineSeparation * this.oneStaffSpace;
			this.tieMidpointThickness = smufl.engravingDefaults.tieMidpointThickness * this.oneStaffSpace;
			this.tupletBracketThickness = smufl.engravingDefaults.tupletBracketThickness * this.oneStaffSpace;
			const standardStemLength = 3 * this.oneStaffSpace;
			this.standardStemLength = standardStemLength;
			this.stemFlagOffsets.set(Duration.QuadrupleWhole, 0);
			this.stemFlagOffsets.set(Duration.DoubleWhole, 0);
			this.stemFlagOffsets.set(Duration.Whole, 0);
			this.stemFlagOffsets.set(Duration.Half, 0);
			this.stemFlagOffsets.set(Duration.Quarter, 0);
			this.stemFlagOffsets.set(Duration.Eighth, 0);
			this.stemFlagOffsets.set(Duration.Sixteenth, 0);
			this.stemFlagOffsets.set(Duration.ThirtySecond, 0);
			this.stemFlagOffsets.set(Duration.SixtyFourth, 0);
			this.stemFlagOffsets.set(Duration.OneHundredTwentyEighth, 0);
			this.stemFlagOffsets.set(Duration.TwoHundredFiftySixth, 0);
			this.stemFlagHeight.set(Duration.QuadrupleWhole, 0);
			this.stemFlagHeight.set(Duration.DoubleWhole, 0);
			this.stemFlagHeight.set(Duration.Whole, 0);
			this.stemFlagHeight.set(Duration.Half, 0);
			this.stemFlagHeight.set(Duration.Quarter, 0);
			this.stemFlagHeight.set(Duration.Eighth, 1 * this.oneStaffSpace);
			this.stemFlagHeight.set(Duration.Sixteenth, 1.5 * this.oneStaffSpace);
			this.stemFlagHeight.set(Duration.ThirtySecond, 2 * this.oneStaffSpace);
			this.stemFlagHeight.set(Duration.SixtyFourth, 3 * this.oneStaffSpace);
			this.stemFlagHeight.set(Duration.OneHundredTwentyEighth, 3.5 * this.oneStaffSpace);
			this.stemFlagHeight.set(Duration.TwoHundredFiftySixth, 4.2 * this.oneStaffSpace);
			for (const [g, v] of Object.entries(smufl.glyphsWithAnchors)) {
				const symbol = EngravingSettings._smuflNameToMusicFontSymbol(g);
				if (symbol) {
					if (v.stemDownNW) {
						const b = new EngravingStemInfo();
						b.x = v.stemDownNW[0] * this.oneStaffSpace;
						b.topY = v.stemDownNW[1] * this.oneStaffSpace;
						if (v.stemDownSW) b.bottomY = v.stemDownSW[1] * this.oneStaffSpace;
						else b.bottomY = 0;
						this.stemDown.set(symbol, b);
					}
					if (v.stemUpSE) {
						const b = new EngravingStemInfo();
						const bottomX = v.stemUpSE[0] * this.oneStaffSpace;
						b.bottomY = v.stemUpSE[1] * this.oneStaffSpace;
						if (v.stemUpNW) {
							b.x = v.stemUpNW[0] * this.oneStaffSpace;
							b.topY = v.stemUpNW[1] * this.oneStaffSpace;
						} else {
							b.x = bottomX - this.stemThickness;
							b.topY = 0;
						}
						this.stemUp.set(symbol, b);
					}
					if (v.repeatOffset) this.repeatOffsetX.set(symbol, v.repeatOffset[0] * this.oneStaffSpace);
					if (v.stemUpNW) {
						const stemLength = v.stemUpNW[1] * this.oneStaffSpace;
						switch (symbol) {
							case MusicFontSymbol.Flag8thUp:
								this.stemFlagOffsets.set(Duration.Eighth, stemLength);
								break;
							case MusicFontSymbol.Flag16thUp:
								this.stemFlagOffsets.set(Duration.Sixteenth, stemLength);
								break;
							case MusicFontSymbol.Flag32ndUp:
								this.stemFlagOffsets.set(Duration.ThirtySecond, stemLength);
								break;
							case MusicFontSymbol.Flag64thUp:
								this.stemFlagOffsets.set(Duration.SixtyFourth, stemLength);
								break;
							case MusicFontSymbol.Flag128thUp:
								this.stemFlagOffsets.set(Duration.OneHundredTwentyEighth, stemLength);
								break;
							case MusicFontSymbol.Flag256thUp:
								this.stemFlagOffsets.set(Duration.TwoHundredFiftySixth, stemLength);
								break;
						}
					}
				}
			}
			const handledSymbols = /* @__PURE__ */ new Set();
			const bBoxes = smufl.glyphBBoxes;
			if (bBoxes) for (const [g, v] of Object.entries(bBoxes)) {
				const symbol = EngravingSettings._smuflNameToMusicFontSymbol(g);
				if (symbol) {
					handledSymbols.add(symbol);
					this.glyphTop.set(symbol, v.bBoxNE[1] * this.oneStaffSpace);
					this.glyphBottom.set(symbol, v.bBoxSW[1] * this.oneStaffSpace);
					this.glyphWidths.set(symbol, (v.bBoxNE[0] - v.bBoxSW[0]) * this.oneStaffSpace);
					this.glyphHeights.set(symbol, (v.bBoxNE[1] - v.bBoxSW[1]) * this.oneStaffSpace);
				}
			}
			const ignoredSymbols = new Set([
				MusicFontSymbol.None,
				MusicFontSymbol.Space,
				MusicFontSymbol.NoteheadNull
			]);
			for (const symbol of MusicFontSymbolLookup.getAllMusicFontSymbols()) if (!handledSymbols.has(symbol)) {
				if (!ignoredSymbols.has(symbol)) Logger.warning("SmuFL", `The provided SmuFL font is missing the glyph ${MusicFontSymbol[symbol]} needed by alphaTab, the music notation might not show all details`);
				this.glyphTop.set(symbol, 0);
				this.glyphBottom.set(symbol, 0);
				this.glyphWidths.set(symbol, 0);
				this.glyphHeights.set(symbol, 0);
			}
			this.numberedBarRendererBarSize = this.staffLineThickness * 2;
			this.numberedBarRendererBarSpacing = this.beamSpacing;
			this.preNoteEffectPadding = .4 * this.oneStaffSpace;
			this.postNoteEffectPadding = .2 * this.oneStaffSpace;
			this.lineRangedGlyphDashGap = .5 * this.oneStaffSpace;
			this.lineRangedGlyphDashSize = 1 * this.oneStaffSpace;
			this.numberedDashGlyphPadding = .3 * this.oneStaffSpace;
			this.numberedDashGlyphPadding = .3 * this.oneStaffSpace;
			this.stringNumberCirclePadding = .3 * this.oneStaffSpace;
			this.rowContainerPadding = Math.ceil(.3 * this.oneStaffSpace);
			this.rowContainerGap = Math.ceil(1 * this.oneStaffSpace);
			this.onNoteEffectPadding = .2 * this.oneStaffSpace;
			this.alternateEndingsPadding = .3 * this.oneStaffSpace;
			this.sustainPedalLinePadding = .5 * this.oneStaffSpace;
			this.tieHeight = 1.2 * this.oneStaffSpace;
			this.beatTimerPadding = .22 * this.oneStaffSpace;
			this.bendNoteHeadElementPadding = .22 * this.oneStaffSpace;
			this.ghostParenthesisWidth = .6 * this.oneStaffSpace;
			this.ghostParenthesisPadding = .3 * this.oneStaffSpace;
			this.brokenBeamWidth = 1 * this.oneStaffSpace;
			this.tabWhammyTextPadding = .4 * this.oneStaffSpace;
			this.tabWhammyDashSize = .4 * this.oneStaffSpace;
			this.tabBendDashSize = .4 * this.oneStaffSpace;
			this.songBookWhammyDipHeight = .6 * this.oneStaffSpace;
			this.tabWhammyPerHalfHeight = .6 * this.oneStaffSpace;
			this.tabBendStaffPadding = .5 * this.oneStaffSpace;
			this.tabBendPerValueHeight = .6 * this.oneStaffSpace;
			this.tabBendLabelPadding = .3 * this.oneStaffSpace;
			this.leftHandTabTieWidth = 2.2 * this.oneStaffSpace;
			this.numberedDashGlyphWidth = 1.5 * this.oneStaffSpace;
			this.deadSlappedLineWidth = .25 * this.oneStaffSpace;
			this.simpleSlideWidth = 1.3 * this.oneStaffSpace;
			this.simpleSlideHeight = .3 * this.oneStaffSpace;
			this.chordDiagramPaddingX = Math.ceil(.5 * this.oneStaffSpace);
			this.chordDiagramPaddingY = Math.ceil(.2 * this.oneStaffSpace);
			this.chordDiagramStringSpacing = Math.ceil(1.1 * this.oneStaffSpace);
			this.chordDiagramFretSpacing = Math.ceil(1.3 * this.oneStaffSpace);
			this.chordDiagramNutHeight = Math.ceil(.33 * this.oneStaffSpace);
			this.chordDiagramFretHeight = Math.ceil(.1 * this.oneStaffSpace);
			this.chordDiagramLineWidth = Math.ceil(.11 * this.oneStaffSpace);
			this.tripletFeelBracketPadding = .2 * this.oneStaffSpace;
			this.accidentalPadding = .1 * this.oneStaffSpace;
			this.preBeatGlyphSpacing = .5 * this.oneStaffSpace;
			this.multiVoiceDisplacedNoteHeadSpacing = .2 * this.oneStaffSpace;
			this.tuningGlyphStringRowPadding = .2 * this.oneStaffSpace;
		}
		/**
		* @internal
		*/
		static smuflNameToGlyphNameMapping = new Map([["4stringTabClef", "FourStringTabClef"], ["6stringTabClef", "SixStringTabClef"]]);
		static _smuflNameToMusicFontSymbol(g) {
			const name = EngravingSettings.smuflNameToGlyphNameMapping.has(g) ? EngravingSettings.smuflNameToGlyphNameMapping.get(g) : g.substring(0, 1).toUpperCase() + g.substring(1);
			return JsonHelper.parseEnumExact(name, MusicFontSymbol);
		}
		/**
		* The size of the bars drawn in numbered notation to indicate the durations.
		*/
		numberedBarRendererBarSize = 0;
		/**
		* The spacing between the bars drawn in numbered notation to indicate the durations.
		*/
		numberedBarRendererBarSpacing = 0;
		/**
		* The padding minimum between the duration dashes.
		*/
		numberedDashGlyphPadding = 0;
		/**
		* The width of the dashed drawn in numbered notation to indicate the durations.
		*/
		numberedDashGlyphWidth = 0;
		/**
		* The gap between dashes on line ranged glyphs (like let-ring)
		*/
		lineRangedGlyphDashGap = 0;
		/**
		* The size between dashes on line ranged glyphs (like let-ring)
		*/
		lineRangedGlyphDashSize = 0;
		/**
		* The padding between effects and glyphs placed before the note heads, e.g. accidentals or brushes
		*/
		preNoteEffectPadding = 0;
		/**
		* The padding between effects and glyphs placed after the note heads, e.g. slides or bends
		*/
		postNoteEffectPadding = 0;
		/**
		* The padding between effects and glyphs placed above/blow the note heads e.g. staccato
		*/
		onNoteEffectPadding = 0;
		/**
		* The padding between the circles around string numbers.
		*/
		stringNumberCirclePadding = 0;
		/**
		* The outer padding for glyphs arranged in a grid like fashion, like the tunings and chord diagrams.
		*/
		rowContainerPadding = 0;
		/**
		* The innter gap for glyphs arranged in a grid like fashion, like the tunings and chord diagrams.
		*/
		rowContainerGap = 0;
		/**
		* The padding used for aligning the alternate ending brackets and texts.
		*/
		alternateEndingsPadding = 0;
		/**
		* The padding between the sustain pedal glyphs and lines.
		*/
		sustainPedalLinePadding = 0;
		/**
		* The height of ties.
		*/
		tieHeight = 0;
		/**
		* The padding between the border and text of beat timers.
		*/
		beatTimerPadding = 0;
		/**
		* The additional padding applied to helper note heads shown on bends.
		*/
		bendNoteHeadElementPadding = 0;
		/**
		* The width of the parenthesis shown on ghost notes and free time time signatures.
		*/
		ghostParenthesisWidth = 0;
		/**
		* The padding between the parenthesis and wrapped elements on ghost notes and free time time signatures
		*/
		ghostParenthesisPadding = 0;
		/**
		* The width of broken beams e.g. when combining a 32nd and 16th note
		*/
		brokenBeamWidth = 0;
		/**
		* The padding between the text and whammy lines.
		*/
		tabWhammyTextPadding = 0;
		/**
		* The height applied per half-note whammy.
		*/
		tabWhammyPerHalfHeight = 0;
		/**
		* The size of the dashes on whammys (e.g. on holds)
		*/
		tabWhammyDashSize = 0;
		/**
		* The height of simple dip whammys when using the songbook mode.
		*/
		songBookWhammyDipHeight = 0;
		/**
		* The width of the lines drawn for dead slapped beats.
		*/
		deadSlappedLineWidth = 0;
		/**
		* The width of ties drawn for left-hand-tapped notes.
		*/
		leftHandTabTieWidth = 0;
		/**
		* The size of the dashes on bends (e.g. on holds)
		*/
		tabBendDashSize = 0;
		/**
		* The additional padding between the staff and the point
		* where bend values are calculated from.
		*/
		tabBendStaffPadding = 0;
		/**
		* The height applied per quarter-note.
		*/
		tabBendPerValueHeight = 0;
		/**
		* The padding applied between the line and text of bends.
		*/
		tabBendLabelPadding = 0;
		/**
		* The width of simple slides like slide out down which do slide to a defined target note.
		*/
		simpleSlideWidth = 0;
		/**
		* The height of simple slides like slide out down which do slide to a defined target note.
		*/
		simpleSlideHeight = 0;
		/**
		* The horizontal padding applied to individual chord diagrams.
		*/
		chordDiagramPaddingX = 0;
		/**
		* The vertical padding applied to individual chord diagrams.
		*/
		chordDiagramPaddingY = 0;
		/**
		* The spacing between strings on chord diagrams.
		*/
		chordDiagramStringSpacing = 0;
		/**
		* The spacing between frets on chord diagrams.
		*/
		chordDiagramFretSpacing = 0;
		/**
		* The height of the nut on chord diagrams..
		*/
		chordDiagramNutHeight = 0;
		/**
		* The height of the individual fret lines.
		*/
		chordDiagramFretHeight = 0;
		/**
		* The width of all other lines drawn on chord diagrams.
		*/
		chordDiagramLineWidth = 0;
		/**
		* The padding between the bracket lines and numbers of tuplets
		*/
		tripletFeelBracketPadding = 0;
		/**
		* The horizontal padding between individual accidentals when multiple ones are applied.
		*/
		accidentalPadding = 0;
		/**
		* The padding between glyphs shown before any beats e.g. clefs and time signatures
		*/
		preBeatGlyphSpacing = 0;
		/**
		* The relative scale of the note drawn on tempo markers
		*/
		tempoNoteScale = .7;
		/**
		* The scale of string numbers shown on tuning glyphs.
		*/
		tuningGlyphCircleNumberScale = .7;
		/**
		* The scale factor applied to the width of the columns of string on tuning glyphs.
		*/
		tuningGlyphStringColumnScale = 1.5;
		/**
		* The padding between rows of strings on tuning glyphs.
		*/
		tuningGlyphStringRowPadding = 0;
		/**
		* The relative scale of any directions glyphs drawn like coda or segno.
		*/
		directionsScale = .6;
		/**
		* The spacing between displaced displaced note heads
		* in case of multi-voice note head overlaps.
		*/
		multiVoiceDisplacedNoteHeadSpacing = 0;
		/**
		* Calculates the stem height for a note of the given duration.
		* @param duration The duration to calculate the height respecting flag sizes.
		* @param hasFlag True if we need to respect flags, false if we have beams.
		* @returns The total stem height
		*/
		getStemLength(duration, hasFlag) {
			return this.standardStemLength + (hasFlag ? this.stemFlagOffsets.get(duration) : 0);
		}
		/**
		* The space needed by flags on the stem-side from top to bottom to place.
		*/
		stemFlagHeight = /* @__PURE__ */ new Map();
		static bravuraMetadata = {
			engravingDefaults: {
				arrowShaftThickness: .16,
				barlineSeparation: .4,
				beamSpacing: .25,
				beamThickness: .5,
				bracketThickness: .5,
				dashedBarlineDashLength: .5,
				dashedBarlineGapLength: .25,
				dashedBarlineThickness: .16,
				hairpinThickness: .16,
				legerLineExtension: .4,
				legerLineThickness: .16,
				lyricLineThickness: .16,
				octaveLineThickness: .16,
				pedalLineThickness: .16,
				repeatBarlineDotSeparation: .16,
				repeatEndingLineThickness: .16,
				slurEndpointThickness: .1,
				slurMidpointThickness: .22,
				staffLineThickness: .13,
				stemThickness: .12,
				subBracketThickness: .16,
				textEnclosureThickness: .16,
				thickBarlineThickness: .5,
				thinBarlineThickness: .16,
				tieEndpointThickness: .1,
				tieMidpointThickness: .22,
				thinThickBarlineSeparation: .4,
				tupletBracketThickness: .16
			},
			glyphBBoxes: {
				FourStringTabClef: {
					bBoxNE: [1.088, 2.016],
					bBoxSW: [-.012, -2.032]
				},
				SixStringTabClef: {
					bBoxNE: [1.632, 3.056],
					bBoxSW: [-.012, -2.992]
				},
				accidentalDoubleFlat: {
					bBoxNE: [1.644, 1.748],
					bBoxSW: [0, -.7]
				},
				accidentalDoubleSharp: {
					bBoxNE: [.988, .508],
					bBoxSW: [0, -.5]
				},
				accidentalFlat: {
					bBoxNE: [.904, 1.756],
					bBoxSW: [0, -.7]
				},
				accidentalNatural: {
					bBoxNE: [.672, 1.364],
					bBoxSW: [0, -1.34]
				},
				accidentalQuarterToneFlatArrowUp: {
					bBoxNE: [.992, 2.316],
					bBoxSW: [-.168, -.708]
				},
				accidentalQuarterToneSharpNaturalArrowUp: {
					bBoxNE: [.848, 2.188],
					bBoxSW: [-.104, -1.36]
				},
				accidentalSharp: {
					bBoxNE: [.996, 1.4],
					bBoxSW: [0, -1.392]
				},
				accidentalThreeQuarterTonesSharpArrowUp: {
					bBoxNE: [1.1, 2.12],
					bBoxSW: [0, -1.388]
				},
				arrowheadBlackDown: {
					bBoxNE: [.912, 1.196],
					bBoxSW: [0, 0]
				},
				arrowheadBlackUp: {
					bBoxNE: [.912, 1.196],
					bBoxSW: [0, 0]
				},
				articAccentAbove: {
					bBoxNE: [1.356, .98],
					bBoxSW: [0, .004]
				},
				articAccentBelow: {
					bBoxNE: [1.356, 0],
					bBoxSW: [0, -.976]
				},
				articMarcatoAbove: {
					bBoxNE: [.94, 1.012],
					bBoxSW: [-.004, -.004]
				},
				articMarcatoBelow: {
					bBoxNE: [.94, 0],
					bBoxSW: [-.004, -1.016]
				},
				articStaccatoAbove: {
					bBoxNE: [.336, .336],
					bBoxSW: [0, 0]
				},
				articStaccatoBelow: {
					bBoxNE: [.336, 0],
					bBoxSW: [0, -.336]
				},
				articTenutoAbove: {
					bBoxNE: [1.352, .192],
					bBoxSW: [-.004, 0]
				},
				articTenutoBelow: {
					bBoxNE: [1.352, 0],
					bBoxSW: [-.004, -.192]
				},
				augmentationDot: {
					bBoxNE: [.4, .2],
					bBoxSW: [0, -.2]
				},
				brace: {
					bBoxNE: [.328, 3.988],
					bBoxSW: [.008, 0]
				},
				bracketBottom: {
					bBoxNE: [1.876, 0],
					bBoxSW: [0, -1.18]
				},
				bracketTop: {
					bBoxNE: [1.876, 1.18],
					bBoxSW: [0, 0]
				},
				buzzRoll: {
					bBoxNE: [.624, .464],
					bBoxSW: [-.62, -.464]
				},
				cClef: {
					bBoxNE: [2.796, 2.024],
					bBoxSW: [0, -2.024]
				},
				cClef8vb: {
					bBoxNE: [2.796, 2.024],
					bBoxSW: [0, -2.964]
				},
				clef15: {
					bBoxNE: [1.436, 1.02],
					bBoxSW: [0, -.012]
				},
				clef8: {
					bBoxNE: [.82, .988],
					bBoxSW: [0, 0]
				},
				coda: {
					bBoxNE: [3.82, 3.592],
					bBoxSW: [-.016, -.632]
				},
				dynamicCrescendoHairpin: {
					bBoxNE: [2.944, 1.424],
					bBoxSW: [.016, .372]
				},
				dynamicFF: {
					bBoxNE: [2.44, 1.776],
					bBoxSW: [-.54, -.608]
				},
				dynamicFFF: {
					bBoxNE: [3.32, 1.776],
					bBoxSW: [-.62, -.608]
				},
				dynamicFFFF: {
					bBoxNE: [4.28, 1.776],
					bBoxSW: [-.62, -.608]
				},
				dynamicFFFFF: {
					bBoxNE: [5.24, 1.776],
					bBoxSW: [-.62, -.608]
				},
				dynamicFFFFFF: {
					bBoxNE: [6.2, 1.776],
					bBoxSW: [-.62, -.608]
				},
				dynamicForte: {
					bBoxNE: [1.456, 1.776],
					bBoxSW: [-.564, -.608]
				},
				dynamicFortePiano: {
					bBoxNE: [2.476, 1.776],
					bBoxSW: [-.564, -.608]
				},
				dynamicForzando: {
					bBoxNE: [1.988, 1.776],
					bBoxSW: [-.564, -.608]
				},
				dynamicMF: {
					bBoxNE: [3.272, 1.724],
					bBoxSW: [-.08, -.66]
				},
				dynamicMP: {
					bBoxNE: [3.3, 1.096],
					bBoxSW: [-.08, -.568]
				},
				dynamicNiente: {
					bBoxNE: [1.232, 1.096],
					bBoxSW: [-.092, -.04]
				},
				dynamicPF: {
					bBoxNE: [3.08, 1.776],
					bBoxSW: [-.288, -.608]
				},
				dynamicPP: {
					bBoxNE: [2.912, 1.096],
					bBoxSW: [-.328, -.568]
				},
				dynamicPPP: {
					bBoxNE: [4.292, 1.096],
					bBoxSW: [-.368, -.568]
				},
				dynamicPPPP: {
					bBoxNE: [5.672, 1.096],
					bBoxSW: [-.408, -.568]
				},
				dynamicPPPPP: {
					bBoxNE: [7.092, 1.096],
					bBoxSW: [-.408, -.568]
				},
				dynamicPPPPPP: {
					bBoxNE: [8.512, 1.096],
					bBoxSW: [-.408, -.568]
				},
				dynamicPiano: {
					bBoxNE: [1.464, 1.096],
					bBoxSW: [-.356, -.568]
				},
				dynamicRinforzando1: {
					bBoxNE: [2.5, 1.776],
					bBoxSW: [-.08, -.608]
				},
				dynamicRinforzando2: {
					bBoxNE: [2.976, 1.776],
					bBoxSW: [-.08, -.608]
				},
				dynamicSforzando1: {
					bBoxNE: [2.416, 1.776],
					bBoxSW: [0, -.608]
				},
				dynamicSforzandoPianissimo: {
					bBoxNE: [4.796, 1.776],
					bBoxSW: [0, -.608]
				},
				dynamicSforzandoPiano: {
					bBoxNE: [3.38, 1.776],
					bBoxSW: [0, -.608]
				},
				dynamicSforzato: {
					bBoxNE: [2.932, 1.776],
					bBoxSW: [0, -.608]
				},
				dynamicSforzatoFF: {
					bBoxNE: [3.856, 1.776],
					bBoxSW: [0, -.608]
				},
				dynamicSforzatoPiano: {
					bBoxNE: [4.304, 1.776],
					bBoxSW: [0, -.608]
				},
				fClef: {
					bBoxNE: [2.736, 1.048],
					bBoxSW: [-.02, -2.54]
				},
				fClef15ma: {
					bBoxNE: [2.736, 1.984],
					bBoxSW: [-.02, -2.54]
				},
				fClef15mb: {
					bBoxNE: [2.736, 1.048],
					bBoxSW: [-.02, -2.968]
				},
				fClef8va: {
					bBoxNE: [2.736, 1.98],
					bBoxSW: [-.02, -2.54]
				},
				fClef8vb: {
					bBoxNE: [2.736, 1.048],
					bBoxSW: [-.02, -2.976]
				},
				fermataAbove: {
					bBoxNE: [2.42, 1.316],
					bBoxSW: [.012, -.012]
				},
				fermataLongAbove: {
					bBoxNE: [2.412, 1.332],
					bBoxSW: [0, -.004]
				},
				fermataShortAbove: {
					bBoxNE: [2.416, 1.364],
					bBoxSW: [0, 0]
				},
				fingering0: {
					bBoxNE: [.94, 1.004],
					bBoxSW: [.08, -.004]
				},
				fingering1: {
					bBoxNE: [.548, 1.016],
					bBoxSW: [.08, 0]
				},
				fingering2: {
					bBoxNE: [.888, 1.012],
					bBoxSW: [.08, -.012]
				},
				fingering3: {
					bBoxNE: [.82, 1.008],
					bBoxSW: [.08, 0]
				},
				fingering4: {
					bBoxNE: [.864, 1.012],
					bBoxSW: [.08, .004]
				},
				fingering5: {
					bBoxNE: [.82, 1.032],
					bBoxSW: [.08, 0]
				},
				fingeringALower: {
					bBoxNE: [1.068, 1.032],
					bBoxSW: [0, -.02]
				},
				fingeringCLower: {
					bBoxNE: [.888, 1.044],
					bBoxSW: [0, -.028]
				},
				fingeringILower: {
					bBoxNE: [.656, 1.54],
					bBoxSW: [-.052, -.028]
				},
				fingeringMLower: {
					bBoxNE: [1.66, 1.028],
					bBoxSW: [-.032, -.016]
				},
				fingeringPLower: {
					bBoxNE: [1.088, 1.028],
					bBoxSW: [-.216, -.612]
				},
				fingeringTLower: {
					bBoxNE: [.604, 1.484],
					bBoxSW: [0, -.028]
				},
				flag128thDown: {
					bBoxNE: [1.092, 3.248],
					bBoxSW: [0, -2.32]
				},
				flag128thUp: {
					bBoxNE: [1.044, 2.132],
					bBoxSW: [0, -3.248]
				},
				flag16thDown: {
					bBoxNE: [1.1635806326044895, 3.2480256],
					bBoxSW: [0, -.036]
				},
				flag16thUp: {
					bBoxNE: [1.116, .008],
					bBoxSW: [0, -3.252]
				},
				flag256thDown: {
					bBoxNE: [1.196, 3.252],
					bBoxSW: [0, -3.004]
				},
				flag256thUp: {
					bBoxNE: [1.056, 2.816],
					bBoxSW: [0, -3.248]
				},
				flag32ndDown: {
					bBoxNE: [1.092, 3.248],
					bBoxSW: [0, -.688]
				},
				flag32ndUp: {
					bBoxNE: [1.044, .596],
					bBoxSW: [0, -3.248]
				},
				flag64thDown: {
					bBoxNE: [1.092, 3.248],
					bBoxSW: [0, -1.504]
				},
				flag64thUp: {
					bBoxNE: [1.044, 1.388],
					bBoxSW: [0, -3.248]
				},
				flag8thDown: {
					bBoxNE: [1.224, 3.232896633157715],
					bBoxSW: [0, -.056]
				},
				flag8thUp: {
					bBoxNE: [1.056, .036],
					bBoxSW: [0, -3.240768470618394]
				},
				fretboardFilledCircle: {
					bBoxNE: [.564, .564],
					bBoxSW: [0, 0]
				},
				fretboardO: {
					bBoxNE: [.564, .564],
					bBoxSW: [0, 0]
				},
				fretboardX: {
					bBoxNE: [.596, .596],
					bBoxSW: [0, 0]
				},
				gClef: {
					bBoxNE: [2.684, 4.392],
					bBoxSW: [0, -2.632]
				},
				gClef15ma: {
					bBoxNE: [2.684, 5.276],
					bBoxSW: [0, -2.632]
				},
				gClef15mb: {
					bBoxNE: [2.684, 4.392],
					bBoxSW: [0, -3.524]
				},
				gClef8va: {
					bBoxNE: [2.684, 5.28],
					bBoxSW: [0, -2.632]
				},
				gClef8vb: {
					bBoxNE: [2.684, 4.392],
					bBoxSW: [0, -3.512]
				},
				graceNoteSlashStemDown: {
					bBoxNE: [2.02, 0],
					bBoxSW: [0, -1.604]
				},
				graceNoteSlashStemUp: {
					bBoxNE: [2.02, 1.604],
					bBoxSW: [0, 0]
				},
				guitarClosePedal: {
					bBoxNE: [1.144, 1.14],
					bBoxSW: [0, -.004]
				},
				guitarFadeIn: {
					bBoxNE: [1.448, 1.46],
					bBoxSW: [0, 0]
				},
				guitarFadeOut: {
					bBoxNE: [1.448, 1.46],
					bBoxSW: [0, 0]
				},
				guitarGolpe: {
					bBoxNE: [1.08, 1.128],
					bBoxSW: [.004, 0]
				},
				guitarLeftHandTapping: {
					bBoxNE: [1.588, 1.364],
					bBoxSW: [0, -.224]
				},
				guitarOpenPedal: {
					bBoxNE: [1.144, 1.144],
					bBoxSW: [0, 0]
				},
				guitarString0: {
					bBoxNE: [2.164, 2.156],
					bBoxSW: [.004, 0]
				},
				guitarString1: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarString2: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarString3: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarString4: {
					bBoxNE: [2.164, 2.156],
					bBoxSW: [.004, 0]
				},
				guitarString5: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarString6: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarString7: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarString8: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarString9: {
					bBoxNE: [2.16, 2.156],
					bBoxSW: [0, 0]
				},
				guitarVibratoStroke: {
					bBoxNE: [.668, .476],
					bBoxSW: [-.056, 0]
				},
				guitarVolumeSwell: {
					bBoxNE: [2.896, 1.46],
					bBoxSW: [0, 0]
				},
				guitarWideVibratoStroke: {
					bBoxNE: [.908, .896],
					bBoxSW: [-.096, 0]
				},
				keyboardPedalPed: {
					bBoxNE: [4.076, 2.22],
					bBoxSW: [0, -.032]
				},
				keyboardPedalUp: {
					bBoxNE: [1.8, 1.8],
					bBoxSW: [0, 0]
				},
				metAugmentationDot: {
					bBoxNE: [.4, .2],
					bBoxSW: [0, -.2]
				},
				metNote8thUp: {
					bBoxNE: [2.132, 2.784],
					bBoxSW: [0, -.564]
				},
				metNoteQuarterUp: {
					bBoxNE: [1.328, 2.752],
					bBoxSW: [0, -.564]
				},
				note8thUp: {
					bBoxNE: [2.264, 3.492],
					bBoxSW: [0, -.552]
				},
				noteQuarterUp: {
					bBoxNE: [1.328, 3.5],
					bBoxSW: [0, -.564]
				},
				noteShapeDiamondBlack: {
					bBoxNE: [1.444, .548],
					bBoxSW: [0, -.552]
				},
				noteShapeDiamondWhite: {
					bBoxNE: [1.444, .544],
					bBoxSW: [0, -.556]
				},
				noteShapeMoonBlack: {
					bBoxNE: [1.444, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeMoonWhite: {
					bBoxNE: [1.444, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeRoundBlack: {
					bBoxNE: [1.456, .552],
					bBoxSW: [0, -.552]
				},
				noteShapeRoundWhite: {
					bBoxNE: [1.464, .548],
					bBoxSW: [0, -.548]
				},
				noteShapeSquareBlack: {
					bBoxNE: [1.44, .46],
					bBoxSW: [0, -.46]
				},
				noteShapeSquareWhite: {
					bBoxNE: [1.44, .46],
					bBoxSW: [0, -.46]
				},
				noteShapeTriangleLeftBlack: {
					bBoxNE: [1.44, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeTriangleLeftWhite: {
					bBoxNE: [1.44, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeTriangleRightBlack: {
					bBoxNE: [1.44, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeTriangleRightWhite: {
					bBoxNE: [1.44, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeTriangleRoundBlack: {
					bBoxNE: [1.424, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeTriangleRoundWhite: {
					bBoxNE: [1.424, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeTriangleUpBlack: {
					bBoxNE: [1.424, .5],
					bBoxSW: [0, -.5]
				},
				noteShapeTriangleUpWhite: {
					bBoxNE: [1.424, .5],
					bBoxSW: [0, -.5]
				},
				noteheadBlack: {
					bBoxNE: [1.18, .5],
					bBoxSW: [0, -.5]
				},
				noteheadCircleSlash: {
					bBoxNE: [1, .5],
					bBoxSW: [0, -.5]
				},
				noteheadCircleX: {
					bBoxNE: [.996, .5],
					bBoxSW: [0, -.5]
				},
				noteheadCircleXDoubleWhole: {
					bBoxNE: [1.688, .62],
					bBoxSW: [0, -.62]
				},
				noteheadCircleXHalf: {
					bBoxNE: [1, .5],
					bBoxSW: [0, -.5]
				},
				noteheadCircleXWhole: {
					bBoxNE: [.996, .5],
					bBoxSW: [0, -.5]
				},
				noteheadCircledBlack: {
					bBoxNE: [1.284, .668],
					bBoxSW: [-.084, -.684]
				},
				noteheadCircledDoubleWhole: {
					bBoxNE: [2.412, .852],
					bBoxSW: [0, -.872]
				},
				noteheadCircledHalf: {
					bBoxNE: [1.244, .668],
					bBoxSW: [-.072, -.648]
				},
				noteheadCircledWhole: {
					bBoxNE: [1.748, .844],
					bBoxSW: [0, -.9]
				},
				noteheadClusterDoubleWhole3rd: {
					bBoxNE: [2.428, 1.62],
					bBoxSW: [0, -.62]
				},
				noteheadClusterHalf3rd: {
					bBoxNE: [1.264, 1.5],
					bBoxSW: [0, -.5]
				},
				noteheadClusterQuarter3rd: {
					bBoxNE: [1.44, 1.5],
					bBoxSW: [0, -.5]
				},
				noteheadClusterWhole3rd: {
					bBoxNE: [1.7, 1.5],
					bBoxSW: [0, -.5]
				},
				noteheadDiamondBlack: {
					bBoxNE: [1, .5],
					bBoxSW: [0, -.5]
				},
				noteheadDiamondBlackWide: {
					bBoxNE: [1.4, .5],
					bBoxSW: [0, -.5]
				},
				noteheadDiamondDoubleWhole: {
					bBoxNE: [1.728, .62],
					bBoxSW: [0, -.62]
				},
				noteheadDiamondHalf: {
					bBoxNE: [1.004, .5],
					bBoxSW: [0, -.5]
				},
				noteheadDiamondWhite: {
					bBoxNE: [1, .5],
					bBoxSW: [0, -.5]
				},
				noteheadDiamondWhiteWide: {
					bBoxNE: [1.4, .5],
					bBoxSW: [0, -.5]
				},
				noteheadDiamondWhole: {
					bBoxNE: [1.08, .5],
					bBoxSW: [0, -.5]
				},
				noteheadDoubleWhole: {
					bBoxNE: [2.396, .62],
					bBoxSW: [0, -.62]
				},
				noteheadDoubleWholeSquare: {
					bBoxNE: [1.664, .792],
					bBoxSW: [0, -.76]
				},
				noteheadHalf: {
					bBoxNE: [1.18, .5],
					bBoxSW: [0, -.5]
				},
				noteheadHeavyX: {
					bBoxNE: [1.54, .5],
					bBoxSW: [0, -.5]
				},
				noteheadHeavyXHat: {
					bBoxNE: [1.828, 1.04],
					bBoxSW: [-.292, -.5]
				},
				noteheadParenthesis: {
					bBoxNE: [1.472, .728],
					bBoxSW: [-.292, -.72]
				},
				noteheadPlusBlack: {
					bBoxNE: [.996, .5],
					bBoxSW: [-.004, -.5]
				},
				noteheadPlusDoubleWhole: {
					bBoxNE: [1.892, .62],
					bBoxSW: [0, -.62]
				},
				noteheadPlusHalf: {
					bBoxNE: [1.044, .5],
					bBoxSW: [0, -.5]
				},
				noteheadPlusWhole: {
					bBoxNE: [1.14, .5],
					bBoxSW: [0, -.5]
				},
				noteheadRoundWhiteWithDot: {
					bBoxNE: [1.004, .5],
					bBoxSW: [0, -.5]
				},
				noteheadSlashHorizontalEnds: {
					bBoxNE: [2.12, 1],
					bBoxSW: [0, -1]
				},
				noteheadSlashWhiteHalf: {
					bBoxNE: [3.12, 1],
					bBoxSW: [0, -1]
				},
				noteheadSlashWhiteWhole: {
					bBoxNE: [3.92, 1],
					bBoxSW: [0, -1]
				},
				noteheadSlashedBlack1: {
					bBoxNE: [1.5, .668],
					bBoxSW: [-.32, -.66]
				},
				noteheadSlashedBlack2: {
					bBoxNE: [1.504, .672],
					bBoxSW: [-.316, -.656]
				},
				noteheadSlashedDoubleWhole1: {
					bBoxNE: [2.384, .672],
					bBoxSW: [0, -.716]
				},
				noteheadSlashedDoubleWhole2: {
					bBoxNE: [2.384, .676],
					bBoxSW: [0, -.712]
				},
				noteheadSlashedHalf1: {
					bBoxNE: [1.544, .64],
					bBoxSW: [-.268, -.568]
				},
				noteheadSlashedHalf2: {
					bBoxNE: [1.52, .672],
					bBoxSW: [-.292, -.536]
				},
				noteheadSlashedWhole1: {
					bBoxNE: [1.732, .592],
					bBoxSW: [-.088, -.628]
				},
				noteheadSlashedWhole2: {
					bBoxNE: [1.744, .604],
					bBoxSW: [-.072, -.616]
				},
				noteheadSquareBlack: {
					bBoxNE: [1.252, .5],
					bBoxSW: [0, -.5]
				},
				noteheadSquareBlackLarge: {
					bBoxNE: [2, 1],
					bBoxSW: [0, -1]
				},
				noteheadSquareBlackWhite: {
					bBoxNE: [2, 1],
					bBoxSW: [0, -1]
				},
				noteheadSquareWhite: {
					bBoxNE: [1.252, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleDownBlack: {
					bBoxNE: [1.168, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleDownDoubleWhole: {
					bBoxNE: [1.932, .62],
					bBoxSW: [0, -.62]
				},
				noteheadTriangleDownHalf: {
					bBoxNE: [1.14, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleDownWhole: {
					bBoxNE: [1.276, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleRightBlack: {
					bBoxNE: [1.356, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleRightWhite: {
					bBoxNE: [1.356, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleUpBlack: {
					bBoxNE: [1.172, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleUpDoubleWhole: {
					bBoxNE: [1.932, .62],
					bBoxSW: [0, -.62]
				},
				noteheadTriangleUpHalf: {
					bBoxNE: [1.14, .5],
					bBoxSW: [0, -.5]
				},
				noteheadTriangleUpWhole: {
					bBoxNE: [1.276, .5],
					bBoxSW: [0, -.5]
				},
				noteheadWhole: {
					bBoxNE: [1.688, .5],
					bBoxSW: [0, -.5]
				},
				noteheadXBlack: {
					bBoxNE: [1.16, .5],
					bBoxSW: [0, -.5]
				},
				noteheadXDoubleWhole: {
					bBoxNE: [2.184, .62],
					bBoxSW: [0, -.62]
				},
				noteheadXHalf: {
					bBoxNE: [1.336, .5],
					bBoxSW: [0, -.5]
				},
				noteheadXOrnate: {
					bBoxNE: [.988, .504],
					bBoxSW: [0, -.504]
				},
				noteheadXWhole: {
					bBoxNE: [1.508, .5],
					bBoxSW: [0, -.5]
				},
				octaveBaselineB: {
					bBoxNE: [.796, 1.352],
					bBoxSW: [0, -.04]
				},
				octaveBaselineM: {
					bBoxNE: [1.524, .928],
					bBoxSW: [0, -.02]
				},
				ornamentMordent: {
					bBoxNE: [2.916, 1.276],
					bBoxSW: [.004, -.292]
				},
				ornamentShortTrill: {
					bBoxNE: [2.9, .98],
					bBoxSW: [0, 0]
				},
				ornamentTrill: {
					bBoxNE: [2.084, 1.56],
					bBoxSW: [0, -.04]
				},
				ornamentTurn: {
					bBoxNE: [1.84, .872],
					bBoxSW: [0, 0]
				},
				ornamentTurnInverted: {
					bBoxNE: [1.828, .872],
					bBoxSW: [-.012, 0]
				},
				ottava: {
					bBoxNE: [1.544, 1.852],
					bBoxSW: [0, -.04]
				},
				ottavaAlta: {
					bBoxNE: [3.54, 1.852],
					bBoxSW: [0, -.04]
				},
				ottavaBassaVb: {
					bBoxNE: [3.184, 1.852],
					bBoxSW: [0, -.04]
				},
				pictEdgeOfCymbal: {
					bBoxNE: [4.828, 2.14],
					bBoxSW: [.004, 0]
				},
				quindicesima: {
					bBoxNE: [2.668, 1.844],
					bBoxSW: [0, -.04]
				},
				quindicesimaAlta: {
					bBoxNE: [5.26, 1.844],
					bBoxSW: [0, -.04]
				},
				repeat1Bar: {
					bBoxNE: [2.128, 1.116],
					bBoxSW: [0, -1]
				},
				repeat2Bars: {
					bBoxNE: [3.048, 1.116],
					bBoxSW: [0, -1]
				},
				repeatDot: {
					bBoxNE: [.4, .2],
					bBoxSW: [0, -.2]
				},
				rest128th: {
					bBoxNE: [1.94, 2.756],
					bBoxSW: [0, -3]
				},
				rest16th: {
					bBoxNE: [1.28, .716],
					bBoxSW: [0, -2]
				},
				rest256th: {
					bBoxNE: [2.164, 2.784],
					bBoxSW: [0, -4]
				},
				rest32nd: {
					bBoxNE: [1.452, 1.704],
					bBoxSW: [0, -2]
				},
				rest64th: {
					bBoxNE: [1.692, 1.72],
					bBoxSW: [0, -3.012]
				},
				rest8th: {
					bBoxNE: [.988, .696],
					bBoxSW: [0, -1.004]
				},
				restDoubleWhole: {
					bBoxNE: [.5, 1],
					bBoxSW: [0, 0]
				},
				restHBarLeft: {
					bBoxNE: [1.5, 1.048],
					bBoxSW: [0, -1.08]
				},
				restHBarMiddle: {
					bBoxNE: [1.42, .384],
					bBoxSW: [-.108, -.416]
				},
				restHBarRight: {
					bBoxNE: [1.5, 1.048],
					bBoxSW: [0, -1.08]
				},
				restHalf: {
					bBoxNE: [1.128, .568],
					bBoxSW: [0, -.008]
				},
				restLonga: {
					bBoxNE: [.5, 1],
					bBoxSW: [0, -.996]
				},
				restQuarter: {
					bBoxNE: [1.08, 1.492],
					bBoxSW: [.004, -1.5]
				},
				restWhole: {
					bBoxNE: [1.128, .036],
					bBoxSW: [0, -.54]
				},
				segno: {
					bBoxNE: [2.2, 3.036],
					bBoxSW: [.016, -.108]
				},
				stringsDownBow: {
					bBoxNE: [1.248, 1.272],
					bBoxSW: [0, 0]
				},
				stringsUpBow: {
					bBoxNE: [.996, 1.98],
					bBoxSW: [.004, .004]
				},
				systemDivider: {
					bBoxNE: [4.232, 4.24],
					bBoxSW: [0, -.272]
				},
				textAugmentationDot: {
					bBoxNE: [.4, .256],
					bBoxSW: [0, -.144]
				},
				textBlackNoteFrac16thLongStem: {
					bBoxNE: [1.368, 3.512],
					bBoxSW: [0, -.56]
				},
				textBlackNoteFrac32ndLongStem: {
					bBoxNE: [1.368, 3.512],
					bBoxSW: [0, -.56]
				},
				textBlackNoteFrac8thLongStem: {
					bBoxNE: [1.368, 3.512],
					bBoxSW: [0, -.56]
				},
				textBlackNoteLongStem: {
					bBoxNE: [1.328, 3.512],
					bBoxSW: [0, -.564]
				},
				textCont16thBeamLongStem: {
					bBoxNE: [1.368, 3.512],
					bBoxSW: [0, 2.264]
				},
				textCont32ndBeamLongStem: {
					bBoxNE: [1.368, 3.512],
					bBoxSW: [0, 1.504]
				},
				textCont8thBeamLongStem: {
					bBoxNE: [1.368, 3.512],
					bBoxSW: [0, 3.012]
				},
				textTuplet3LongStem: {
					bBoxNE: [.94, 5.3],
					bBoxSW: [0, 4.2]
				},
				textTupletBracketEndLongStem: {
					bBoxNE: [1.272, 4.764],
					bBoxSW: [0, 3.94]
				},
				textTupletBracketStartLongStem: {
					bBoxNE: [1.272, 4.764],
					bBoxSW: [0, 3.94]
				},
				timeSig0: {
					bBoxNE: [1.8, 1.004],
					bBoxSW: [.08, -1]
				},
				timeSig1: {
					bBoxNE: [1.256, 1.004],
					bBoxSW: [.08, -1]
				},
				timeSig2: {
					bBoxNE: [1.704, 1.016],
					bBoxSW: [.08, -1.028]
				},
				timeSig3: {
					bBoxNE: [1.604, .996],
					bBoxSW: [.08, -1.004]
				},
				timeSig4: {
					bBoxNE: [1.8, 1.004],
					bBoxSW: [.08, -1]
				},
				timeSig5: {
					bBoxNE: [1.532, .984],
					bBoxSW: [.08, -1.004]
				},
				timeSig6: {
					bBoxNE: [1.656, 1.004],
					bBoxSW: [.08, -.996]
				},
				timeSig7: {
					bBoxNE: [1.684, .996],
					bBoxSW: [.08, -1]
				},
				timeSig8: {
					bBoxNE: [1.664, 1.036],
					bBoxSW: [.08, -1.036]
				},
				timeSig9: {
					bBoxNE: [1.656, 1.004],
					bBoxSW: [.08, -.996]
				},
				timeSigCommon: {
					bBoxNE: [1.696, 1.004],
					bBoxSW: [.02, -.996]
				},
				timeSigCutCommon: {
					bBoxNE: [1.672, 1.444],
					bBoxSW: [0, -1.436]
				},
				tremolo1: {
					bBoxNE: [.6, .376],
					bBoxSW: [-.6, -.372]
				},
				tremolo2: {
					bBoxNE: [.596, .748],
					bBoxSW: [-.604, -.748]
				},
				tremolo3: {
					bBoxNE: [.6, 1.112],
					bBoxSW: [-.6, -1.12]
				},
				tremolo4: {
					bBoxNE: [.6, 1.496],
					bBoxSW: [-.6, -1.48]
				},
				tremolo5: {
					bBoxNE: [.6, 1.88],
					bBoxSW: [-.604, -1.84]
				},
				tuplet0: {
					bBoxNE: [1.2731041262817027, 1.5],
					bBoxSW: [-.001204330173715796, -.032]
				},
				tuplet1: {
					bBoxNE: [1.024, 1.488],
					bBoxSW: [.04, 0]
				},
				tuplet2: {
					bBoxNE: [1.316, 1.5],
					bBoxSW: [.04, -.024]
				},
				tuplet3: {
					bBoxNE: [1.224, 1.5],
					bBoxSW: [.04, -.032]
				},
				tuplet4: {
					bBoxNE: [1.252, 1.488],
					bBoxSW: [.04, 0]
				},
				tuplet5: {
					bBoxNE: [1.308, 1.492],
					bBoxSW: [.04, -.032]
				},
				tuplet6: {
					bBoxNE: [1.256, 1.5],
					bBoxSW: [.04105974105482295, -.032]
				},
				tuplet7: {
					bBoxNE: [1.332, 1.488],
					bBoxSW: [.12, -.016]
				},
				tuplet8: {
					bBoxNE: [1.292, 1.5],
					bBoxSW: [.04, -.032]
				},
				tuplet9: {
					bBoxNE: [1.254940258945177, 1.5],
					bBoxSW: [.04, -.032]
				},
				tupletColon: {
					bBoxNE: [.484, 1.072],
					bBoxSW: [.04, .232]
				},
				unpitchedPercussionClef1: {
					bBoxNE: [1.528, 1],
					bBoxSW: [0, -1]
				},
				wiggleSawtooth: {
					bBoxNE: [3.06, 1.06],
					bBoxSW: [-.068, -1.068]
				},
				wiggleSawtoothNarrow: {
					bBoxNE: [2.06, 1.064],
					bBoxSW: [-.072, -1.064]
				},
				wiggleTrill: {
					bBoxNE: [1.08, .836],
					bBoxSW: [-.144, .392]
				},
				wiggleVibratoMediumFast: {
					bBoxNE: [1.292, .8],
					bBoxSW: [-.104, -.164]
				}
			},
			glyphsWithAnchors: {
				accidentalDoubleFlat: {
					cutOutNE: [.988, .644],
					cutOutSE: [1.336, -.396]
				},
				accidentalFlat: {
					cutOutNE: [.252, .656],
					cutOutSE: [.504, -.476]
				},
				accidentalNatural: {
					cutOutNE: [.192, .776],
					cutOutSW: [.476, -.828]
				},
				accidentalQuarterToneFlatArrowUp: {
					cutOutNE: [.604, .664],
					cutOutSE: [.62, -.452]
				},
				accidentalQuarterToneSharpNaturalArrowUp: { cutOutSW: [.616, -.868] },
				accidentalSharp: {
					cutOutNE: [.84, .896],
					cutOutNW: [.144, .568],
					cutOutSE: [.84, -.596],
					cutOutSW: [.144, -.896]
				},
				accidentalThreeQuarterTonesSharpArrowUp: {
					cutOutNW: [.272, 1.304],
					cutOutSE: [.86, -.584],
					cutOutSW: [.132, -.888]
				},
				dynamicFF: { opticalCenter: [1.852, 0] },
				dynamicFFF: { opticalCenter: [2.472, 0] },
				dynamicFFFF: { opticalCenter: [2.824, 0] },
				dynamicFFFFF: { opticalCenter: [2.976, 0] },
				dynamicFFFFFF: { opticalCenter: [3.504, 0] },
				dynamicForte: { opticalCenter: [1.256, 0] },
				dynamicFortePiano: { opticalCenter: [1.5, 0] },
				dynamicForzando: { opticalCenter: [1.352, 0] },
				dynamicMF: { opticalCenter: [1.796, 0] },
				dynamicMP: { opticalCenter: [1.848, 0] },
				dynamicNiente: { opticalCenter: [.616, 0] },
				dynamicPF: { opticalCenter: [1.68, 0] },
				dynamicPP: { opticalCenter: [1.708, 0] },
				dynamicPPP: { opticalCenter: [2.368, 0] },
				dynamicPPPP: { opticalCenter: [3.004, 0] },
				dynamicPPPPP: { opticalCenter: [3.552, 0] },
				dynamicPPPPPP: { opticalCenter: [4.248, 0] },
				dynamicPiano: { opticalCenter: [1.22, 0] },
				dynamicRinforzando1: { opticalCenter: [1.564, 0] },
				dynamicRinforzando2: { opticalCenter: [2.084, 0] },
				dynamicSforzando1: { opticalCenter: [1.3, 0] },
				dynamicSforzandoPianissimo: { opticalCenter: [1.972, 0] },
				dynamicSforzandoPiano: { opticalCenter: [1.904, 0] },
				dynamicSforzato: { opticalCenter: [1.76, 0] },
				dynamicSforzatoFF: { opticalCenter: [2.276, 0] },
				dynamicSforzatoPiano: { opticalCenter: [1.848, 0] },
				flag128thDown: { stemDownSW: [0, -2.076] },
				flag128thUp: { stemUpNW: [0, 1.9] },
				flag16thDown: { stemDownSW: [0, .128] },
				flag16thUp: { stemUpNW: [0, -.088] },
				flag256thDown: { stemDownSW: [0, -2.812] },
				flag256thUp: { stemUpNW: [0, 2.592] },
				flag32ndDown: { stemDownSW: [0, -.448] },
				flag32ndUp: { stemUpNW: [0, .376] },
				flag64thDown: { stemDownSW: [0, -1.244] },
				flag64thUp: { stemUpNW: [0, 1.172] },
				flag8thDown: {
					graceNoteSlashNW: [-.596, 2.168],
					graceNoteSlashSE: [1.328, .628],
					stemDownSW: [0, .132]
				},
				flag8thUp: {
					graceNoteSlashNE: [1.284, -.796],
					graceNoteSlashSW: [-.644, -2.456],
					stemUpNW: [0, -.04]
				},
				guitarVibratoStroke: { repeatOffset: [.608, 0] },
				guitarWideVibratoStroke: { repeatOffset: [.82, 0] },
				noteShapeDiamondBlack: {
					stemDownNW: [0, 0],
					stemUpSE: [1.444, 0]
				},
				noteShapeDiamondWhite: {
					stemDownNW: [0, 0],
					stemUpSE: [1.436, 0]
				},
				noteShapeMoonBlack: {
					stemDownNW: [0, .068],
					stemUpSE: [1.44, .068]
				},
				noteShapeMoonWhite: {
					stemDownNW: [0, .072],
					stemUpSE: [1.444, .068]
				},
				noteShapeRoundBlack: {
					stemDownNW: [0, -.168],
					stemUpSE: [1.444, .184]
				},
				noteShapeRoundWhite: {
					stemDownNW: [0, -.168],
					stemUpSE: [1.456, .192]
				},
				noteShapeSquareBlack: {
					stemDownNW: [0, .46],
					stemUpSE: [1.44, -.46]
				},
				noteShapeSquareWhite: {
					stemDownNW: [0, .46],
					stemUpSE: [1.44, -.46]
				},
				noteShapeTriangleLeftBlack: {
					stemDownNW: [0, .5],
					stemUpSE: [1.436, -.5]
				},
				noteShapeTriangleLeftWhite: {
					stemDownNW: [0, .5],
					stemUpSE: [1.436, -.5]
				},
				noteShapeTriangleRightBlack: {
					stemDownNW: [0, .476],
					stemUpSE: [1.44, -.5]
				},
				noteShapeTriangleRightWhite: {
					stemDownNW: [0, .476],
					stemUpSE: [1.44, -.5]
				},
				noteShapeTriangleRoundBlack: {
					stemDownNW: [0, .172],
					stemUpSE: [1.424, .172]
				},
				noteShapeTriangleRoundWhite: {
					stemDownNW: [0, .172],
					stemUpSE: [1.424, .172]
				},
				noteShapeTriangleUpBlack: {
					stemDownNW: [0, -.5],
					stemUpSE: [1.424, -.5]
				},
				noteShapeTriangleUpWhite: {
					stemDownNW: [0, -.5],
					stemUpSE: [1.424, -.5]
				},
				noteheadBlack: {
					cutOutNW: [.208, .3],
					cutOutSE: [.94, -.296],
					splitStemDownNE: [.968, -.248],
					splitStemDownNW: [.12, -.416],
					splitStemUpSE: [1.092, .392],
					splitStemUpSW: [.312, .356],
					stemDownNW: [0, -.168],
					stemUpSE: [1.18, .168]
				},
				noteheadCircleSlash: {
					stemDownNW: [.004, 0],
					stemUpSE: [1, 0]
				},
				noteheadCircleX: {
					stemDownNW: [0, 0],
					stemUpSE: [.996, 0]
				},
				noteheadCircleXDoubleWhole: { noteheadOrigin: [.352, 0] },
				noteheadCircleXHalf: {
					stemDownNW: [0, 0],
					stemUpSE: [1, 0]
				},
				noteheadCircledBlack: {
					stemDownNW: [0, -.164],
					stemUpSE: [1.18, .168]
				},
				noteheadCircledDoubleWhole: { noteheadOrigin: [.356, 0] },
				noteheadCircledHalf: {
					stemDownNW: [0, -.144],
					stemUpSE: [1.172, .156]
				},
				noteheadClusterDoubleWhole3rd: { noteheadOrigin: [.364, 0] },
				noteheadClusterHalf3rd: {
					stemDownNW: [0, -.164],
					stemUpSE: [1.264, 1.144]
				},
				noteheadClusterQuarter3rd: {
					stemDownNW: [0, .26],
					stemUpSE: [1.44, .744]
				},
				noteheadDiamondBlack: {
					stemDownNW: [0, 0],
					stemUpSE: [1, 0]
				},
				noteheadDiamondBlackWide: {
					stemDownNW: [0, 0],
					stemUpSE: [1.4, 0]
				},
				noteheadDiamondDoubleWhole: { noteheadOrigin: [.324, 0] },
				noteheadDiamondHalf: {
					stemDownNW: [0, 0],
					stemUpSE: [1.004, 0]
				},
				noteheadDiamondWhite: {
					stemDownNW: [0, 0],
					stemUpSE: [1, 0]
				},
				noteheadDiamondWhiteWide: {
					stemDownNW: [0, .004],
					stemUpSE: [1.4, 0]
				},
				noteheadDoubleWhole: { noteheadOrigin: [.36, 0] },
				noteheadHalf: {
					cutOutNW: [.204, .296],
					cutOutSE: [.98, -.3],
					splitStemDownNE: [.956, -.3],
					splitStemDownNW: [.128, -.428],
					splitStemUpSE: [1.108, .372],
					splitStemUpSW: [.328, .38],
					stemDownNW: [0, -.168],
					stemUpSE: [1.18, .168]
				},
				noteheadHeavyX: {
					stemDownNW: [0, -.436],
					stemUpSE: [1.54, .44]
				},
				noteheadHeavyXHat: {
					stemDownNW: [0, -.436],
					stemUpSE: [1.54, .456]
				},
				noteheadPlusBlack: {
					stemDownNW: [-.004, 0],
					stemUpSE: [.996, 0]
				},
				noteheadPlusDoubleWhole: { noteheadOrigin: [.372, 0] },
				noteheadPlusHalf: {
					stemDownNW: [0, -.112],
					stemUpSE: [1.044, .088]
				},
				noteheadRoundWhiteWithDot: {
					stemDownNW: [0, 0],
					stemUpSE: [1.004, 0]
				},
				noteheadSlashHorizontalEnds: {
					stemDownNW: [0, -1],
					stemUpSE: [2.12, 1]
				},
				noteheadSlashWhiteHalf: {
					stemDownNW: [0, -1],
					stemUpSE: [3.12, 1]
				},
				noteheadSlashedBlack1: {
					stemDownNW: [0, -.172],
					stemUpSE: [1.18, .164]
				},
				noteheadSlashedBlack2: {
					stemDownNW: [0, -.172],
					stemUpSE: [1.18, .164]
				},
				noteheadSlashedDoubleWhole1: { noteheadOrigin: [.356, 0] },
				noteheadSlashedDoubleWhole2: { noteheadOrigin: [.356, 0] },
				noteheadSlashedHalf1: {
					stemDownNW: [0, -.168],
					stemUpSE: [1.168, .164]
				},
				noteheadSlashedHalf2: {
					stemDownNW: [0, -.164],
					stemUpSE: [1.172, .168]
				},
				noteheadSquareBlack: {
					stemDownNW: [0, -.5],
					stemUpSE: [1.252, .5]
				},
				noteheadSquareBlackLarge: {
					stemDownNW: [0, 0],
					stemUpSE: [2, 0]
				},
				noteheadSquareBlackWhite: {
					stemDownNW: [0, -1],
					stemUpSE: [2, 1]
				},
				noteheadSquareWhite: {
					stemDownNW: [0, -.5],
					stemUpSE: [1.252, .5]
				},
				noteheadTriangleDownBlack: {
					stemDownNW: [0, .5],
					stemUpSE: [1.168, .5]
				},
				noteheadTriangleDownDoubleWhole: { noteheadOrigin: [.384, 0] },
				noteheadTriangleDownHalf: {
					stemDownNW: [0, .464],
					stemUpSE: [1.14, .464]
				},
				noteheadTriangleRightBlack: {
					stemDownNW: [0, -.5],
					stemUpSE: [1.356, .5]
				},
				noteheadTriangleRightWhite: {
					stemDownNW: [0, -.5],
					stemUpSE: [1.356, .5]
				},
				noteheadTriangleUpBlack: {
					stemDownNW: [0, -.5],
					stemUpSE: [1.172, -.5]
				},
				noteheadTriangleUpDoubleWhole: { noteheadOrigin: [.34, 0] },
				noteheadTriangleUpHalf: {
					stemDownNW: [0, -.46],
					stemUpSE: [1.14, -.46]
				},
				noteheadWhole: {
					cutOutNW: [.172, .332],
					cutOutSE: [1.532, -.364]
				},
				noteheadXBlack: {
					stemDownNW: [0, -.44],
					stemUpSE: [1.16, .444]
				},
				noteheadXDoubleWhole: { noteheadOrigin: [.348, 0] },
				noteheadXHalf: {
					stemDownNW: [0, -.412],
					stemUpSE: [1.336, .412]
				},
				noteheadXOrnate: {
					stemDownNW: [0, -.312],
					stemUpSE: [.988, .316]
				},
				wiggleSawtooth: { repeatOffset: [2.992, 0] },
				wiggleSawtoothNarrow: { repeatOffset: [1.996, 0] },
				wiggleTrill: { repeatOffset: [.948, 0] },
				wiggleVibratoMediumFast: { repeatOffset: [1.18, 0] }
			}
		};
	};
	//#endregion
	//#region src/model/Font.ts
	/**
	* A very basic font parser which parses the fields according to
	* https://www.w3.org/TR/CSS21/fonts.html#propdef-font
	* @internal
	*/
	var FontParserToken = class {
		startPos;
		endPos;
		text;
		constructor(text, startPos, endPos) {
			this.text = text;
			this.startPos = startPos;
			this.endPos = endPos;
		}
	};
	/**
	* @internal
	*/
	var FontParser = class FontParser {
		style = "normal";
		variant = "normal";
		weight = "normal";
		stretch = "normal";
		lineHeight = "normal";
		size = "1rem";
		families = [];
		parseOnlyFamilies = false;
		_tokens;
		_currentTokenIndex = -1;
		_input = "";
		_currentToken = null;
		constructor(input) {
			this._input = input;
			this._tokens = this._splitToTokens(input);
		}
		_splitToTokens(input) {
			const tokens = [];
			let startPos = 0;
			while (startPos < input.length) {
				let endPos = startPos;
				while (endPos < input.length && input.charAt(endPos) !== " ") endPos++;
				if (endPos > startPos) tokens.push(new FontParserToken(input.substring(startPos, endPos), startPos, endPos));
				startPos = endPos + 1;
			}
			return tokens;
		}
		parse() {
			this._reset();
			if (this._tokens.length === 1) switch (this._currentToken?.text) {
				case "caption":
				case "icon":
				case "menu":
				case "message-box":
				case "small-caption":
				case "status-bar":
				case "inherit": return;
			}
			if (!this.parseOnlyFamilies) {
				this._fontStyleVariantWeight();
				this._fontSizeLineHeight();
			}
			this._fontFamily();
		}
		static parseFamilies(value) {
			const parser = new FontParser(value);
			parser.parseOnlyFamilies = true;
			parser.parse();
			return parser.families;
		}
		_fontFamily() {
			if (!this._currentToken) {
				if (this.parseOnlyFamilies) return;
				throw new Error("Missing font list");
			}
			const familyListInput = this._input.substr(this._currentToken.startPos).trim();
			let pos = 0;
			while (pos < familyListInput.length) {
				const c = familyListInput.charAt(pos);
				if (c === " " || c === ",") pos++;
				else if (c === "\"" || c === "'") {
					const endOfString = this._findEndOfQuote(familyListInput, pos + 1, c);
					this.families.push(familyListInput.substring(pos + 1, endOfString).split(`\\${c}`).join(c));
					pos = endOfString + 1;
				} else {
					const endOfString = this._findEndOfQuote(familyListInput, pos + 1, ",");
					this.families.push(familyListInput.substring(pos, endOfString).trim());
					pos = endOfString + 1;
				}
			}
		}
		_findEndOfQuote(s, pos, quoteChar) {
			let escaped = false;
			while (pos < s.length) {
				const c = s.charAt(pos);
				if (!escaped && c === quoteChar) return pos;
				if (!escaped && c === "\\") escaped = true;
				else escaped = false;
				pos += 1;
			}
			return s.length;
		}
		_fontSizeLineHeight() {
			if (!this._currentToken) throw new Error("Missing font size");
			const parts = this._currentToken.text.split("/");
			if (parts.length >= 3) throw new Error(`Invalid font size '${this._currentToken}' specified`);
			this._nextToken();
			if (parts.length >= 2) if (parts[1] === "/") {
				if (!this._currentToken) throw new Error("Missing line-height after font size");
				this.lineHeight = this._currentToken.text;
				this._nextToken();
			} else {
				this.size = parts[0];
				this.lineHeight = parts[1];
			}
			else if (parts.length >= 1) {
				this.size = parts[0];
				if (this._currentToken && this._currentToken.text.indexOf("/") === 0) if (this._currentToken.text === "/") {
					this._nextToken();
					if (!this._currentToken) throw new Error("Missing line-height after font size");
					this.lineHeight = this._currentToken.text;
					this._nextToken();
				} else {
					this.lineHeight = this._currentToken.text.substr(1);
					this._nextToken();
				}
			} else throw new Error("Missing font size");
		}
		_nextToken() {
			this._currentTokenIndex++;
			if (this._currentTokenIndex < this._tokens.length) this._currentToken = this._tokens[this._currentTokenIndex];
			else this._currentToken = null;
		}
		_fontStyleVariantWeight() {
			let hasStyle = false;
			let hasVariant = false;
			let hasWeight = false;
			let valuesNeeded = 3;
			const ambiguous = [];
			while (true) {
				if (!this._currentToken) return;
				const text = this._currentToken.text;
				switch (text) {
					case "normal":
					case "inherit":
						ambiguous.push(text);
						valuesNeeded--;
						this._nextToken();
						break;
					case "italic":
					case "oblique":
						this.style = text;
						hasStyle = true;
						valuesNeeded--;
						this._nextToken();
						break;
					case "small-caps":
						this.variant = text;
						hasVariant = true;
						valuesNeeded--;
						this._nextToken();
						break;
					case "bold":
					case "bolder":
					case "lighter":
					case "100":
					case "200":
					case "300":
					case "400":
					case "500":
					case "600":
					case "700":
					case "800":
					case "900":
						this.weight = text;
						hasWeight = true;
						valuesNeeded--;
						this._nextToken();
						break;
					default: return;
				}
				if (valuesNeeded === 0) break;
			}
			while (ambiguous.length > 0) {
				const v = ambiguous.pop();
				if (!hasWeight) this.weight = v;
				else if (!hasVariant) this.variant = v;
				else if (!hasStyle) this.style = v;
			}
		}
		_reset() {
			this._currentTokenIndex = -1;
			this._nextToken();
		}
		static quoteFont(f) {
			if (f.indexOf(" ") === -1) return f;
			return `"${f.replaceAll("\"", "\\\"")}"`;
		}
	};
	/**
	* Lists all flags for font styles.
	* @public
	*/
	var FontStyle = /* @__PURE__ */ function(FontStyle) {
		/**
		* No flags.
		*/
		FontStyle[FontStyle["Plain"] = 0] = "Plain";
		/**
		* Font is italic.
		*/
		FontStyle[FontStyle["Italic"] = 1] = "Italic";
		return FontStyle;
	}({});
	/**
	* Lists all font weight values.
	* @public
	*/
	var FontWeight = /* @__PURE__ */ function(FontWeight) {
		/**
		* Not bold
		*/
		FontWeight[FontWeight["Regular"] = 0] = "Regular";
		/**
		* Font is bold
		*/
		FontWeight[FontWeight["Bold"] = 1] = "Bold";
		return FontWeight;
	}({});
	/**
	* @json_immutable
	* @public
	*/
	var Font = class Font {
		_css;
		_cssScale = 0;
		_families;
		_style;
		_weight;
		_size;
		_reset() {
			this._cssScale = 0;
			this._css = this.toCssString();
		}
		/**
		* Gets the first font family name.
		* @deprecated Consider using {@link families} for multi font family support.
		*/
		get family() {
			return this._families[0];
		}
		/**
		* Sets the font family list.
		* @deprecated Consider using {@link families} for multi font family support.
		*/
		set family(value) {
			this.families = FontParser.parseFamilies(value);
		}
		/**
		* Gets the font family name.
		*/
		get families() {
			return this._families;
		}
		/**
		* Sets the font family name.
		*/
		set families(value) {
			this._families = value;
			this._reset();
		}
		/**
		* Gets the font size in pixels.
		*/
		get size() {
			return this._size;
		}
		/**
		* Sets the font size in pixels.
		*/
		set size(value) {
			this._size = value;
			this._reset();
		}
		/**
		* Gets the font style.
		*/
		get style() {
			return this._style;
		}
		/**
		* Sets the font style.
		*/
		set style(value) {
			this._style = value;
			this._reset();
		}
		/**
		* Gets the font weight.
		*/
		get weight() {
			return this._weight;
		}
		/**
		* Gets or sets the font weight.
		*/
		set weight(value) {
			this._weight = value;
			this._reset();
		}
		get isBold() {
			return this.weight === 1;
		}
		get isItalic() {
			return this.style === 1;
		}
		/**
		* Initializes a new instance of the {@link Font} class.
		* @param family The family.
		* @param size The size.
		* @param style The style.
		* @param weight The weight.
		*/
		constructor(family, size, style = 0, weight = 0) {
			this._families = FontParser.parseFamilies(family);
			this._size = size;
			this._style = style;
			this._weight = weight;
			this._css = this.toCssString();
		}
		withSize(newSize) {
			return Font.withFamilyList(this._families, newSize, this._style, this._weight);
		}
		/**
		* Initializes a new instance of the {@link Font} class.
		* @param families The families.
		* @param size The size.
		* @param style The style.
		* @param weight The weight.
		*/
		static withFamilyList(families, size, style = 0, weight = 0) {
			const f = new Font("", size, style, weight);
			f.families = families;
			return f;
		}
		toCssString(scale = 1) {
			if (!this._css || !(Math.abs(scale - this._cssScale) < .01)) {
				let buf = "";
				if (this.isBold) buf += "bold ";
				if (this.isItalic) buf += "italic ";
				buf += this.size * scale;
				buf += "px ";
				buf += this.families.map((f) => FontParser.quoteFont(f)).join(", ");
				this._css = buf;
				this._cssScale = scale;
			}
			return this._css;
		}
		static fromJson(v) {
			if (v instanceof Font) return v;
			switch (typeof v) {
				case "undefined": return;
				case "object": {
					const m = v;
					const families = m.get("families");
					const size = m.get("size");
					const style = JsonHelper.parseEnum(m.get("style"), FontStyle);
					const weight = JsonHelper.parseEnum(m.get("weight"), FontWeight);
					return Font.withFamilyList(families, size, style, weight);
				}
				case "string": {
					const parser = new FontParser(v);
					parser.parse();
					const families = parser.families;
					const fontSizeString = parser.size.toLowerCase();
					let fontSize = 0;
					switch (fontSizeString) {
						case "xx-small":
							fontSize = 7;
							break;
						case "x-small":
							fontSize = 10;
							break;
						case "small":
						case "smaller":
							fontSize = 13;
							break;
						case "medium":
							fontSize = 16;
							break;
						case "large":
						case "larger":
							fontSize = 18;
							break;
						case "x-large":
							fontSize = 24;
							break;
						case "xx-large":
							fontSize = 32;
							break;
						default:
							try {
								if (fontSizeString.endsWith("em")) fontSize = Number.parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)) * 16;
								else if (fontSizeString.endsWith("pt")) fontSize = Number.parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)) * 16 / 12;
								else if (fontSizeString.endsWith("px")) fontSize = Number.parseFloat(fontSizeString.substr(0, fontSizeString.length - 2));
								else fontSize = 12;
							} catch {
								fontSize = 12;
							}
							break;
					}
					let fontStyle = 0;
					if (parser.style === "italic") fontStyle = 1;
					let fontWeight = 0;
					switch (parser.weight.toLowerCase()) {
						case "normal":
						case "lighter": break;
						default:
							fontWeight = 1;
							break;
					}
					return Font.withFamilyList(families, fontSize, fontStyle, fontWeight);
				}
				default: return;
			}
		}
		static toJson(font) {
			if (!font) return;
			const o = /* @__PURE__ */ new Map();
			o.set("families", font.families);
			o.set("size", font.size);
			o.set("style", font.style);
			o.set("weight", font.weight);
			return o;
		}
	};
	//#endregion
	//#region src/RenderingResources.ts
	/**
	* This public class contains central definitions for controlling the visual appearance.
	* @json
	* @json_declaration
	* @public
	*/
	var RenderingResources = class RenderingResources {
		static _sansFont = "Arial, sans-serif";
		static _serifFont = "Georgia, serif";
		static _effectFont = new Font(RenderingResources._serifFont, 12, FontStyle.Italic);
		/**
		* The default fonts for notation elements if not specified by the user.
		*/
		static defaultFonts = new Map([
			[NotationElement.ScoreTitle, new Font(RenderingResources._serifFont, 32, FontStyle.Plain)],
			[NotationElement.ScoreSubTitle, new Font(RenderingResources._serifFont, 20, FontStyle.Plain)],
			[NotationElement.ScoreArtist, new Font(RenderingResources._serifFont, 20, FontStyle.Plain)],
			[NotationElement.ScoreAlbum, new Font(RenderingResources._serifFont, 20, FontStyle.Plain)],
			[NotationElement.ScoreWords, new Font(RenderingResources._serifFont, 15, FontStyle.Plain)],
			[NotationElement.ScoreMusic, new Font(RenderingResources._serifFont, 15, FontStyle.Plain)],
			[NotationElement.ScoreWordsAndMusic, new Font(RenderingResources._serifFont, 15, FontStyle.Plain)],
			[NotationElement.ScoreCopyright, new Font(RenderingResources._sansFont, 12, FontStyle.Plain, FontWeight.Bold)],
			[NotationElement.EffectBeatTimer, new Font(RenderingResources._serifFont, 12, FontStyle.Plain)],
			[NotationElement.EffectDirections, new Font(RenderingResources._serifFont, 14, FontStyle.Plain)],
			[NotationElement.ChordDiagramFretboardNumbers, new Font(RenderingResources._sansFont, 11, FontStyle.Plain)],
			[NotationElement.EffectFingering, new Font(RenderingResources._serifFont, 14, FontStyle.Plain)],
			[NotationElement.EffectMarker, new Font(RenderingResources._serifFont, 14, FontStyle.Plain, FontWeight.Bold)],
			[NotationElement.EffectCapo, RenderingResources._effectFont],
			[NotationElement.EffectFreeTime, RenderingResources._effectFont],
			[NotationElement.EffectLyrics, RenderingResources._effectFont],
			[NotationElement.EffectTap, RenderingResources._effectFont],
			[NotationElement.ChordDiagrams, RenderingResources._effectFont],
			[NotationElement.EffectChordNames, RenderingResources._effectFont],
			[NotationElement.EffectText, RenderingResources._effectFont],
			[NotationElement.EffectPalmMute, RenderingResources._effectFont],
			[NotationElement.EffectLetRing, RenderingResources._effectFont],
			[NotationElement.EffectBeatBarre, RenderingResources._effectFont],
			[NotationElement.EffectTripletFeel, RenderingResources._effectFont],
			[NotationElement.EffectHarmonics, RenderingResources._effectFont],
			[NotationElement.EffectPickSlide, RenderingResources._effectFont],
			[NotationElement.GuitarTuning, RenderingResources._effectFont],
			[NotationElement.EffectRasgueado, RenderingResources._effectFont],
			[NotationElement.EffectWhammyBar, RenderingResources._effectFont],
			[NotationElement.TrackNames, RenderingResources._effectFont],
			[NotationElement.RepeatCount, new Font(RenderingResources._sansFont, 11, FontStyle.Plain)],
			[NotationElement.BarNumber, new Font(RenderingResources._sansFont, 11, FontStyle.Plain)],
			[NotationElement.ScoreBendSlur, new Font(RenderingResources._sansFont, 11, FontStyle.Plain)],
			[NotationElement.EffectAlternateEndings, new Font(RenderingResources._serifFont, 15, FontStyle.Plain)],
			[NotationElement.EffectHammerOnPullOffText, RenderingResources._effectFont],
			[NotationElement.EffectSlideText, RenderingResources._effectFont]
		]);
		/**
		* The name of the SMuFL Font to use for rendering music symbols.
		*
		* @remarks
		* If this family name is provided, alphaTab will not load any custom font, but expects
		* this font to be available in your environment (loadad as webfont or registered in alphaSkia).
		*
		* When using alphaTab in a browser environment it is rather recommended to specify the web font
		* via the `smuflFontSources` on the `CoreSettings`and skipping this setting.
		*
		* You will also need to fill {@link engravingSettings} to match this font.
		*
		* @since 1.7.0
		* @internal
		*/
		smuflFontFamilyName;
		/**
		* The SMuFL Metrics to use for rendering music symbols.
		* @defaultValue `alphaTab`
		* @since 1.7.0
		*/
		engravingSettings = EngravingSettings.bravuraDefaults;
		/**
		* The font to use for displaying the songs copyright information in the header of the music sheet.
		* @defaultValue `bold 12px Arial, sans-serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreCopyright}
		*/
		get copyrightFont() {
			return this.elementFonts.get(NotationElement.ScoreCopyright);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreCopyright}
		*/
		set copyrightFont(value) {
			this.elementFonts.set(NotationElement.ScoreCopyright, value);
		}
		/**
		* The font to use for displaying the songs title in the header of the music sheet.
		* @defaultValue `32px Georgia, serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreTitle}
		*/
		get titleFont() {
			return this.elementFonts.get(NotationElement.ScoreTitle);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreTitle}
		*/
		set titleFont(value) {
			this.elementFonts.set(NotationElement.ScoreTitle, value);
		}
		/**
		* The font to use for displaying the songs subtitle in the header of the music sheet.
		* @defaultValue `20px Georgia, serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreSubTitle}
		*/
		get subTitleFont() {
			return this.elementFonts.get(NotationElement.ScoreSubTitle);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreSubTitle}
		*/
		set subTitleFont(value) {
			this.elementFonts.set(NotationElement.ScoreSubTitle, value);
		}
		/**
		* The font to use for displaying the lyrics information in the header of the music sheet.
		* @defaultValue `15px Arial, sans-serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreWords}
		*/
		get wordsFont() {
			return this.elementFonts.get(NotationElement.ScoreWords);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.ScoreWords}
		*/
		set wordsFont(value) {
			this.elementFonts.set(NotationElement.ScoreWords, value);
		}
		/**
		* The font to use for displaying beat time information in the music sheet.
		* @defaultValue `12px Georgia, serif`
		* @since 1.4.0
		* @deprecated use {@link elementFonts} with {@link NotationElement.EffectBeatTimer}
		*/
		get timerFont() {
			return this.elementFonts.get(NotationElement.EffectBeatTimer);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.EffectBeatTimer}
		*/
		set timerFont(value) {
			this.elementFonts.set(NotationElement.EffectBeatTimer, value);
		}
		/**
		* The font to use for displaying the directions texts.
		* @defaultValue `14px Georgia, serif`
		* @since 1.4.0
		* @deprecated use {@link elementFonts} with {@link NotationElement.EffectDirections}
		*/
		get directionsFont() {
			return this.elementFonts.get(NotationElement.EffectDirections);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.EffectDirections}
		*/
		set directionsFont(value) {
			this.elementFonts.set(NotationElement.EffectDirections, value);
		}
		/**
		* The font to use for displaying the fretboard numbers in chord diagrams.
		* @defaultValue `11px Arial, sans-serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with {@link NotationElement.ChordDiagramFretboardNumbers}
		*/
		get fretboardNumberFont() {
			return this.elementFonts.get(NotationElement.ChordDiagramFretboardNumbers);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.ChordDiagramFretboardNumbers}
		*/
		set fretboardNumberFont(value) {
			this.elementFonts.set(NotationElement.ChordDiagramFretboardNumbers, value);
		}
		/**
		* Unused, see deprecation note.
		* @defaultValue `14px Georgia, serif`
		* @since 0.9.6
		* @deprecated Since 1.7.0 alphaTab uses the glyphs contained in the SMuFL font
		* @json_ignore
		*/
		fingeringFont = RenderingResources._effectFont;
		/**
		* Unused, see deprecation note.
		* @defaultValue `12px Georgia, serif`
		* @since 1.4.0
		* @deprecated Since 1.7.0 alphaTab uses the glyphs contained in the SMuFL font
		* @json_ignore
		*/
		inlineFingeringFont = RenderingResources._effectFont;
		/**
		* The font to use for section marker labels shown above the music sheet.
		* @defaultValue `bold 14px Georgia, serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with {@link NotationElement.EffectMarker}
		*/
		get markerFont() {
			return this.elementFonts.get(NotationElement.EffectMarker);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.EffectMarker}
		*/
		set markerFont(value) {
			this.elementFonts.set(NotationElement.EffectMarker, value);
		}
		/**
		* Ununsed, see deprecation note.
		* @defaultValue `italic 12px Georgia, serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with the respective
		* @json_ignore
		*/
		effectFont = RenderingResources._effectFont;
		/**
		* The font to use for displaying the bar numbers above the music sheet.
		* @defaultValue `11px Arial, sans-serif`
		* @since 0.9.6
		* @deprecated use {@link elementFonts} with {@link NotationElement.BarNumber}
		*/
		get barNumberFont() {
			return this.elementFonts.get(NotationElement.BarNumber);
		}
		/**
		* @deprecated use {@link elementFonts} with {@link NotationElement.BarNumber}
		*/
		set barNumberFont(value) {
			this.elementFonts.set(NotationElement.BarNumber, value);
		}
		/**
		* The fonts used by individual elements. Check `defaultFonts` for the elements which have custom fonts.
		* Removing fonts from this map can lead to unexpected side effects and errors. Only update it with new values.
		* @json_immutable
		*/
		elementFonts = /* @__PURE__ */ new Map();
		/**
		* The font to use for displaying the numbered music notation in the music sheet.
		* @defaultValue `14px Arial, sans-serif`
		* @since 1.4.0
		*/
		numberedNotationFont = new Font(RenderingResources._sansFont, 16, FontStyle.Plain);
		/**
		* The font to use for displaying the grace notes in numbered music notation in the music sheet.
		* @defaultValue `16px Arial, sans-serif`
		* @since 1.4.0
		*/
		numberedNotationGraceFont = new Font(RenderingResources._sansFont, 14, FontStyle.Plain);
		/**
		* The font to use for displaying the guitar tablature numbers in the music sheet.
		* @defaultValue `13px Arial, sans-serif`
		* @since 0.9.6
		*/
		tablatureFont = new Font(RenderingResources._sansFont, 14, FontStyle.Plain);
		/**
		* The font to use for grace notation related texts in the music sheet.
		* @defaultValue `11px Arial, sans-serif`
		* @since 0.9.6
		*/
		graceFont = new Font(RenderingResources._sansFont, 12, FontStyle.Plain);
		/**
		* The color to use for rendering the lines of staves.
		* @defaultValue `rgb(165, 165, 165)`
		* @since 0.9.6
		*/
		staffLineColor = new Color(165, 165, 165, 255);
		/**
		* The color to use for rendering bar separators, the accolade and repeat signs.
		* @defaultValue `rgb(34, 34, 17)`
		* @since 0.9.6
		*/
		barSeparatorColor = new Color(34, 34, 17, 255);
		/**
		* The color to use for displaying the bar numbers above the music sheet.
		* @defaultValue `rgb(200, 0, 0)`
		* @since 0.9.6
		*/
		barNumberColor = new Color(200, 0, 0, 255);
		/**
		* The color to use for music notation elements of the primary voice.
		* @defaultValue `rgb(0, 0, 0)`
		* @since 0.9.6
		*/
		mainGlyphColor = new Color(0, 0, 0, 255);
		/**
		* The color to use for music notation elements of the secondary voices.
		* @defaultValue `rgb(0,0,0,0.4)`
		* @since 0.9.6
		*/
		secondaryGlyphColor = new Color(0, 0, 0, 100);
		/**
		* The color to use for displaying the song information above the music sheets.
		* @defaultValue `rgb(0, 0, 0)`
		* @since 0.9.6
		*/
		scoreInfoColor = new Color(0, 0, 0, 255);
		constructor() {
			for (const [k, v] of RenderingResources.defaultFonts) this.elementFonts.set(k, v.withSize(v.size));
		}
		/**
		* @internal
		* @param element
		*/
		getFontForElement(element) {
			let notationElement = NotationElement.ScoreWords;
			switch (element) {
				case ScoreSubElement.Title:
					notationElement = NotationElement.ScoreTitle;
					break;
				case ScoreSubElement.SubTitle:
					notationElement = NotationElement.ScoreSubTitle;
					break;
				case ScoreSubElement.Artist:
					notationElement = NotationElement.ScoreArtist;
					break;
				case ScoreSubElement.Album:
					notationElement = NotationElement.ScoreAlbum;
					break;
				case ScoreSubElement.Words:
					notationElement = NotationElement.ScoreWords;
					break;
				case ScoreSubElement.Music:
					notationElement = NotationElement.ScoreMusic;
					break;
				case ScoreSubElement.WordsAndMusic:
					notationElement = NotationElement.ScoreWordsAndMusic;
					break;
				case ScoreSubElement.Copyright:
				case ScoreSubElement.CopyrightSecondLine:
					notationElement = NotationElement.ScoreCopyright;
					break;
				default:
					notationElement = NotationElement.ScoreWords;
					break;
			}
			return this.getFontForNotationElement(notationElement);
		}
		/**
		* @internal
		* @param element
		*/
		getFontForNotationElement(notationElement) {
			return this.elementFonts.has(notationElement) ? this.elementFonts.get(notationElement) : RenderingResources.defaultFonts.get(notationElement);
		}
	};
	//#endregion
	//#region src/StaveProfile.ts
	/**
	* Lists all stave profiles controlling which staves are shown.
	* @public
	*/
	var StaveProfile = /* @__PURE__ */ 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";
		return StaveProfile;
	}({});
	//#endregion
	//#region src/DisplaySettings.ts
	/**
	* Lists the different modes in which the staves and systems are arranged.
	* @public
	*/
	var SystemsLayoutMode = /* @__PURE__ */ function(SystemsLayoutMode) {
		/**
		* Use the automatic alignment system provided by alphaTab (default)
		*/
		SystemsLayoutMode[SystemsLayoutMode["Automatic"] = 0] = "Automatic";
		/**
		* Use the systems layout and sizing information stored from the score model.
		*/
		SystemsLayoutMode[SystemsLayoutMode["UseModelLayout"] = 1] = "UseModelLayout";
		return SystemsLayoutMode;
	}({});
	/**
	* The display settings control how the general layout and display of alphaTab is done.
	* @json
	* @json_declaration
	* @public
	*/
	var DisplaySettings = class {
		/**
		* The zoom level of the rendered notation.
		* @since 0.9.6
		* @category Display
		* @defaultValue `1.0`
		* @remarks
		* AlphaTab can scale up or down the rendered music notation for more optimized display scenarios. By default music notation is rendered at 100% scale (value 1) and can be scaled up or down by
		* percental values.
		*/
		scale = 1;
		/**
		* The default stretch force to use for layouting.
		* @since 0.9.6
		* @category Display
		* @defaultValue `1`
		* @remarks
		* The stretch force is a setting that controls the spacing of the music notation. AlphaTab uses a varaint of the Gourlay algorithm for spacing which has springs and rods for
		* aligning elements. This setting controls the "strength" of the springs. The stronger the springs, the wider the spacing.
		*
		* | Force 1                                                      | Force 0.5                                             |
		* |--------------------------------------------------------------|-------------------------------------------------------|
		* | ![Default](https://alphatab.net/img/reference/property/stretchforce-default.png) | ![0.5](https://alphatab.net/img/reference/property/stretchforce-half.png) |
		*/
		stretchForce = 1;
		/**
		* The layouting mode used to arrange the the notation.
		* @remarks
		* AlphaTab has various layout engines that arrange the rendered bars differently. This setting controls which layout mode is used.
		*
		* @since 0.9.6
		* @category Display
		* @defaultValue `LayoutMode.Page`
		*/
		layoutMode = LayoutMode.Page;
		/**
		* The stave profile defining which staves are shown for the music sheet.
		* @since 0.9.6
		* @category Display
		* @defaultValue `StaveProfile.Default`
		* @remarks
		* AlphaTab has various stave profiles that define which staves will be shown in for the rendered tracks. Its recommended
		* to keep this on {@link StaveProfile.Default} and rather rely on the options available ob {@link Staff} level
		* @deprecated Set the notation visibility by modifying the {@link Staff} properties.
		*/
		staveProfile = StaveProfile.Default;
		/**
		* Limit the displayed bars per system (row). (-1 for automatic mode)
		* @since 0.9.6
		* @category Display
		* @defaultValue `-1`
		* @remarks
		* This setting sets the number of bars that should be put into one row during layouting. This setting is only respected
		* when using the {@link LayoutMode.Page} where bars are aligned in systems. [Demo](https://alphatab.net/docs/showcase/layouts#page-layout-5-bars-per-row).
		*/
		barsPerRow = -1;
		/**
		* The bar start index to start layouting with.
		* @since 0.9.6
		* @category Display
		* @defaultValue `1`
		* @remarks
		* This setting sets the index of the first bar that should be rendered from the overall song. This setting can be used to
		* achieve a paging system or to only show partial bars of the same file. By this a tutorial alike display can be achieved
		* that explains various parts of the song. Please note that this is the bar number as shown in the music sheet (1-based) not the array index (0-based).
		* [Demo](https://alphatab.net/docs/showcase/layouts#page-layout-bar-5-to-8)
		*/
		startBar = 1;
		/**
		* The total number of bars that should be rendered from the song. (-1 for all bars)
		* @since 0.9.6
		* @category Display
		* @defaultValue `-1`
		* @remarks
		* This setting sets the number of bars that should be rendered from the overall song. This setting can be used to
		* achieve a paging system or to only show partial bars of the same file. By this a tutorial alike display can be achieved
		* that explains various parts of the song. [Demo](https://alphatab.net/docs/showcase/layouts)
		*/
		barCount = -1;
		/**
		* The number of bars that should be placed within one partial render.
		* @since 0.9.6
		* @category Display
		* @defaultValue `10`
		* @remarks
		* AlphaTab renders the whole music sheet in smaller chunks named "partials". This is to reduce the risk of
		* encountering browser performance restrictions and it gives faster visual feedback to the user. This
		* setting controls how many bars are placed within such a partial.
		*/
		barCountPerPartial = 10;
		/**
		* Whether to justify also the last system in page layouts.
		* @remarks
		* Setting this option to `true` tells alphaTab to also justify the last system (row) like it
		* already does for the systems which are full.
		* | Justification Disabled                                       | Justification Enabled                                |
		* |--------------------------------------------------------------|-------------------------------------------------------|
		* | ![Disabled](https://alphatab.net/img/reference/property/justify-last-system-false.png) | ![Enabled](https://alphatab.net/img/reference/property/justify-last-system-true.png) |
		* @since 1.3.0
		* @category Display
		* @defaultValue `false`
		*/
		justifyLastSystem = false;
		/**
		* Allows adjusting of the used fonts and colors for rendering.
		* @json_partial_names
		* @since 0.9.6
		* @category Display
		* @defaultValue `false`
		* @domWildcard
		* @remarks
		* AlphaTab allows configuring the colors and fonts used for rendering via the rendering resources settings. Please note that as of today
		* this is the primary way of changing the way how alphaTab styles elements. CSS styling in the browser cannot be guaranteed to work due to its flexibility.
		*
		*
		* Due to space reasons in the following table the common prefix of the settings are removed. Please refer to these examples to eliminate confusion on the usage:
		*
		* | Platform   | Prefix                    | Example Usage                                                      |
		* |------------|---------------------------|--------------------------------------------------------------------|
		* | JavaScript | `display.resources.`      | `settings.display.resources.wordsFont = ...`                       |
		* | JSON       | `display.resources.`      | `var settings = { display: { resources: { wordsFonts: '...'} } };` |
		* | JSON       | `resources.`              | `var settings = { resources: { wordsFonts: '...'} };`              |
		* | .net       | `Display.Resources.`      | `settings.Display.Resources.WordsFonts = ...`                      |
		* | Android    | `display.resources.`      | `settings.display.resources.wordsFonts = ...`                      |
		* ## Types
		*
		* ### Fonts
		*
		* For the JavaScript platform any font that might be installed on the client machines can be used.
		* Any additional fonts can be added via WebFonts. The rendering of the score will be delayed until it is detected that the font was loaded.
		* Simply use any CSS font property compliant string as configuration. Relative font sizes with percentual values are not supported, remaining values will be considered if supported.
		*
		* {@since 1.2.3} Multiple fonts are also supported for the Web version. alphaTab will check if any of the fonts in the list is loaded instead of all. If none is available at the time alphaTab is initialized, it will try to initiate the load of the specified fonts individual through the Browser Font APIs.
		*
		* For the .net platform any installed font on the system can be used. Simply construct the `Font` object to configure your desired fonts.
		*
		* ### Colors
		*
		* For JavaScript you can use any CSS font property compliant string. (#RGB, #RGBA, #RRGGBB, #RRGGBBAA, rgb(r,g,b), rgba(r,g,b,a) )
		*
		* On .net simply construct the `Color` object to configure your desired color.
		*/
		resources = new RenderingResources();
		/**
		* Adjusts the padding between the music notation and the border.
		* @remarks
		* Adjusts the padding between the music notation and the outer border of the container element.
		* The array is either:
		* * 2 elements: `[left-right, top-bottom]`
		* * 4 elements: ``[left, top, right, bottom]``
		* @since 0.9.6
		* @category Display
		* @defaultValue `[35, 35]`
		*/
		padding = [35, 35];
		/**
		* The top padding applied to first system.
		* @since 1.4.0
		* @category Display
		* @defaultValue `0`
		*/
		firstSystemPaddingTop = 0;
		/**
		* The top padding applied systems beside the first one.
		* @since 1.4.0
		* @category Display
		* @defaultValue `10`
		*/
		systemPaddingTop = 10;
		/**
		* The bottom padding applied to systems beside the last one.
		* @since 1.4.0
		* @category Display
		* @defaultValue `10`
		*/
		systemPaddingBottom = 10;
		/**
		* The bottom padding applied to the last system.
		* @since 1.4.0
		* @category Display
		* @defaultValue `5`
		*/
		lastSystemPaddingBottom = 5;
		/**
		* The padding left to the track name label of the system.
		* @since 1.4.0
		* @category Display
		* @defaultValue `0`
		*/
		systemLabelPaddingLeft = 0;
		/**
		* The padding left to the track name label of the system.
		* @since 1.4.0
		* @category Display
		* @defaultValue `3`
		*/
		systemLabelPaddingRight = 3;
		/**
		* The padding between the accolade bar and the start of the bar itself.
		* @since 1.4.0
		* @category Display
		* @defaultValue `3`
		*/
		accoladeBarPaddingRight = 3;
		/**
		* The top padding applied to the first main notation staff (standard, tabs, numbered, slash).
		* @since 1.8.0
		* @category Display
		* @defaultValue `0`
		*/
		firstNotationStaffPaddingTop = 0;
		/**
		* The bottom padding applied to last main notation staff (standard, tabs, numbered, slash).
		* @since 1.8.0
		* @category Display
		* @defaultValue `0`
		*/
		lastNotationStaffPaddingBottom = 0;
		/**
		* The top padding applied to main notation staves (standard, tabs, numbered, slash).
		* @since 1.4.0
		* @category Display
		* @defaultValue `0`
		*/
		notationStaffPaddingTop = 0;
		/**
		* The bottom padding applied to main notation staves (standard, tabs, numbered, slash).
		* @since 1.4.0
		* @category Display
		* @defaultValue `0`
		*/
		notationStaffPaddingBottom = 0;
		/**
		* The top padding applied to effect annotation staffs.
		* @since 1.4.0
		* @category Display
		* @defaultValue `0`
		* @deprecated Effect staves do not exist anymore, effects are now part of the main notation staves. This value has no effect anymore.
		* Use {@link effectBandPaddingBottom} to control the padding after effect bands.
		*/
		effectStaffPaddingTop = 0;
		/**
		* The bottom padding applied to effect annotation staffs.
		* @since 1.4.0
		* @category Display
		* @defaultValue `0`
		* @deprecated Effect staves do not exist anymore, effects are now part of the main notation staves. This value has no effect anymore.
		* Use {@link effectBandPaddingBottom} to control the padding after effect bands.
		*/
		effectStaffPaddingBottom = 0;
		/**
		* The left padding applied between the left line and the first glyph in the first staff in a system.
		* @since 1.4.0
		* @category Display
		* @defaultValue `6`
		*/
		firstStaffPaddingLeft = 6;
		/**
		* The left padding applied between the left line and the first glyph in the following staff in a system.
		* @since 1.4.0
		* @category Display
		* @defaultValue `2`
		*/
		staffPaddingLeft = 2;
		/**
		* The padding between individual effect bands.
		* @since 1.7.0
		* @category Display
		* @defaultValue `2`
		*/
		effectBandPaddingBottom = 2;
		/**
		* The additional padding to apply between the staves of two separate tracks.
		* @since 1.8.0
		* @category Display
		* @defaultValue `5`
		*/
		trackStaffPaddingBetween = 5;
		/**
		* The additional padding to apply between multiple lyric lines.
		* @since 1.8.0
		* @category Display
		* @defaultValue `5`
		*/
		lyricLinesPaddingBetween = 5;
		/**
		* The mode used to arrange staves and systems.
		* @since 1.3.0
		* @category Display
		* @defaultValue `1`
		* @remarks
		* By default alphaTab uses an own (automatic) mode to arrange and scale the bars when
		* putting them into staves. This property allows changing this mode to change the music sheet arrangement.
		*
		* ## Supported File Formats:
		* * Guitar Pro 6-8 {@since 1.3.0}
		* If you want/need support for more file formats to respect the sizing information feel free to [open a discussion](https://github.com/CoderLine/alphaTab/discussions/new?category=ideas) on GitHub.
		*
		* ## Automatic Mode
		*
		* In the automatic mode alphaTab arranges the bars and staves using its internal mechanisms.
		*
		* For the `page` layout this means it will scale the bars according to the `stretchForce` and available width.
		* Wrapping into new systems (rows) will happen when the row is considered "full".
		*
		* For the `horizontal` layout the `stretchForce` defines the sizing and no wrapping happens at all.
		*
		* ## Model Layout mode
		*
		* File formats like Guitar Pro embed information about the layout in the file and alphaTab can read and use this information.
		* When this mode is enabled, alphaTab will also actively use this information and try to respect it.
		*
		* alphaTab holds following information in the data model and developers can change those values (e.g. by tapping into the `scoreLoaded`) event.
		*
		* **Used when single tracks are rendered:**
		*
		* * `score.tracks[index].systemsLayout` - An array of numbers describing how many bars should be placed within each system (row).
		* * `score.tracks[index].defaultSystemsLayout` - The number of bars to place in a system (row) when no value is defined in the `systemsLayout`.
		* * `score.tracks[index].staves[index].bars[index].displayScale` - The relative size of this bar in the system it is placed. Note that this is not directly a percentage value. e.g. if there are 3 bars and all define scale 1, they are sized evenly.
		* * `score.tracks[index].staves[index].bars[index].displayWidth` - The absolute size of this bar when displayed.
		*
		* **Used when multiple tracks are rendered:**
		*
		* * `score.systemsLayout` - Like the `systemsLayout` on track level.
		* * `score.defaultSystemsLayout` - Like the `defaultSystemsLayout` on track level.
		* * `score.masterBars[index].displayScale` - Like the `displayScale` on bar level.
		* * `score.masterBars[index].displayWidth` - Like the `displayWidth` on bar level.
		*
		* ### Page Layout
		*
		* The page layout uses the `systemsLayout` and `defaultSystemsLayout` to decide how many bars go into a single system (row).
		* Additionally when sizing the bars within the system the `displayScale` is used. As indicated above, the scale is rather a ratio than a percentage value but percentages work also:
		*
		* ![Page Layout](https://alphatab.net/img/reference/property/systems-layout-page-examples.png)
		*
		* The page layout does not use `displayWidth`. The use of absolute widths would break the proper alignments needed for this kind of display.
		*
		* In both modes, prefix and postfix glyphs (clef, key signature, time signature, barlines) are treated as fixed overhead: they keep their
		* natural size and the remaining staff width is distributed across bars by a per-bar weight. This matches the convention used by
		* Guitar Pro, Dorico, Finale, Sibelius and MuseScore. Bars that carry a system-start prefix or a mid-line clef/key/time-signature change
		* are therefore visibly wider than plain bars with the same weight. The weight source depends on the mode:
		*
		* * `Automatic` (default for `page` layout): weights come from the built-in spacing engine (the natural content width of each bar).
		*   `displayScale` on the model is ignored.
		* * `UseModelLayout` (and the `parchment` layout): weights come from `bar.displayScale` / `masterBar.displayScale`. An unset
		*   `displayScale` defaults to `1` and behaves identically to an explicit `1`, matching Guitar Pro (which omits the value when the
		*   author hasn't customized it).
		*
		* ### Horizontal Layout
		*
		* The horizontal layout uses the `displayWidth` to scale the bars to size the bars exactly as specified. This kind of sizing and layout can be useful for usecases like:
		*
		* * Comparing files against each other (top/bottom comparison)
		* * Aligning the playback of multiple files on one screen assuming the same tempo (e.g. one file per track).
		* @deprecated Use the {@link LayoutMode.Parchment} to display a music sheet respecting the systems layout.
		*/
		systemsLayoutMode = 0;
	};
	//#endregion
	//#region src/ImporterSettings.ts
	/**
	* All settings related to importers that decode file formats.
	* @json
	* @json_declaration
	* @public
	*/
	var ImporterSettings = class {
		/**
		* The text encoding to use when decoding strings.
		* @since 0.9.6
		* @defaultValue `utf-8`
		* @category Importer
		* @remarks
		* By default strings are interpreted as UTF-8 from the input files. This is sometimes not the case and leads to strong display
		* of strings in the rendered notation. Via this setting the text encoding for decoding the strings can be changed. The supported
		* encodings depend on the browser or operating system. This setting is considered for the importers
		*
		* * Guitar Pro 7
		* * Guitar Pro 6
		* * Guitar Pro 3-5
		* * MusicXML
		*/
		encoding = "utf-8";
		/**
		* If part-groups should be merged into a single track (MusicXML).
		* @since 0.9.6
		* @defaultValue `false`
		* @category Importer
		* @remarks
		* This setting controls whether multiple `part-group` tags will result into a single track with multiple staves.
		*/
		mergePartGroupsInMusicXml = false;
		/**
		* Enables detecting lyrics from beat texts
		* @since 1.2.0
		* @category Importer
		* @defaultValue `false`
		* @remarks
		*
		* On various old Guitar Pro 3-5 files tab authors often used the "beat text" feature to add lyrics to the individual tracks.
		* This was easier and quicker than using the lyrics feature.
		*
		* These texts were optimized to align correctly when viewed in Guitar Pro with the default layout but can lead to
		* disturbed display in alphaTab. When `beatTextAsLyrics` is set to true, alphaTab will try to rather parse beat text
		* values as lyrics using typical text patterns like dashes, underscores and spaces.
		*
		* The lyrics are only detected if not already proper lyrics are applied to the track.
		*
		* Enable this option for input files which suffer from this practice.
		*
		* > [!NOTE]
		* > alphaTab tries to relate the texts and chunks to the beats but this is not perfect.
		* > Errors are likely to happen with such kind of files.
		*
		* **Enabled**
		*
		* ![Enabled](https://alphatab.net/img/reference/property/beattextaslyrics-enabled.png)
		*
		* **Disabled**
		*
		* ![Disabled](https://alphatab.net/img/reference/property/beattextaslyrics-disabled.png)
		*/
		beatTextAsLyrics = false;
		/**
		* This setting controls the escape hatch for handling potentially malicous or corrupt
		* input files. At selected spots in the codebase, we use this buffer size as maximum
		* allowed sizes. e.g. during unzipping or decoding strings.
		* This prevents resource exhaustion, especially when alphaTab is used on server side.
		* Increase this buffer size if you need to handle very big files.
		* @defaultValue `128000000`
		* @category Core
		* @since 1.9.0
		*/
		maxDecodingBufferSize = 128e6;
	};
	//#endregion
	//#region src/PlayerSettings.ts
	/**
	* Lists all modes how alphaTab can scroll the container during playback.
	* @public
	*/
	var ScrollMode = /* @__PURE__ */ function(ScrollMode) {
		/**
		* Do not scroll automatically
		*/
		ScrollMode[ScrollMode["Off"] = 0] = "Off";
		/**
		* Scrolling happens as soon the offsets of the cursors change.
		*/
		ScrollMode[ScrollMode["Continuous"] = 1] = "Continuous";
		/**
		* Scrolling happens as soon the cursors exceed the displayed range.
		*/
		ScrollMode[ScrollMode["OffScreen"] = 2] = "OffScreen";
		/**
		* Scrolling happens constantly in a smooth fashion.
		* This will disable the use of any native scroll optimizations but
		* manually scroll the scroll container in the required speed.
		*/
		ScrollMode[ScrollMode["Smooth"] = 3] = "Smooth";
		return ScrollMode;
	}({});
	/**
	* This object defines the details on how to generate the vibrato effects.
	* @json
	* @json_declaration
	* @public
	*/
	var VibratoPlaybackSettings = class {
		/**
		* The wavelength of the note-wide vibrato in midi ticks.
		* @defaultValue `240`
		*/
		noteWideLength = 240;
		/**
		* The amplitude for the note-wide vibrato in semitones.
		* @defaultValue `1`
		*/
		noteWideAmplitude = 1;
		/**
		* The wavelength of the note-slight vibrato in midi ticks.
		* @defaultValue `360`
		*/
		noteSlightLength = 360;
		/**
		* The amplitude for the note-slight vibrato in semitones.
		* @defaultValue `0.5`
		*/
		noteSlightAmplitude = .5;
		/**
		* The wavelength of the beat-wide vibrato in midi ticks.
		* @defaultValue `480`
		*/
		beatWideLength = 480;
		/**
		* The amplitude for the beat-wide vibrato in semitones.
		* @defaultValue `2`
		*/
		beatWideAmplitude = 2;
		/**
		* The wavelength of the beat-slight vibrato in midi ticks.
		* @defaultValue `480`
		*/
		beatSlightLength = 480;
		/**
		* The amplitude for the beat-slight vibrato in semitones.
		* @defaultValue `2`
		*/
		beatSlightAmplitude = 2;
	};
	/**
	* This object defines the details on how to generate the slide effects.
	* @json
	* @json_declaration
	* @public
	*/
	var SlidePlaybackSettings = class {
		/**
		* Gets or sets 1/4 tones (bend value) offset that
		* simple slides like slide-out-below or slide-in-above use.
		* @defaultValue `6`
		*/
		simpleSlidePitchOffset = 6;
		/**
		* The percentage which the simple slides should take up
		* from the whole note. for "slide into" effects the slide will take place
		* from time 0 where the note is plucked to 25% of the overall note duration.
		* For "slide out" effects the slide will start 75% and finish at 100% of the overall
		* note duration.
		* @defaultValue `0.25`
		*/
		simpleSlideDurationRatio = .25;
		/**
		* The percentage which the legato and shift slides should take up
		* from the whole note. For a value 0.5 the sliding will start at 50% of the overall note duration
		* and finish at 100%
		* @defaultValue `0.5`
		*/
		shiftSlideDurationRatio = .5;
	};
	/**
	* Lists the different modes how alphaTab will play the generated audio.
	* @target web
	* @public
	*/
	var PlayerOutputMode = /* @__PURE__ */ function(PlayerOutputMode) {
		/**
		* If audio worklets are available in the browser, they will be used for playing the audio.
		* It will fallback to the ScriptProcessor output if unavailable.
		*/
		PlayerOutputMode[PlayerOutputMode["WebAudioAudioWorklets"] = 0] = "WebAudioAudioWorklets";
		/**
		* Uses the legacy ScriptProcessor output which might perform worse.
		*/
		PlayerOutputMode[PlayerOutputMode["WebAudioScriptProcessor"] = 1] = "WebAudioScriptProcessor";
		return PlayerOutputMode;
	}({});
	/**
	* Lists the different modes how the internal alphaTab player (and related cursor behavior) is working.
	* @public
	*/
	var PlayerMode = /* @__PURE__ */ function(PlayerMode) {
		/**
		* The player functionality is fully disabled.
		*/
		PlayerMode[PlayerMode["Disabled"] = 0] = "Disabled";
		/**
		* The player functionality is enabled.
		* If the loaded file provides a backing track, it is used for playback.
		* If no backing track is provided, the midi synthesizer is used.
		*/
		PlayerMode[PlayerMode["EnabledAutomatic"] = 1] = "EnabledAutomatic";
		/**
		* The player functionality is enabled and the synthesizer is used (even if a backing track is embedded in the file).
		*/
		PlayerMode[PlayerMode["EnabledSynthesizer"] = 2] = "EnabledSynthesizer";
		/**
		* The player functionality is enabled. If the input data model has no backing track configured, the player might not work as expected (as playback completes instantly).
		*/
		PlayerMode[PlayerMode["EnabledBackingTrack"] = 3] = "EnabledBackingTrack";
		/**
		* The player functionality is enabled and an external audio/video source is used as time axis.
		* The related player APIs need to be used to update the current position of the external audio source within alphaTab.
		*/
		PlayerMode[PlayerMode["EnabledExternalMedia"] = 4] = "EnabledExternalMedia";
		return PlayerMode;
	}({});
	/**
	* The player settings control how the audio playback and UI is behaving.
	* @json
	* @json_declaration
	* @public
	*/
	var PlayerSettings = class {
		/**
		* The sound font file to load for the player.
		* @target web
		* @since 0.9.6
		* @defaultValue `null`
		* @category Player - JavaScript Specific
		* @remarks
		* When the player is enabled the soundfont from this URL will be loaded automatically after the player is ready.
		*/
		soundFont = null;
		/**
		* The element to apply the scrolling on.
		* @target web
		* @json_read_only
		* @json_raw
		* @since 0.9.6
		* @defaultValue `html,body`
		* @category Player - JavaScript Specific
		* @remarks
		* When the player is active, it by default automatically scrolls the browser window to the currently played bar. This setting
		* defines which elements should be scrolled to bring the played bar into the view port. By default scrolling happens on the `html,body`
		* selector.
		*/
		scrollElement = "html,body";
		/**
		* The mode used for playing audio samples
		* @target web
		* @since 1.3.0
		* @defaultValue `PlayerOutputMode.WebAudioAudioWorklets`
		* @category Player - JavaScript Specific
		* @remarks
		* Controls how alphaTab will play the audio samples in the browser.
		*/
		outputMode = 0;
		/**
		* Whether the player should be enabled.
		* @since 0.9.6
		* @defaultValue `false`
		* @category Player
		* @deprecated Use {@link playerMode} instead.
		* @remarks
		* This setting configures whether the player feature is enabled or not. Depending on the platform enabling the player needs some additional actions of the developer.
		* For the JavaScript version the [player.soundFont](/docs/reference/settings/player/soundfont) property must be set to the URL of the sound font that should be used or it must be loaded manually via API.
		* For .net manually the soundfont must be loaded.
		*
		* AlphaTab does not ship a default UI for the player. The API must be hooked up to some UI controls to allow the user to interact with the player.
		*/
		enablePlayer = false;
		/**
		* Whether the player should be enabled and which mode it should use.
		* @since 1.6.0
		* @defaultValue `PlayerMode.Disabled`
		* @category Player
		* @remarks
		* This setting configures whether the player feature is enabled or not. Depending on the platform enabling the player needs some additional actions of the developer.
		*
		* **Synthesizer**
		*
		* If the synthesizer is used (via {@link PlayerMode.EnabledAutomatic} or {@link PlayerMode.EnabledSynthesizer}) a sound font is needed so that the midi synthesizer can produce the audio samples.
		*
		* For the JavaScript version the [player.soundFont](/docs/reference/settings/player/soundfont) property must be set to the URL of the sound font that should be used or it must be loaded manually via API.
		* For .net manually the soundfont must be loaded.
		*
		* **Backing Track**
		*
		* For a built-in backing track of the input file no additional data needs to be loaded (assuming everything is filled via the input file).
		* Otherwise the `score.backingTrack` needs to be filled before loading and the related sync points need to be configured.
		*
		* **External Media**
		*
		* For synchronizing alphaTab with an external media no data needs to be loaded into alphaTab. The configured sync points on the MasterBars are used
		* as reference to synchronize the external media with the internal time axis. Then the related APIs on the AlphaTabApi object need to be used
		* to update the playback state and exterrnal audio position during playback.
		*
		* **User Interface**
		*
		* AlphaTab does not ship a default UI for the player. The API must be hooked up to some UI controls to allow the user to interact with the player.
		*/
		playerMode = 0;
		/**
		* Whether playback cursors should be displayed.
		* @since 0.9.6
		* @defaultValue `true` (if player is not disabled)
		* @category Player
		* @remarks
		* This setting configures whether the playback cursors are shown or not. In case a developer decides to built an own cursor system the default one can be disabled with this setting. Enabling the cursor also requires the player to be active.
		*/
		enableCursor = true;
		/**
		* Whether the beat cursor should be animated or just ticking.
		* @since 1.2.3
		* @defaultValue `true`
		* @category Player
		* @remarks
		* This setting configures whether the beat cursor is animated smoothly or whether it is ticking from beat to beat.
		* The animation of the cursor might not be available on all targets so it might not have any effect.
		*/
		enableAnimatedBeatCursor = true;
		/**
		* Whether the notation elements of the currently played beat should be highlighted.
		* @since 1.2.3
		* @defaultValue `true`
		* @category Player
		* @remarks
		* This setting configures whether the note elements are highlighted during playback.
		* The highlighting of elements might not be available on all targets and render engine, so it might not have any effect.
		*/
		enableElementHighlighting = true;
		/**
		* Whether the default user interaction behavior should be active or not.
		* @since 0.9.7
		* @defaultValue `true`
		* @category Player
		* @remarks
		* This setting configures whether alphaTab provides the default user interaction features like selection of the playback range and "seek on click".
		* By default users can select the desired playback range with the mouse and also jump to individual beats by click. This behavior can be contolled with this setting.
		*/
		enableUserInteraction = true;
		/**
		* The X-offset to add when scrolling.
		* @since 0.9.6
		* @defaultValue `0`
		* @category Player
		* @remarks
		* When alphaTab does an auto-scrolling to the displayed bar, it will try to align the view port to the displayed bar. If due to
		* some layout specifics or for aesthetics a small padding is needed, this setting allows an additional X-offset that is added to the
		* scroll position.
		*/
		scrollOffsetX = 0;
		/**
		* The Y-offset to add when scrolling.
		* @since 0.9.6
		* @defaultValue `0`
		* @category Player
		* @remarks
		* When alphaTab does an auto-scrolling to the displayed bar, it will try to align the view port to the displayed bar. If due to
		* some layout specifics or for aesthetics a small padding is needed, this setting allows an additional Y-offset that is added to the
		* scroll position.
		*/
		scrollOffsetY = 0;
		/**
		* The mode how to scroll.
		* @since 0.9.6
		* @defaultValue `ScrollMode.Continuous`
		* @category Player
		* @remarks
		* This setting controls how alphaTab behaves for scrolling.
		*/
		scrollMode = 1;
		/**
		* How fast the scrolling to the new position should happen.
		* @since 0.9.6
		* @defaultValue `300`
		* @category Player
		* @remarks
		* If possible from the platform, alphaTab will try to do a smooth scrolling to the played bar.
		* This setting defines the speed of scrolling in milliseconds.
		* Note that {@link nativeBrowserSmoothScroll} must be set to `false` for this to have an effect.
		*/
		scrollSpeed = 300;
		/**
		* Whether the native browser smooth scroll mechanism should be used over a custom animation.
		* @target web
		* @since 1.2.3
		* @defaultValue `true`
		* @category Player
		* @remarks
		* This setting configures whether the [native browser feature](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTo)
		* for smooth scrolling should be used over a custom animation.
		* If this setting is enabled, options like {@link scrollSpeed} will not have an effect anymore.
		*/
		nativeBrowserSmoothScroll = true;
		/**
		* The bend duration in milliseconds for songbook bends.
		* @since 0.9.6
		* @defaultValue `75`
		* @category Player
		* @remarks
		* If the display mode `songbook` is enabled, this has an effect on the way bends are played. For songbook bends the bend is done very quickly at the end or start of the beat.
		* This setting defines the play duration for those bends in milliseconds. This duration is in milliseconds unlike some other settings which are in midi ticks. The reason is that on songbook bends,
		* the bends should always be played in the same speed, regardless of the song tempo. Midi ticks are tempo dependent.
		*/
		songBookBendDuration = 75;
		/**
		* The duration of whammy dips in milliseconds for songbook whammys.
		* @since 0.9.6
		* @defaultValue `150`
		* @category Player
		* @remarks
		* If the display mode `songbook` is enabled, this has an effect on the way whammy dips are played. For songbook dips the whammy is pressed very quickly at the start of the beat.
		* This setting defines the play duration for those whammy bars in milliseconds. This duration is in milliseconds unlike some other settings which are in midi ticks. The reason is that on songbook dips,
		* the whammy should always be pressed in the same speed, regardless of the song tempo. Midi ticks are tempo dependent.
		*/
		songBookDipDuration = 150;
		/**
		* The Vibrato settings allow control how the different vibrato types are generated for audio.
		* @json_partial_names
		* @since 0.9.6
		* @category Player
		* @remarks
		* AlphaTab supports 4 types of vibratos, for each vibrato the amplitude and the wavelength can be configured. The amplitude controls how many semitones
		* the vibrato changes the pitch up and down while playback. The wavelength controls how many midi ticks it will take to complete one up and down vibrato.
		* The 4 vibrato types are:
		*
		* 1. Beat Slight - A fast vibrato on the whole beat. This vibrato is usually done with the whammy bar.
		* 2. Beat Wide - A slow vibrato on the whole beat. This vibrato is usually done with the whammy bar.
		* 3. Note Slight - A fast vibrato on a single note. This vibrato is usually done with the finger on the fretboard.
		* 4. Note Wide - A slow vibrato on a single note. This vibrato is usually done with the finger on the fretboard.
		*/
		vibrato = new VibratoPlaybackSettings();
		/**
		* The slide settings allow control how the different slide types are generated for audio.
		* @json_partial_names
		* @since 0.9.6
		* @domWildcard
		* @category Player
		* @remarks
		* AlphaTab supports various types of slides which can be grouped into 3 types:
		*
		* * Shift Slides
		* * Legato Slides
		*
		*
		* * Slide into from below
		* * Slide into from above
		* * Slide out to below
		* * Slide out to above
		*
		*
		* * Pick Slide out to above
		* * Pick Slide out to below
		*
		* For the first 2 groups the audio generation can be adapted. For the pick slide the audio generation cannot be adapted
		* as there is no mechanism yet in alphaTab to play pick slides to make them sound real.
		*
		* For the first group only the duration or start point of the slide can be configured while for the second group
		* the duration/start-point and the pitch offset can be configured.
		*/
		slide = new SlidePlaybackSettings();
		/**
		* Whether the triplet feel should be played or only displayed.
		* @since 0.9.6
		* @defaultValue `true`
		* @category Player
		* @remarks
		* If this setting is enabled alphaTab will play the triplet feels accordingly, if it is disabled the triplet feel is only displayed but not played.
		*/
		playTripletFeel = true;
		/**
		* The number of milliseconds the player should buffer.
		* @since 1.2.3
		* @defaultValue `500`
		* @category Player
		* @remarks
		* Gets or sets how many milliseconds of audio samples should be buffered in total.
		*
		* * Larger buffers cause a delay from when audio settings like volumes will be applied.
		* * Smaller buffers can cause audio crackling due to constant buffering that is happening.
		*
		* This buffer size can be changed whenever needed.
		*/
		bufferTimeInMilliseconds = 500;
	};
	//#endregion
	//#region src/generated/CoreSettingsSerializer.ts
	/**
	* @internal
	*/
	var CoreSettingsSerializer = class CoreSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => CoreSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("scriptfile", obj.scriptFile);
			o.set("fontdirectory", obj.fontDirectory);
			if (obj.smuflFontSources !== null) {
				const m = /* @__PURE__ */ new Map();
				o.set("smuflfontsources", m);
				for (const [k, v] of obj.smuflFontSources) m.set(k.toString(), v);
			}
			o.set("file", obj.file);
			o.set("tex", obj.tex);
			o.set("tracks", obj.tracks);
			o.set("enablelazyloading", obj.enableLazyLoading);
			o.set("engine", obj.engine);
			o.set("loglevel", obj.logLevel);
			o.set("useworkers", obj.useWorkers);
			o.set("includenotebounds", obj.includeNoteBounds);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "scriptfile":
					obj.scriptFile = v;
					return true;
				case "fontdirectory":
					obj.fontDirectory = v;
					return true;
				case "smuflfontsources":
					obj.smuflFontSources = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.smuflFontSources.set(JsonHelper.parseEnum(k, FontFileFormat), v);
					});
					return true;
				case "file":
					obj.file = v;
					return true;
				case "tex":
					obj.tex = v;
					return true;
				case "tracks":
					obj.tracks = v;
					return true;
				case "enablelazyloading":
					obj.enableLazyLoading = v;
					return true;
				case "engine":
					obj.engine = v;
					return true;
				case "loglevel":
					obj.logLevel = JsonHelper.parseEnum(v, LogLevel);
					return true;
				case "useworkers":
					obj.useWorkers = v;
					return true;
				case "includenotebounds":
					obj.includeNoteBounds = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/EngravingStemInfoSerializer.ts
	/**
	* @internal
	*/
	var EngravingStemInfoSerializer = class EngravingStemInfoSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => EngravingStemInfoSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("topy", obj.topY);
			o.set("bottomy", obj.bottomY);
			o.set("x", obj.x);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "topy":
					obj.topY = v;
					return true;
				case "bottomy":
					obj.bottomY = v;
					return true;
				case "x":
					obj.x = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/EngravingSettingsSerializer.ts
	/**
	* @internal
	*/
	var EngravingSettingsSerializer = class EngravingSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => EngravingSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("musicfontsize", obj.musicFontSize);
			o.set("onestaffspace", obj.oneStaffSpace);
			o.set("tablinespacing", obj.tabLineSpacing);
			o.set("arrowshaftthickness", obj.arrowShaftThickness);
			o.set("barlineseparation", obj.barlineSeparation);
			o.set("beamspacing", obj.beamSpacing);
			o.set("beamthickness", obj.beamThickness);
			o.set("bracketthickness", obj.bracketThickness);
			o.set("dashedbarlinedashlength", obj.dashedBarlineDashLength);
			o.set("dashedbarlinegaplength", obj.dashedBarlineGapLength);
			o.set("dashedbarlinethickness", obj.dashedBarlineThickness);
			o.set("hairpinthickness", obj.hairpinThickness);
			o.set("legerlinethickness", obj.legerLineThickness);
			o.set("legerlineextension", obj.legerLineExtension);
			o.set("octavelinethickness", obj.octaveLineThickness);
			o.set("pedallinethickness", obj.pedalLineThickness);
			o.set("repeatbarlinedotseparation", obj.repeatBarlineDotSeparation);
			o.set("repeatendinglinethickness", obj.repeatEndingLineThickness);
			o.set("slurmidpointthickness", obj.slurMidpointThickness);
			o.set("stafflinethickness", obj.staffLineThickness);
			o.set("stemthickness", obj.stemThickness);
			o.set("thickbarlinethickness", obj.thickBarlineThickness);
			o.set("thinbarlinethickness", obj.thinBarlineThickness);
			o.set("thinthickbarlineseparation", obj.thinThickBarlineSeparation);
			o.set("tiemidpointthickness", obj.tieMidpointThickness);
			o.set("tupletbracketthickness", obj.tupletBracketThickness);
			{
				const m = /* @__PURE__ */ new Map();
				o.set("stemup", m);
				for (const [k, v] of obj.stemUp) m.set(k.toString(), EngravingStemInfoSerializer.toJson(v));
			}
			{
				const m = /* @__PURE__ */ new Map();
				o.set("stemdown", m);
				for (const [k, v] of obj.stemDown) m.set(k.toString(), EngravingStemInfoSerializer.toJson(v));
			}
			{
				const m = /* @__PURE__ */ new Map();
				o.set("repeatoffsetx", m);
				for (const [k, v] of obj.repeatOffsetX) m.set(k.toString(), v);
			}
			o.set("standardstemlength", obj.standardStemLength);
			{
				const m = /* @__PURE__ */ new Map();
				o.set("stemflagoffsets", m);
				for (const [k, v] of obj.stemFlagOffsets) m.set(k.toString(), v);
			}
			{
				const m = /* @__PURE__ */ new Map();
				o.set("glyphtop", m);
				for (const [k, v] of obj.glyphTop) m.set(k.toString(), v);
			}
			{
				const m = /* @__PURE__ */ new Map();
				o.set("glyphbottom", m);
				for (const [k, v] of obj.glyphBottom) m.set(k.toString(), v);
			}
			{
				const m = /* @__PURE__ */ new Map();
				o.set("glyphwidths", m);
				for (const [k, v] of obj.glyphWidths) m.set(k.toString(), v);
			}
			{
				const m = /* @__PURE__ */ new Map();
				o.set("glyphheights", m);
				for (const [k, v] of obj.glyphHeights) m.set(k.toString(), v);
			}
			o.set("numberedbarrendererbarsize", obj.numberedBarRendererBarSize);
			o.set("numberedbarrendererbarspacing", obj.numberedBarRendererBarSpacing);
			o.set("numbereddashglyphpadding", obj.numberedDashGlyphPadding);
			o.set("numbereddashglyphwidth", obj.numberedDashGlyphWidth);
			o.set("linerangedglyphdashgap", obj.lineRangedGlyphDashGap);
			o.set("linerangedglyphdashsize", obj.lineRangedGlyphDashSize);
			o.set("prenoteeffectpadding", obj.preNoteEffectPadding);
			o.set("postnoteeffectpadding", obj.postNoteEffectPadding);
			o.set("onnoteeffectpadding", obj.onNoteEffectPadding);
			o.set("stringnumbercirclepadding", obj.stringNumberCirclePadding);
			o.set("rowcontainerpadding", obj.rowContainerPadding);
			o.set("rowcontainergap", obj.rowContainerGap);
			o.set("alternateendingspadding", obj.alternateEndingsPadding);
			o.set("sustainpedallinepadding", obj.sustainPedalLinePadding);
			o.set("tieheight", obj.tieHeight);
			o.set("beattimerpadding", obj.beatTimerPadding);
			o.set("bendnoteheadelementpadding", obj.bendNoteHeadElementPadding);
			o.set("ghostparenthesiswidth", obj.ghostParenthesisWidth);
			o.set("ghostparenthesispadding", obj.ghostParenthesisPadding);
			o.set("brokenbeamwidth", obj.brokenBeamWidth);
			o.set("tabwhammytextpadding", obj.tabWhammyTextPadding);
			o.set("tabwhammyperhalfheight", obj.tabWhammyPerHalfHeight);
			o.set("tabwhammydashsize", obj.tabWhammyDashSize);
			o.set("songbookwhammydipheight", obj.songBookWhammyDipHeight);
			o.set("deadslappedlinewidth", obj.deadSlappedLineWidth);
			o.set("lefthandtabtiewidth", obj.leftHandTabTieWidth);
			o.set("tabbenddashsize", obj.tabBendDashSize);
			o.set("tabbendstaffpadding", obj.tabBendStaffPadding);
			o.set("tabbendpervalueheight", obj.tabBendPerValueHeight);
			o.set("tabbendlabelpadding", obj.tabBendLabelPadding);
			o.set("simpleslidewidth", obj.simpleSlideWidth);
			o.set("simpleslideheight", obj.simpleSlideHeight);
			o.set("chorddiagrampaddingx", obj.chordDiagramPaddingX);
			o.set("chorddiagrampaddingy", obj.chordDiagramPaddingY);
			o.set("chorddiagramstringspacing", obj.chordDiagramStringSpacing);
			o.set("chorddiagramfretspacing", obj.chordDiagramFretSpacing);
			o.set("chorddiagramnutheight", obj.chordDiagramNutHeight);
			o.set("chorddiagramfretheight", obj.chordDiagramFretHeight);
			o.set("chorddiagramlinewidth", obj.chordDiagramLineWidth);
			o.set("tripletfeelbracketpadding", obj.tripletFeelBracketPadding);
			o.set("accidentalpadding", obj.accidentalPadding);
			o.set("prebeatglyphspacing", obj.preBeatGlyphSpacing);
			o.set("temponotescale", obj.tempoNoteScale);
			o.set("tuningglyphcirclenumberscale", obj.tuningGlyphCircleNumberScale);
			o.set("tuningglyphstringcolumnscale", obj.tuningGlyphStringColumnScale);
			o.set("tuningglyphstringrowpadding", obj.tuningGlyphStringRowPadding);
			o.set("directionsscale", obj.directionsScale);
			o.set("multivoicedisplacednoteheadspacing", obj.multiVoiceDisplacedNoteHeadSpacing);
			{
				const m = /* @__PURE__ */ new Map();
				o.set("stemflagheight", m);
				for (const [k, v] of obj.stemFlagHeight) m.set(k.toString(), v);
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "musicfontsize":
					obj.musicFontSize = v;
					return true;
				case "onestaffspace":
					obj.oneStaffSpace = v;
					return true;
				case "tablinespacing":
					obj.tabLineSpacing = v;
					return true;
				case "arrowshaftthickness":
					obj.arrowShaftThickness = v;
					return true;
				case "barlineseparation":
					obj.barlineSeparation = v;
					return true;
				case "beamspacing":
					obj.beamSpacing = v;
					return true;
				case "beamthickness":
					obj.beamThickness = v;
					return true;
				case "bracketthickness":
					obj.bracketThickness = v;
					return true;
				case "dashedbarlinedashlength":
					obj.dashedBarlineDashLength = v;
					return true;
				case "dashedbarlinegaplength":
					obj.dashedBarlineGapLength = v;
					return true;
				case "dashedbarlinethickness":
					obj.dashedBarlineThickness = v;
					return true;
				case "hairpinthickness":
					obj.hairpinThickness = v;
					return true;
				case "legerlinethickness":
					obj.legerLineThickness = v;
					return true;
				case "legerlineextension":
					obj.legerLineExtension = v;
					return true;
				case "octavelinethickness":
					obj.octaveLineThickness = v;
					return true;
				case "pedallinethickness":
					obj.pedalLineThickness = v;
					return true;
				case "repeatbarlinedotseparation":
					obj.repeatBarlineDotSeparation = v;
					return true;
				case "repeatendinglinethickness":
					obj.repeatEndingLineThickness = v;
					return true;
				case "slurmidpointthickness":
					obj.slurMidpointThickness = v;
					return true;
				case "stafflinethickness":
					obj.staffLineThickness = v;
					return true;
				case "stemthickness":
					obj.stemThickness = v;
					return true;
				case "thickbarlinethickness":
					obj.thickBarlineThickness = v;
					return true;
				case "thinbarlinethickness":
					obj.thinBarlineThickness = v;
					return true;
				case "thinthickbarlineseparation":
					obj.thinThickBarlineSeparation = v;
					return true;
				case "tiemidpointthickness":
					obj.tieMidpointThickness = v;
					return true;
				case "tupletbracketthickness":
					obj.tupletBracketThickness = v;
					return true;
				case "stemup":
					obj.stemUp = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						const i = new EngravingStemInfo();
						EngravingStemInfoSerializer.fromJson(i, v);
						obj.stemUp.set(JsonHelper.parseEnum(k, MusicFontSymbol), i);
					});
					return true;
				case "stemdown":
					obj.stemDown = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						const i = new EngravingStemInfo();
						EngravingStemInfoSerializer.fromJson(i, v);
						obj.stemDown.set(JsonHelper.parseEnum(k, MusicFontSymbol), i);
					});
					return true;
				case "repeatoffsetx":
					obj.repeatOffsetX = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.repeatOffsetX.set(JsonHelper.parseEnum(k, MusicFontSymbol), v);
					});
					return true;
				case "standardstemlength":
					obj.standardStemLength = v;
					return true;
				case "stemflagoffsets":
					obj.stemFlagOffsets = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.stemFlagOffsets.set(JsonHelper.parseEnum(k, Duration), v);
					});
					return true;
				case "glyphtop":
					obj.glyphTop = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.glyphTop.set(JsonHelper.parseEnum(k, MusicFontSymbol), v);
					});
					return true;
				case "glyphbottom":
					obj.glyphBottom = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.glyphBottom.set(JsonHelper.parseEnum(k, MusicFontSymbol), v);
					});
					return true;
				case "glyphwidths":
					obj.glyphWidths = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.glyphWidths.set(JsonHelper.parseEnum(k, MusicFontSymbol), v);
					});
					return true;
				case "glyphheights":
					obj.glyphHeights = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.glyphHeights.set(JsonHelper.parseEnum(k, MusicFontSymbol), v);
					});
					return true;
				case "numberedbarrendererbarsize":
					obj.numberedBarRendererBarSize = v;
					return true;
				case "numberedbarrendererbarspacing":
					obj.numberedBarRendererBarSpacing = v;
					return true;
				case "numbereddashglyphpadding":
					obj.numberedDashGlyphPadding = v;
					return true;
				case "numbereddashglyphwidth":
					obj.numberedDashGlyphWidth = v;
					return true;
				case "linerangedglyphdashgap":
					obj.lineRangedGlyphDashGap = v;
					return true;
				case "linerangedglyphdashsize":
					obj.lineRangedGlyphDashSize = v;
					return true;
				case "prenoteeffectpadding":
					obj.preNoteEffectPadding = v;
					return true;
				case "postnoteeffectpadding":
					obj.postNoteEffectPadding = v;
					return true;
				case "onnoteeffectpadding":
					obj.onNoteEffectPadding = v;
					return true;
				case "stringnumbercirclepadding":
					obj.stringNumberCirclePadding = v;
					return true;
				case "rowcontainerpadding":
					obj.rowContainerPadding = v;
					return true;
				case "rowcontainergap":
					obj.rowContainerGap = v;
					return true;
				case "alternateendingspadding":
					obj.alternateEndingsPadding = v;
					return true;
				case "sustainpedallinepadding":
					obj.sustainPedalLinePadding = v;
					return true;
				case "tieheight":
					obj.tieHeight = v;
					return true;
				case "beattimerpadding":
					obj.beatTimerPadding = v;
					return true;
				case "bendnoteheadelementpadding":
					obj.bendNoteHeadElementPadding = v;
					return true;
				case "ghostparenthesiswidth":
					obj.ghostParenthesisWidth = v;
					return true;
				case "ghostparenthesispadding":
					obj.ghostParenthesisPadding = v;
					return true;
				case "brokenbeamwidth":
					obj.brokenBeamWidth = v;
					return true;
				case "tabwhammytextpadding":
					obj.tabWhammyTextPadding = v;
					return true;
				case "tabwhammyperhalfheight":
					obj.tabWhammyPerHalfHeight = v;
					return true;
				case "tabwhammydashsize":
					obj.tabWhammyDashSize = v;
					return true;
				case "songbookwhammydipheight":
					obj.songBookWhammyDipHeight = v;
					return true;
				case "deadslappedlinewidth":
					obj.deadSlappedLineWidth = v;
					return true;
				case "lefthandtabtiewidth":
					obj.leftHandTabTieWidth = v;
					return true;
				case "tabbenddashsize":
					obj.tabBendDashSize = v;
					return true;
				case "tabbendstaffpadding":
					obj.tabBendStaffPadding = v;
					return true;
				case "tabbendpervalueheight":
					obj.tabBendPerValueHeight = v;
					return true;
				case "tabbendlabelpadding":
					obj.tabBendLabelPadding = v;
					return true;
				case "simpleslidewidth":
					obj.simpleSlideWidth = v;
					return true;
				case "simpleslideheight":
					obj.simpleSlideHeight = v;
					return true;
				case "chorddiagrampaddingx":
					obj.chordDiagramPaddingX = v;
					return true;
				case "chorddiagrampaddingy":
					obj.chordDiagramPaddingY = v;
					return true;
				case "chorddiagramstringspacing":
					obj.chordDiagramStringSpacing = v;
					return true;
				case "chorddiagramfretspacing":
					obj.chordDiagramFretSpacing = v;
					return true;
				case "chorddiagramnutheight":
					obj.chordDiagramNutHeight = v;
					return true;
				case "chorddiagramfretheight":
					obj.chordDiagramFretHeight = v;
					return true;
				case "chorddiagramlinewidth":
					obj.chordDiagramLineWidth = v;
					return true;
				case "tripletfeelbracketpadding":
					obj.tripletFeelBracketPadding = v;
					return true;
				case "accidentalpadding":
					obj.accidentalPadding = v;
					return true;
				case "prebeatglyphspacing":
					obj.preBeatGlyphSpacing = v;
					return true;
				case "temponotescale":
					obj.tempoNoteScale = v;
					return true;
				case "tuningglyphcirclenumberscale":
					obj.tuningGlyphCircleNumberScale = v;
					return true;
				case "tuningglyphstringcolumnscale":
					obj.tuningGlyphStringColumnScale = v;
					return true;
				case "tuningglyphstringrowpadding":
					obj.tuningGlyphStringRowPadding = v;
					return true;
				case "directionsscale":
					obj.directionsScale = v;
					return true;
				case "multivoicedisplacednoteheadspacing":
					obj.multiVoiceDisplacedNoteHeadSpacing = v;
					return true;
				case "stemflagheight":
					obj.stemFlagHeight = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.stemFlagHeight.set(JsonHelper.parseEnum(k, Duration), v);
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/RenderingResourcesSerializer.ts
	/**
	* @internal
	*/
	var RenderingResourcesSerializer = class RenderingResourcesSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => RenderingResourcesSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("smuflfontfamilyname", obj.smuflFontFamilyName);
			o.set("engravingsettings", EngravingSettingsSerializer.toJson(obj.engravingSettings));
			{
				const m = /* @__PURE__ */ new Map();
				o.set("elementfonts", m);
				for (const [k, v] of obj.elementFonts) m.set(k.toString(), Font.toJson(v));
			}
			o.set("numberednotationfont", Font.toJson(obj.numberedNotationFont));
			o.set("numberednotationgracefont", Font.toJson(obj.numberedNotationGraceFont));
			o.set("tablaturefont", Font.toJson(obj.tablatureFont));
			o.set("gracefont", Font.toJson(obj.graceFont));
			o.set("stafflinecolor", Color.toJson(obj.staffLineColor));
			o.set("barseparatorcolor", Color.toJson(obj.barSeparatorColor));
			o.set("barnumbercolor", Color.toJson(obj.barNumberColor));
			o.set("mainglyphcolor", Color.toJson(obj.mainGlyphColor));
			o.set("secondaryglyphcolor", Color.toJson(obj.secondaryGlyphColor));
			o.set("scoreinfocolor", Color.toJson(obj.scoreInfoColor));
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "smuflfontfamilyname":
					obj.smuflFontFamilyName = v;
					return true;
				case "elementfonts":
					JsonHelper.forEach(v, (v, k) => {
						obj.elementFonts.set(JsonHelper.parseEnum(k, NotationElement), Font.fromJson(v));
					});
					return true;
				case "numberednotationfont":
					obj.numberedNotationFont = Font.fromJson(v);
					return true;
				case "numberednotationgracefont":
					obj.numberedNotationGraceFont = Font.fromJson(v);
					return true;
				case "tablaturefont":
					obj.tablatureFont = Font.fromJson(v);
					return true;
				case "gracefont":
					obj.graceFont = Font.fromJson(v);
					return true;
				case "stafflinecolor":
					obj.staffLineColor = Color.fromJson(v);
					return true;
				case "barseparatorcolor":
					obj.barSeparatorColor = Color.fromJson(v);
					return true;
				case "barnumbercolor":
					obj.barNumberColor = Color.fromJson(v);
					return true;
				case "mainglyphcolor":
					obj.mainGlyphColor = Color.fromJson(v);
					return true;
				case "secondaryglyphcolor":
					obj.secondaryGlyphColor = Color.fromJson(v);
					return true;
				case "scoreinfocolor":
					obj.scoreInfoColor = Color.fromJson(v);
					return true;
			}
			if (["engravingsettings"].indexOf(property) >= 0) {
				EngravingSettingsSerializer.fromJson(obj.engravingSettings, v);
				return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/DisplaySettingsSerializer.ts
	/**
	* @internal
	*/
	var DisplaySettingsSerializer = class DisplaySettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => DisplaySettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("scale", obj.scale);
			o.set("stretchforce", obj.stretchForce);
			o.set("layoutmode", obj.layoutMode);
			o.set("staveprofile", obj.staveProfile);
			o.set("barsperrow", obj.barsPerRow);
			o.set("startbar", obj.startBar);
			o.set("barcount", obj.barCount);
			o.set("barcountperpartial", obj.barCountPerPartial);
			o.set("justifylastsystem", obj.justifyLastSystem);
			o.set("resources", RenderingResourcesSerializer.toJson(obj.resources));
			o.set("padding", obj.padding);
			o.set("firstsystempaddingtop", obj.firstSystemPaddingTop);
			o.set("systempaddingtop", obj.systemPaddingTop);
			o.set("systempaddingbottom", obj.systemPaddingBottom);
			o.set("lastsystempaddingbottom", obj.lastSystemPaddingBottom);
			o.set("systemlabelpaddingleft", obj.systemLabelPaddingLeft);
			o.set("systemlabelpaddingright", obj.systemLabelPaddingRight);
			o.set("accoladebarpaddingright", obj.accoladeBarPaddingRight);
			o.set("firstnotationstaffpaddingtop", obj.firstNotationStaffPaddingTop);
			o.set("lastnotationstaffpaddingbottom", obj.lastNotationStaffPaddingBottom);
			o.set("notationstaffpaddingtop", obj.notationStaffPaddingTop);
			o.set("notationstaffpaddingbottom", obj.notationStaffPaddingBottom);
			o.set("effectstaffpaddingtop", obj.effectStaffPaddingTop);
			o.set("effectstaffpaddingbottom", obj.effectStaffPaddingBottom);
			o.set("firststaffpaddingleft", obj.firstStaffPaddingLeft);
			o.set("staffpaddingleft", obj.staffPaddingLeft);
			o.set("effectbandpaddingbottom", obj.effectBandPaddingBottom);
			o.set("trackstaffpaddingbetween", obj.trackStaffPaddingBetween);
			o.set("lyriclinespaddingbetween", obj.lyricLinesPaddingBetween);
			o.set("systemslayoutmode", obj.systemsLayoutMode);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "scale":
					obj.scale = v;
					return true;
				case "stretchforce":
					obj.stretchForce = v;
					return true;
				case "layoutmode":
					obj.layoutMode = JsonHelper.parseEnum(v, LayoutMode);
					return true;
				case "staveprofile":
					obj.staveProfile = JsonHelper.parseEnum(v, StaveProfile);
					return true;
				case "barsperrow":
					obj.barsPerRow = v;
					return true;
				case "startbar":
					obj.startBar = v;
					return true;
				case "barcount":
					obj.barCount = v;
					return true;
				case "barcountperpartial":
					obj.barCountPerPartial = v;
					return true;
				case "justifylastsystem":
					obj.justifyLastSystem = v;
					return true;
				case "padding":
					obj.padding = v;
					return true;
				case "firstsystempaddingtop":
					obj.firstSystemPaddingTop = v;
					return true;
				case "systempaddingtop":
					obj.systemPaddingTop = v;
					return true;
				case "systempaddingbottom":
					obj.systemPaddingBottom = v;
					return true;
				case "lastsystempaddingbottom":
					obj.lastSystemPaddingBottom = v;
					return true;
				case "systemlabelpaddingleft":
					obj.systemLabelPaddingLeft = v;
					return true;
				case "systemlabelpaddingright":
					obj.systemLabelPaddingRight = v;
					return true;
				case "accoladebarpaddingright":
					obj.accoladeBarPaddingRight = v;
					return true;
				case "firstnotationstaffpaddingtop":
					obj.firstNotationStaffPaddingTop = v;
					return true;
				case "lastnotationstaffpaddingbottom":
					obj.lastNotationStaffPaddingBottom = v;
					return true;
				case "notationstaffpaddingtop":
					obj.notationStaffPaddingTop = v;
					return true;
				case "notationstaffpaddingbottom":
					obj.notationStaffPaddingBottom = v;
					return true;
				case "effectstaffpaddingtop":
					obj.effectStaffPaddingTop = v;
					return true;
				case "effectstaffpaddingbottom":
					obj.effectStaffPaddingBottom = v;
					return true;
				case "firststaffpaddingleft":
					obj.firstStaffPaddingLeft = v;
					return true;
				case "staffpaddingleft":
					obj.staffPaddingLeft = v;
					return true;
				case "effectbandpaddingbottom":
					obj.effectBandPaddingBottom = v;
					return true;
				case "trackstaffpaddingbetween":
					obj.trackStaffPaddingBetween = v;
					return true;
				case "lyriclinespaddingbetween":
					obj.lyricLinesPaddingBetween = v;
					return true;
				case "systemslayoutmode":
					obj.systemsLayoutMode = JsonHelper.parseEnum(v, SystemsLayoutMode);
					return true;
			}
			if (["resources"].indexOf(property) >= 0) {
				RenderingResourcesSerializer.fromJson(obj.resources, v);
				return true;
			}
			for (const c of ["resources"]) if (property.indexOf(c) === 0) {
				if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring(c.length), v)) return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/NotationSettingsSerializer.ts
	/**
	* @internal
	*/
	var NotationSettingsSerializer = class NotationSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => NotationSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("notationmode", obj.notationMode);
			o.set("fingeringmode", obj.fingeringMode);
			{
				const m = /* @__PURE__ */ new Map();
				o.set("elements", m);
				for (const [k, v] of obj.elements) m.set(k.toString(), v);
			}
			o.set("rhythmmode", obj.rhythmMode);
			o.set("rhythmheight", obj.rhythmHeight);
			o.set("transpositionpitches", obj.transpositionPitches);
			o.set("displaytranspositionpitches", obj.displayTranspositionPitches);
			o.set("smallgracetabnotes", obj.smallGraceTabNotes);
			o.set("extendbendarrowsontiednotes", obj.extendBendArrowsOnTiedNotes);
			o.set("extendlineeffectstobeatend", obj.extendLineEffectsToBeatEnd);
			o.set("slurheight", obj.slurHeight);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "notationmode":
					obj.notationMode = JsonHelper.parseEnum(v, NotationMode);
					return true;
				case "fingeringmode":
					obj.fingeringMode = JsonHelper.parseEnum(v, FingeringMode);
					return true;
				case "elements":
					obj.elements = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.elements.set(JsonHelper.parseEnum(k, NotationElement), v);
					});
					return true;
				case "rhythmmode":
					obj.rhythmMode = JsonHelper.parseEnum(v, TabRhythmMode);
					return true;
				case "rhythmheight":
					obj.rhythmHeight = v;
					return true;
				case "transpositionpitches":
					obj.transpositionPitches = v;
					return true;
				case "displaytranspositionpitches":
					obj.displayTranspositionPitches = v;
					return true;
				case "smallgracetabnotes":
					obj.smallGraceTabNotes = v;
					return true;
				case "extendbendarrowsontiednotes":
					obj.extendBendArrowsOnTiedNotes = v;
					return true;
				case "extendlineeffectstobeatend":
					obj.extendLineEffectsToBeatEnd = v;
					return true;
				case "slurheight":
					obj.slurHeight = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/ImporterSettingsSerializer.ts
	/**
	* @internal
	*/
	var ImporterSettingsSerializer = class ImporterSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => ImporterSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("encoding", obj.encoding);
			o.set("mergepartgroupsinmusicxml", obj.mergePartGroupsInMusicXml);
			o.set("beattextaslyrics", obj.beatTextAsLyrics);
			o.set("maxdecodingbuffersize", obj.maxDecodingBufferSize);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "encoding":
					obj.encoding = v;
					return true;
				case "mergepartgroupsinmusicxml":
					obj.mergePartGroupsInMusicXml = v;
					return true;
				case "beattextaslyrics":
					obj.beatTextAsLyrics = v;
					return true;
				case "maxdecodingbuffersize":
					obj.maxDecodingBufferSize = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/VibratoPlaybackSettingsSerializer.ts
	/**
	* @internal
	*/
	var VibratoPlaybackSettingsSerializer = class VibratoPlaybackSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => VibratoPlaybackSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("notewidelength", obj.noteWideLength);
			o.set("notewideamplitude", obj.noteWideAmplitude);
			o.set("noteslightlength", obj.noteSlightLength);
			o.set("noteslightamplitude", obj.noteSlightAmplitude);
			o.set("beatwidelength", obj.beatWideLength);
			o.set("beatwideamplitude", obj.beatWideAmplitude);
			o.set("beatslightlength", obj.beatSlightLength);
			o.set("beatslightamplitude", obj.beatSlightAmplitude);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "notewidelength":
					obj.noteWideLength = v;
					return true;
				case "notewideamplitude":
					obj.noteWideAmplitude = v;
					return true;
				case "noteslightlength":
					obj.noteSlightLength = v;
					return true;
				case "noteslightamplitude":
					obj.noteSlightAmplitude = v;
					return true;
				case "beatwidelength":
					obj.beatWideLength = v;
					return true;
				case "beatwideamplitude":
					obj.beatWideAmplitude = v;
					return true;
				case "beatslightlength":
					obj.beatSlightLength = v;
					return true;
				case "beatslightamplitude":
					obj.beatSlightAmplitude = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/SlidePlaybackSettingsSerializer.ts
	/**
	* @internal
	*/
	var SlidePlaybackSettingsSerializer = class SlidePlaybackSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => SlidePlaybackSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("simpleslidepitchoffset", obj.simpleSlidePitchOffset);
			o.set("simpleslidedurationratio", obj.simpleSlideDurationRatio);
			o.set("shiftslidedurationratio", obj.shiftSlideDurationRatio);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "simpleslidepitchoffset":
					obj.simpleSlidePitchOffset = v;
					return true;
				case "simpleslidedurationratio":
					obj.simpleSlideDurationRatio = v;
					return true;
				case "shiftslidedurationratio":
					obj.shiftSlideDurationRatio = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/PlayerSettingsSerializer.ts
	/**
	* @internal
	*/
	var PlayerSettingsSerializer = class PlayerSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => PlayerSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("soundfont", obj.soundFont);
			o.set("outputmode", obj.outputMode);
			o.set("enableplayer", obj.enablePlayer);
			o.set("playermode", obj.playerMode);
			o.set("enablecursor", obj.enableCursor);
			o.set("enableanimatedbeatcursor", obj.enableAnimatedBeatCursor);
			o.set("enableelementhighlighting", obj.enableElementHighlighting);
			o.set("enableuserinteraction", obj.enableUserInteraction);
			o.set("scrolloffsetx", obj.scrollOffsetX);
			o.set("scrolloffsety", obj.scrollOffsetY);
			o.set("scrollmode", obj.scrollMode);
			o.set("scrollspeed", obj.scrollSpeed);
			o.set("nativebrowsersmoothscroll", obj.nativeBrowserSmoothScroll);
			o.set("songbookbendduration", obj.songBookBendDuration);
			o.set("songbookdipduration", obj.songBookDipDuration);
			o.set("vibrato", VibratoPlaybackSettingsSerializer.toJson(obj.vibrato));
			o.set("slide", SlidePlaybackSettingsSerializer.toJson(obj.slide));
			o.set("playtripletfeel", obj.playTripletFeel);
			o.set("buffertimeinmilliseconds", obj.bufferTimeInMilliseconds);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "soundfont":
					obj.soundFont = v;
					return true;
				case "scrollelement":
					obj.scrollElement = v;
					return true;
				case "outputmode":
					obj.outputMode = JsonHelper.parseEnum(v, PlayerOutputMode);
					return true;
				case "enableplayer":
					obj.enablePlayer = v;
					return true;
				case "playermode":
					obj.playerMode = JsonHelper.parseEnum(v, PlayerMode);
					return true;
				case "enablecursor":
					obj.enableCursor = v;
					return true;
				case "enableanimatedbeatcursor":
					obj.enableAnimatedBeatCursor = v;
					return true;
				case "enableelementhighlighting":
					obj.enableElementHighlighting = v;
					return true;
				case "enableuserinteraction":
					obj.enableUserInteraction = v;
					return true;
				case "scrolloffsetx":
					obj.scrollOffsetX = v;
					return true;
				case "scrolloffsety":
					obj.scrollOffsetY = v;
					return true;
				case "scrollmode":
					obj.scrollMode = JsonHelper.parseEnum(v, ScrollMode);
					return true;
				case "scrollspeed":
					obj.scrollSpeed = v;
					return true;
				case "nativebrowsersmoothscroll":
					obj.nativeBrowserSmoothScroll = v;
					return true;
				case "songbookbendduration":
					obj.songBookBendDuration = v;
					return true;
				case "songbookdipduration":
					obj.songBookDipDuration = v;
					return true;
				case "playtripletfeel":
					obj.playTripletFeel = v;
					return true;
				case "buffertimeinmilliseconds":
					obj.bufferTimeInMilliseconds = v;
					return true;
			}
			if (["vibrato"].indexOf(property) >= 0) {
				VibratoPlaybackSettingsSerializer.fromJson(obj.vibrato, v);
				return true;
			}
			for (const c of ["vibrato"]) if (property.indexOf(c) === 0) {
				if (VibratoPlaybackSettingsSerializer.setProperty(obj.vibrato, property.substring(c.length), v)) return true;
			}
			if (["slide"].indexOf(property) >= 0) {
				SlidePlaybackSettingsSerializer.fromJson(obj.slide, v);
				return true;
			}
			for (const c of ["slide"]) if (property.indexOf(c) === 0) {
				if (SlidePlaybackSettingsSerializer.setProperty(obj.slide, property.substring(c.length), v)) return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/ExporterSettingsSerializer.ts
	/**
	* @internal
	*/
	var ExporterSettingsSerializer = class ExporterSettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => ExporterSettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("indent", obj.indent);
			o.set("comments", obj.comments);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "indent":
					obj.indent = v;
					return true;
				case "comments":
					obj.comments = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/SettingsSerializer.ts
	/**
	* @internal
	*/
	var SettingsSerializer = class SettingsSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => SettingsSerializer.setProperty(obj, k.toLowerCase(), v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("core", CoreSettingsSerializer.toJson(obj.core));
			o.set("display", DisplaySettingsSerializer.toJson(obj.display));
			o.set("notation", NotationSettingsSerializer.toJson(obj.notation));
			o.set("importer", ImporterSettingsSerializer.toJson(obj.importer));
			o.set("player", PlayerSettingsSerializer.toJson(obj.player));
			o.set("exporter", ExporterSettingsSerializer.toJson(obj.exporter));
			return o;
		}
		static setProperty(obj, property, v) {
			if (["core", ""].indexOf(property) >= 0) {
				CoreSettingsSerializer.fromJson(obj.core, v);
				return true;
			}
			for (const c of ["core", ""]) if (property.indexOf(c) === 0) {
				if (CoreSettingsSerializer.setProperty(obj.core, property.substring(c.length), v)) return true;
			}
			if (["display", ""].indexOf(property) >= 0) {
				DisplaySettingsSerializer.fromJson(obj.display, v);
				return true;
			}
			for (const c of ["display", ""]) if (property.indexOf(c) === 0) {
				if (DisplaySettingsSerializer.setProperty(obj.display, property.substring(c.length), v)) return true;
			}
			if (["notation"].indexOf(property) >= 0) {
				NotationSettingsSerializer.fromJson(obj.notation, v);
				return true;
			}
			for (const c of ["notation"]) if (property.indexOf(c) === 0) {
				if (NotationSettingsSerializer.setProperty(obj.notation, property.substring(c.length), v)) return true;
			}
			if (["importer"].indexOf(property) >= 0) {
				ImporterSettingsSerializer.fromJson(obj.importer, v);
				return true;
			}
			for (const c of ["importer"]) if (property.indexOf(c) === 0) {
				if (ImporterSettingsSerializer.setProperty(obj.importer, property.substring(c.length), v)) return true;
			}
			if (["player"].indexOf(property) >= 0) {
				PlayerSettingsSerializer.fromJson(obj.player, v);
				return true;
			}
			for (const c of ["player"]) if (property.indexOf(c) === 0) {
				if (PlayerSettingsSerializer.setProperty(obj.player, property.substring(c.length), v)) return true;
			}
			if (["exporter"].indexOf(property) >= 0) {
				ExporterSettingsSerializer.fromJson(obj.exporter, v);
				return true;
			}
			for (const c of ["exporter"]) if (property.indexOf(c) === 0) {
				if (ExporterSettingsSerializer.setProperty(obj.exporter, property.substring(c.length), v)) return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/ExporterSettings.ts
	/**
	* All settings related to exporters that encode file formats.
	* @json
	* @json_declaration
	* @public
	*/
	var ExporterSettings = class {
		/**
		* How many characters should be indented on formatted outputs. If set to negative values
		* formatted outputs are disabled.
		* @since 1.7.0
		* @defaultValue `2`
		* @category Exporter
		*/
		indent = 2;
		/**
		* Whether to write extended comments into the exported file (e.g. to in alphaTex to mark where certain metadata or bars starts)
		* @since 1.7.0
		* @defaultValue `false`
		* @category Exporter
		*/
		comments = false;
	};
	//#endregion
	//#region src/Settings.ts
	/**
	* This public class contains instance specific settings for alphaTab
	* @json
	* @json_declaration
	* @public
	*/
	var Settings = class Settings {
		/**
		* The core settings control the general behavior of alphatab like
		* what modules are active.
		* @json_on_parent
		* @json_partial_names
		*/
		core = new CoreSettings();
		/**
		* The display settings control how the general layout and display of alphaTab is done.
		* @json_on_parent
		* @json_partial_names
		*/
		display = new DisplaySettings();
		/**
		* The notation settings control how various music notation elements are shown and behaving.
		* @json_partial_names
		*/
		notation = new NotationSettings();
		/**
		* All settings related to importers that decode file formats.
		* @json_partial_names
		*/
		importer = new ImporterSettings();
		/**
		* Contains all player related settings
		* @json_partial_names
		*/
		player = new PlayerSettings();
		/**
		* All settings related to exporter that export file formats.
		* @json_partial_names
		*/
		exporter = new ExporterSettings();
		setSongBookModeSettings() {
			this.notation.notationMode = NotationMode.SongBook;
			this.notation.smallGraceTabNotes = false;
			this.notation.fingeringMode = FingeringMode.SingleNoteEffectBand;
			this.notation.extendBendArrowsOnTiedNotes = false;
			this.notation.elements.set(NotationElement.ParenthesisOnTiedBends, false);
			this.notation.elements.set(NotationElement.TabNotesOnTiedBends, false);
			this.notation.elements.set(NotationElement.ZerosOnDiveWhammys, true);
		}
		static get songBook() {
			const settings = new Settings();
			settings.setSongBookModeSettings();
			return settings;
		}
		/**
		* @target web
		*/
		fillFromJson(json) {
			SettingsSerializer.fromJson(this, json);
		}
		/**
		* handles backwards compatibility aspects on the settings, removed in 2.0
		* @internal
		*/
		handleBackwardsCompatibility() {
			if (this.player.playerMode === PlayerMode.Disabled && this.player.enablePlayer) this.player.playerMode = PlayerMode.EnabledAutomatic;
		}
	};
	//#endregion
	//#region src/importer/ScoreLoader.ts
	/**
	* The ScoreLoader enables you easy loading of Scores using all
	* available importers
	* @public
	*/
	var ScoreLoader = class ScoreLoader {
		/**
		* Loads the given alphaTex string.
		* @param tex The alphaTex string.
		* @param settings The settings to use for parsing.
		* @returns The parsed {@see Score}.
		*/
		static loadAlphaTex(tex, settings) {
			const parser = new AlphaTexImporter();
			parser.logErrors = true;
			parser.initFromString(tex, settings ?? new Settings());
			return parser.readScore();
		}
		/**
		* Loads a score asynchronously from the given datasource
		* @param path the source path to load the binary file from
		* @param success this function is called if the Score was successfully loaded from the datasource
		* @param error this function is called if any error during the loading occured.
		* @param settings settings for the score import
		* @target web
		*/
		static loadScoreAsync(path, success, error, settings) {
			const xhr = new XMLHttpRequest();
			xhr.open("GET", path, true, null, null);
			xhr.responseType = "arraybuffer";
			xhr.onreadystatechange = () => {
				if (xhr.readyState === XMLHttpRequest.DONE) {
					const response = xhr.response;
					if (xhr.status === 200 || xhr.status === 0 && response) try {
						const buffer = xhr.response;
						const reader = new Uint8Array(buffer);
						success(ScoreLoader.loadScoreFromBytes(reader, settings));
					} catch (e) {
						error(e);
					}
					else if (xhr.status === 0) error(new FileLoadError("You are offline!!\n Please Check Your Network.", xhr));
					else if (xhr.status === 404) error(new FileLoadError("Requested URL not found.", xhr));
					else if (xhr.status === 500) error(new FileLoadError("Internel Server Error.", xhr));
					else if (xhr.statusText === "parsererror") error(new FileLoadError("Error.\nParsing JSON Request failed.", xhr));
					else if (xhr.statusText === "timeout") error(new FileLoadError("Request Time out.", xhr));
					else error(new FileLoadError(`Unknow Error: ${xhr.responseText}`, xhr));
				}
			};
			xhr.send();
		}
		/**
		* Loads the score from the given binary data.
		* @param data The binary data containing a score in any known file format.
		* @param settings The settings to use during importing.
		* @returns The loaded score.
		*/
		static loadScoreFromBytes(data, settings) {
			if (!settings) settings = new Settings();
			const importers = Environment.buildImporters();
			Logger.debug("ScoreLoader", `Loading score from ${data.length} bytes using ${importers.length} importers`);
			let score = null;
			const readable = new ThrowingReadable(ByteBuffer.fromBuffer(data));
			for (const importer of importers) {
				readable.reset();
				try {
					Logger.debug("ScoreLoader", `Importing using importer ${importer.name}`);
					importer.init(readable, settings);
					score = importer.readScore();
					Logger.debug("ScoreLoader", `Score imported using ${importer.name}`);
					break;
				} catch (e) {
					if (e instanceof UnsupportedFormatError) Logger.debug("ScoreLoader", `${importer.name} does not support the file`);
					else {
						Logger.error("ScoreLoader", "Score import failed due to unexpected error: ", e);
						throw e;
					}
				}
			}
			if (score) return score;
			throw new UnsupportedFormatError("No compatible importer found for file");
		}
	};
	//#endregion
	//#region src/platform/javascript/BrowserMouseEventArgs.ts
	/**
	* @target web
	* @internal
	*/
	var BrowserMouseEventArgs = class {
		mouseEvent;
		get isLeftMouseButton() {
			return this.mouseEvent.button === 0;
		}
		getX(relativeTo) {
			const relativeToElement = relativeTo.element;
			const left = relativeToElement.getBoundingClientRect().left + relativeToElement.ownerDocument.defaultView.pageXOffset;
			return this.mouseEvent.pageX - left;
		}
		getY(relativeTo) {
			const relativeToElement = relativeTo.element;
			const top = relativeToElement.getBoundingClientRect().top + relativeToElement.ownerDocument.defaultView.pageYOffset;
			return this.mouseEvent.pageY - top;
		}
		preventDefault() {
			this.mouseEvent.preventDefault();
		}
		constructor(e) {
			this.mouseEvent = e;
		}
	};
	//#endregion
	//#region src/platform/javascript/HtmlElementContainer.ts
	/**
	* @target web
	* @internal
	*/
	var HtmlElementContainer = class HtmlElementContainer {
		static _resizeObserver = new Lazy(() => new ResizeObserver((entries) => {
			for (const e of entries) {
				const evt = new CustomEvent("resize", { detail: e });
				e.target.dispatchEvent(evt);
			}
		}));
		_resizeListeners = 0;
		get width() {
			return this.element.offsetWidth;
		}
		set width(value) {
			this.element.style.width = `${value}px`;
		}
		get scrollLeft() {
			return this.element.scrollLeft;
		}
		set scrollLeft(value) {
			this.element.scrollLeft = value;
		}
		get scrollTop() {
			return this.element.scrollTop;
		}
		set scrollTop(value) {
			this.element.scrollTop = value;
		}
		get height() {
			return this.element.offsetHeight;
		}
		set height(value) {
			if (value >= 0) this.element.style.height = `${value}px`;
			else this.element.style.height = "100%";
		}
		get isVisible() {
			return !!this.element.offsetWidth || !!this.element.offsetHeight || !!this.element.getClientRects().length;
		}
		element;
		constructor(element) {
			this.element = element;
			this.mouseDown = {
				on: (value) => {
					const nativeListener = (e) => {
						value(new BrowserMouseEventArgs(e));
					};
					this.element.addEventListener("mousedown", nativeListener, true);
					return () => {
						this.element.removeEventListener("mousedown", nativeListener, true);
					};
				},
				off: (_value) => {}
			};
			this.mouseUp = {
				on: (value) => {
					const nativeListener = (e) => {
						value(new BrowserMouseEventArgs(e));
					};
					this.element.addEventListener("mouseup", nativeListener, true);
					return () => {
						this.element.removeEventListener("mouseup", nativeListener, true);
					};
				},
				off: (_value) => {}
			};
			this.mouseMove = {
				on: (value) => {
					const nativeListener = (e) => {
						value(new BrowserMouseEventArgs(e));
					};
					this.element.addEventListener("mousemove", nativeListener, true);
					return () => {
						this.element.removeEventListener("mousemove", nativeListener, true);
					};
				},
				off: (_) => {}
			};
			const container = this;
			this.resize = {
				on: function(value) {
					if (container._resizeListeners === 0) HtmlElementContainer._resizeObserver.value.observe(container.element);
					container.element.addEventListener("resize", value, true);
					container._resizeListeners++;
					return () => this.off(value);
				},
				off: (value) => {
					this.element.removeEventListener("resize", value, true);
					this._resizeListeners--;
					if (this._resizeListeners <= 0) {
						this._resizeListeners = 0;
						HtmlElementContainer._resizeObserver.value.unobserve(this.element);
					}
				}
			};
		}
		stopAnimation() {
			this.element.style.transition = "none";
		}
		transitionToX(duration, x) {
			this.element.style.transition = `transform ${duration}ms linear`;
			this.setBounds(x, NaN, NaN, NaN);
		}
		lastBounds = new Bounds();
		setBounds(x, y, w, h) {
			if (Number.isNaN(x)) x = this.lastBounds.x;
			if (Number.isNaN(y)) y = this.lastBounds.y;
			if (Number.isNaN(w)) w = this.lastBounds.w;
			if (Number.isNaN(h)) h = this.lastBounds.h;
			this.element.style.transform = `translate(${x}px, ${y}px) scale(${w}, ${h})`;
			this.element.style.transformOrigin = "top left";
			this.lastBounds.x = x;
			this.lastBounds.y = y;
			this.lastBounds.w = w;
			this.lastBounds.h = h;
		}
		/**
		* This event occurs when the control was resized.
		*/
		resize;
		/**
		* This event occurs when a mouse/finger press happened on the control.
		*/
		mouseDown;
		/**
		* This event occurs when a mouse/finger moves on top of the control.
		*/
		mouseMove;
		/**
		* This event occurs when a mouse/finger is released from the control.
		*/
		mouseUp;
		appendChild(child) {
			this.element.appendChild(child.element);
		}
		clear() {
			this.element.innerText = "";
		}
	};
	//#endregion
	//#region src/platform/javascript/WebPlatform.ts
	/**
	* Lists all web specific platforms alphaTab might run in
	* like browser, nodejs.
	* @public
	*/
	var WebPlatform = /* @__PURE__ */ function(WebPlatform) {
		WebPlatform[WebPlatform["Browser"] = 0] = "Browser";
		WebPlatform[WebPlatform["NodeJs"] = 1] = "NodeJs";
		WebPlatform[WebPlatform["BrowserModule"] = 2] = "BrowserModule";
		return WebPlatform;
	}({});
	//#endregion
	//#region src/platform/svg/FontSizes.ts
	/**
	* Describes the sizes of a font for measuring purposes.
	* @internal
	*/
	var FontSizeDefinition = class {
		/**
		* The widths of each character starting with the ascii code 0x20 at index 0.
		*/
		characterWidths;
		/**
		* The heights of each character starting with the ascii code 0x20 at index 0.
		*/
		characterHeights;
		constructor(characterWidths, characterHeights) {
			this.characterWidths = characterWidths;
			this.characterHeights = characterHeights;
		}
	};
	/**
	* This public class stores text widths for several fonts and allows width calculation
	* @partial
	* @internal
	*/
	var FontSizes = class FontSizes {
		static fontSizeLookupTables = /* @__PURE__ */ new Map();
		static ControlChars = 32;
		/**
		* @target web
		* @partial
		*/
		static generateFontLookup(family) {
			if (FontSizes.fontSizeLookupTables.has(family)) return;
			if (!Environment.isRunningInWorker && Environment.webPlatform !== WebPlatform.NodeJs) {
				const measureContext = document.createElement("canvas").getContext("2d");
				measureContext.font = `11px ${family}`;
				const widths = [];
				const heights = [];
				for (let i = FontSizes.ControlChars; i < 255; i++) {
					const s = String.fromCharCode(i);
					const metrics = measureContext.measureText(s);
					widths.push(metrics.width);
					const height = metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent;
					heights.push(height);
				}
				const data = new FontSizeDefinition(new Uint8Array(widths), new Uint8Array(heights));
				FontSizes.fontSizeLookupTables.set(family, data);
			} else {
				const data = new FontSizeDefinition(new Uint8Array([8]), new Uint8Array([10]));
				FontSizes.fontSizeLookupTables.set(family, data);
			}
		}
		static measureString(s, families, size, style, weight) {
			let data;
			const dataSize = 11;
			let family = families[0];
			for (let i = 0; i < families.length; i++) if (FontSizes.fontSizeLookupTables.has(families[i])) {
				family = families[i];
				break;
			}
			if (!FontSizes.fontSizeLookupTables.has(family)) FontSizes.generateFontLookup(family);
			data = FontSizes.fontSizeLookupTables.get(family);
			let factor = 1;
			if (style === FontStyle.Italic) factor *= 1.1;
			if (weight === FontWeight.Bold) factor *= 1.1;
			let stringSize = 0;
			let stringHeight = 0;
			for (let i = 0; i < s.length; i++) {
				const code = Math.min(data.characterWidths.length - 1, s.charCodeAt(i) - FontSizes.ControlChars);
				if (code >= 0) {
					stringSize += data.characterWidths[code] * size / dataSize;
					stringHeight = Math.max(stringHeight, data.characterHeights[code] * size / dataSize);
				}
			}
			factor *= 1.07;
			return new MeasuredText(stringSize * factor, stringHeight);
		}
	};
	//#endregion
	//#region src/util/FontLoadingChecker.ts
	/**
	* This small utility helps to detect whether a particular font is already loaded.
	* @target web
	* @internal
	*/
	var FontLoadingChecker = class {
		_originalFamilies;
		_families;
		_isStarted = false;
		isFontLoaded = false;
		fontLoaded = new EventEmitterOfT();
		constructor(families) {
			this._originalFamilies = families;
			this._families = families;
		}
		checkForFontAvailability() {
			if (Environment.isRunningInWorker) {
				this.isFontLoaded = false;
				return;
			}
			if (this._isStarted) return;
			this._isStarted = true;
			let failCounter = 0;
			const failCounterId = window.setInterval(() => {
				Logger.warning("Rendering", `Could not load font '${this._families[0]}' within ${(failCounter + 1) * 5} seconds`, null);
				if (this._families.length > 1) {
					this._families.shift();
					failCounter = 0;
				} else failCounter++;
			}, 5e3);
			Logger.debug("Font", `Start checking for font availablility: ${this._families.join(", ")}`);
			const errorHandler = (e) => {
				if (this._families.length > 1) {
					Logger.debug("Font", `[${this._families[0]}] Loading Failed, switching to ${this._families[1]}`, e);
					this._families.shift();
					window.setTimeout(() => {
						checkFont();
					}, 0);
				} else {
					Logger.error("Font", `[${this._originalFamilies.join(",")}] Loading Failed, rendering cannot start`, e);
					window.clearInterval(failCounterId);
				}
			};
			const successHandler = (font) => {
				Logger.debug("Font", `[${font}] Font API signaled available`);
				this.isFontLoaded = true;
				window.clearInterval(failCounterId);
				this.fontLoaded.trigger(this._families[0]);
			};
			const checkFont = async () => {
				for (const font of this._families) if (await this._isFontAvailable(font, false)) {
					successHandler(font);
					return;
				}
				try {
					await document.fonts.load(`1em ${this._families[0]}`);
				} catch (e) {
					errorHandler(e);
				}
				Logger.debug("Font", `[${this._families[0]}] Font API signaled loaded`);
				if (await this._isFontAvailable(this._families[0], true)) successHandler(this._families[0]);
				else errorHandler("Font not available");
				return true;
			};
			document.fonts.ready.then(() => {
				checkFont();
			});
		}
		_isFontAvailable(family, advancedCheck) {
			return new Promise((resolve) => {
				const fontString = `1em ${family}`;
				if (document.fonts.check(fontString)) resolve(true);
				else if (advancedCheck) {
					Logger.debug("Font", `Font ${family} not available, creating test element to trigger load`);
					const testElement = document.createElement("div");
					testElement.style.font = fontString;
					testElement.style.opacity = "0";
					testElement.style.position = "absolute";
					testElement.style.top = "0";
					testElement.style.left = "0";
					testElement.innerText = `Trigger ${family} load`;
					document.body.appendChild(testElement);
					setTimeout(() => {
						document.body.removeChild(testElement);
						if (document.fonts.check(fontString)) resolve(true);
						else resolve(false);
					}, 200);
				} else resolve(false);
			});
		}
	};
	//#endregion
	//#region src/synth/ds/CircularSampleBuffer.ts
	/**
	* Represents a fixed size circular sample buffer that can be written to and read from.
	* @internal
	*/
	var CircularSampleBuffer = class {
		_buffer;
		_writePosition = 0;
		_readPosition = 0;
		/**
		* Gets the number of samples written to the buffer.
		*/
		count = 0;
		/**
		* Initializes a new instance of the {@link CircularSampleBuffer} class.
		* @param size The size.
		*/
		constructor(size) {
			this._buffer = new Float32Array(size);
		}
		/**
		* Clears all samples written to this buffer.
		*/
		clear() {
			this._readPosition = 0;
			this._writePosition = 0;
			this.count = 0;
			this._buffer = new Float32Array(this._buffer.length);
		}
		/**
		* Writes the given samples to this buffer.
		* @param data The sample array to read from.
		* @param offset
		* @param count
		* @returns
		*/
		write(data, offset, count) {
			let samplesWritten = 0;
			if (count > this._buffer.length - this.count) count = this._buffer.length - this.count;
			const writeToEnd = Math.min(this._buffer.length - this._writePosition, count);
			this._buffer.set(data.subarray(offset, offset + writeToEnd), this._writePosition);
			this._writePosition += writeToEnd;
			this._writePosition %= this._buffer.length;
			samplesWritten += writeToEnd;
			if (samplesWritten < count) {
				this._buffer.set(data.subarray(offset + samplesWritten, offset + samplesWritten + count - samplesWritten), this._writePosition);
				this._writePosition += count - samplesWritten;
				samplesWritten = count;
			}
			this.count += samplesWritten;
			return samplesWritten;
		}
		/**
		* Reads the requested amount of samples from the buffer.
		* @param data The sample array to store the read elements.
		* @param offset The offset within the destination buffer to put the items at.
		* @param count The number of items to read from this buffer.
		* @returns The number of items actually read from the buffer.
		*/
		read(data, offset, count) {
			if (count > this.count) count = this.count;
			let samplesRead = 0;
			const readToEnd = Math.min(this._buffer.length - this._readPosition, count);
			data.set(this._buffer.subarray(this._readPosition, this._readPosition + readToEnd), offset);
			samplesRead += readToEnd;
			this._readPosition += readToEnd;
			this._readPosition %= this._buffer.length;
			if (samplesRead < count) {
				data.set(this._buffer.subarray(this._readPosition, this._readPosition + count - samplesRead), offset + samplesRead);
				this._readPosition += count - samplesRead;
				samplesRead = count;
			}
			this.count -= samplesRead;
			return samplesRead;
		}
	};
	//#endregion
	//#region src/platform/javascript/AlphaSynthScriptProcessorOutput.ts
	/**
	* This class implements a HTML5 Web Audio API based audio output device
	* for alphaSynth using the legacy ScriptProcessor node.
	* @target web
	* @internal
	*/
	var AlphaSynthScriptProcessorOutput = class extends AlphaSynthWebAudioOutputBase {
		_audioNode = null;
		_circularBuffer;
		_bufferCount = 0;
		_requestedBufferCount = 0;
		open(bufferTimeInMilliseconds) {
			super.open(bufferTimeInMilliseconds);
			this._bufferCount = Math.floor(bufferTimeInMilliseconds * this.sampleRate / 1e3 / AlphaSynthWebAudioOutputBase.BufferSize);
			this._circularBuffer = new CircularSampleBuffer(AlphaSynthWebAudioOutputBase.BufferSize * this._bufferCount);
			this.onReady();
		}
		play() {
			super.play();
			const ctx = this.context;
			this._audioNode = ctx.createScriptProcessor(4096, 0, 2);
			this._audioNode.onaudioprocess = this._generateSound.bind(this);
			this._circularBuffer.clear();
			this._requestBuffers();
			this.source = ctx.createBufferSource();
			this.source.buffer = this.buffer;
			this.source.loop = true;
			this.source.connect(this._audioNode, 0, 0);
			this.source.start(0);
			this._audioNode.connect(ctx.destination, 0, 0);
		}
		pause() {
			super.pause();
			if (this._audioNode) this._audioNode.disconnect(0);
			this._audioNode = null;
		}
		addSamples(f) {
			this._circularBuffer.write(f, 0, f.length);
			this._requestedBufferCount--;
		}
		resetSamples() {
			this._circularBuffer.clear();
		}
		_requestBuffers() {
			const halfBufferCount = this._bufferCount / 2 | 0;
			const halfSamples = halfBufferCount * AlphaSynthWebAudioOutputBase.BufferSize;
			if (this._circularBuffer.count + this._requestedBufferCount * AlphaSynthWebAudioOutputBase.BufferSize < halfSamples) {
				for (let i = 0; i < halfBufferCount; i++) this.onSampleRequest();
				this._requestedBufferCount += halfBufferCount;
			}
		}
		_outputBuffer = new Float32Array(0);
		_generateSound(e) {
			const left = e.outputBuffer.getChannelData(0);
			const right = e.outputBuffer.getChannelData(1);
			const samples = left.length + right.length;
			let buffer = this._outputBuffer;
			if (buffer.length !== samples) {
				buffer = new Float32Array(samples);
				this._outputBuffer = buffer;
			}
			const samplesFromBuffer = this._circularBuffer.read(buffer, 0, Math.min(buffer.length, this._circularBuffer.count));
			let s = 0;
			const min = Math.min(left.length, samplesFromBuffer);
			for (let i = 0; i < min; i++) {
				left[i] = buffer[s++];
				right[i] = buffer[s++];
			}
			if (samplesFromBuffer < left.length) for (let i = samplesFromBuffer; i < left.length; i++) {
				left[i] = 0;
				right[i] = 0;
			}
			this.onSamplesPlayed(samplesFromBuffer / SynthConstants.AudioChannels);
			this._requestBuffers();
		}
	};
	//#endregion
	//#region src/generated/model/BeamingRulesSerializer.ts
	/**
	* @internal
	*/
	var BeamingRulesSerializer = class BeamingRulesSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => BeamingRulesSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			{
				const m = /* @__PURE__ */ new Map();
				o.set("groups", m);
				for (const [k, v] of obj.groups) m.set(k.toString(), v);
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "groups":
					obj.groups = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.groups.set(JsonHelper.parseEnum(k, Duration), v);
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/SectionSerializer.ts
	/**
	* @internal
	*/
	var SectionSerializer = class SectionSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => SectionSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("marker", obj.marker);
			o.set("text", obj.text);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "marker":
					obj.marker = v;
					return true;
				case "text":
					obj.text = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/SyncPointDataSerializer.ts
	/**
	* @internal
	*/
	var SyncPointDataSerializer = class SyncPointDataSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => SyncPointDataSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("baroccurence", obj.barOccurence);
			o.set("millisecondoffset", obj.millisecondOffset);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "baroccurence":
					obj.barOccurence = v;
					return true;
				case "millisecondoffset":
					obj.millisecondOffset = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/AutomationSerializer.ts
	/**
	* @internal
	*/
	var AutomationSerializer = class AutomationSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => AutomationSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("islinear", obj.isLinear);
			o.set("type", obj.type);
			o.set("value", obj.value);
			if (obj.syncPointValue) o.set("syncpointvalue", SyncPointDataSerializer.toJson(obj.syncPointValue));
			o.set("ratioposition", obj.ratioPosition);
			o.set("text", obj.text);
			o.set("isvisible", obj.isVisible);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "islinear":
					obj.isLinear = v;
					return true;
				case "type":
					obj.type = JsonHelper.parseEnum(v, AutomationType);
					return true;
				case "value":
					obj.value = v;
					return true;
				case "syncpointvalue":
					if (v) {
						obj.syncPointValue = new SyncPointData();
						SyncPointDataSerializer.fromJson(obj.syncPointValue, v);
					} else obj.syncPointValue = void 0;
					return true;
				case "ratioposition":
					obj.ratioPosition = v;
					return true;
				case "text":
					obj.text = v;
					return true;
				case "isvisible":
					obj.isVisible = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/FermataSerializer.ts
	/**
	* @internal
	*/
	var FermataSerializer = class FermataSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => FermataSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("type", obj.type);
			o.set("length", obj.length);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "type":
					obj.type = JsonHelper.parseEnum(v, FermataType);
					return true;
				case "length":
					obj.length = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/MasterBarSerializer.ts
	/**
	* @internal
	*/
	var MasterBarSerializer = class MasterBarSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => MasterBarSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("alternateendings", obj.alternateEndings);
			o.set("isdoublebar", obj.isDoubleBar);
			o.set("isrepeatstart", obj.isRepeatStart);
			o.set("repeatcount", obj.repeatCount);
			o.set("timesignaturenumerator", obj.timeSignatureNumerator);
			o.set("timesignaturedenominator", obj.timeSignatureDenominator);
			o.set("timesignaturecommon", obj.timeSignatureCommon);
			if (obj.beamingRules) o.set("beamingrules", BeamingRulesSerializer.toJson(obj.beamingRules));
			o.set("isfreetime", obj.isFreeTime);
			o.set("tripletfeel", obj.tripletFeel);
			if (obj.section) o.set("section", SectionSerializer.toJson(obj.section));
			o.set("tempoautomations", obj.tempoAutomations.map((i) => AutomationSerializer.toJson(i)));
			if (obj.syncPoints !== void 0) o.set("syncpoints", obj.syncPoints?.map((i) => AutomationSerializer.toJson(i)));
			if (obj.fermata !== null) {
				const m = /* @__PURE__ */ new Map();
				o.set("fermata", m);
				for (const [k, v] of obj.fermata) m.set(k.toString(), FermataSerializer.toJson(v));
			}
			o.set("start", obj.start);
			o.set("isanacrusis", obj.isAnacrusis);
			o.set("displayscale", obj.displayScale);
			o.set("displaywidth", obj.displayWidth);
			if (obj.directions !== null) {
				const a = [];
				o.set("directions", a);
				for (const v of obj.directions) a.push(v);
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "alternateendings":
					obj.alternateEndings = v;
					return true;
				case "isdoublebar":
					obj.isDoubleBar = v;
					return true;
				case "isrepeatstart":
					obj.isRepeatStart = v;
					return true;
				case "repeatcount":
					obj.repeatCount = v;
					return true;
				case "timesignaturenumerator":
					obj.timeSignatureNumerator = v;
					return true;
				case "timesignaturedenominator":
					obj.timeSignatureDenominator = v;
					return true;
				case "timesignaturecommon":
					obj.timeSignatureCommon = v;
					return true;
				case "beamingrules":
					if (v) {
						obj.beamingRules = new BeamingRules();
						BeamingRulesSerializer.fromJson(obj.beamingRules, v);
					} else obj.beamingRules = void 0;
					return true;
				case "isfreetime":
					obj.isFreeTime = v;
					return true;
				case "tripletfeel":
					obj.tripletFeel = JsonHelper.parseEnum(v, TripletFeel);
					return true;
				case "section":
					if (v) {
						obj.section = new Section();
						SectionSerializer.fromJson(obj.section, v);
					} else obj.section = null;
					return true;
				case "tempoautomations":
					obj.tempoAutomations = [];
					for (const o of v) {
						const i = new Automation();
						AutomationSerializer.fromJson(i, o);
						obj.tempoAutomations.push(i);
					}
					return true;
				case "syncpoints":
					if (v) {
						obj.syncPoints = [];
						for (const o of v) {
							const i = new Automation();
							AutomationSerializer.fromJson(i, o);
							obj.addSyncPoint(i);
						}
					}
					return true;
				case "fermata":
					obj.fermata = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						const i = new Fermata();
						FermataSerializer.fromJson(i, v);
						obj.addFermata(Number.parseInt(k), i);
					});
					return true;
				case "start":
					obj.start = v;
					return true;
				case "isanacrusis":
					obj.isAnacrusis = v;
					return true;
				case "displayscale":
					obj.displayScale = v;
					return true;
				case "displaywidth":
					obj.displayWidth = v;
					return true;
				case "directions":
					for (const i of v) obj.addDirection(JsonHelper.parseEnum(i, Direction));
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/BendPointSerializer.ts
	/**
	* @internal
	*/
	var BendPointSerializer = class BendPointSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => BendPointSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("offset", obj.offset);
			o.set("value", obj.value);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "offset":
					obj.offset = v;
					return true;
				case "value":
					obj.value = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/NoteStyleSerializer.ts
	/**
	* @internal
	*/
	var NoteStyleSerializer = class NoteStyleSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => NoteStyleSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("notehead", obj.noteHead);
			o.set("noteheadcenteronstem", obj.noteHeadCenterOnStem);
			{
				const m = /* @__PURE__ */ new Map();
				o.set("colors", m);
				for (const [k, v] of obj.colors) m.set(k.toString(), Color.toJson(v));
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "notehead":
					obj.noteHead = JsonHelper.parseEnum(v, MusicFontSymbol);
					return true;
				case "noteheadcenteronstem":
					obj.noteHeadCenterOnStem = v;
					return true;
				case "colors":
					obj.colors = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.colors.set(JsonHelper.parseEnum(k, NoteSubElement), Color.fromJson(v));
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/NoteSerializer.ts
	/**
	* @internal
	*/
	var NoteSerializer = class NoteSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => NoteSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("id", obj.id);
			o.set("accentuated", obj.accentuated);
			o.set("bendtype", obj.bendType);
			o.set("bendstyle", obj.bendStyle);
			o.set("iscontinuedbend", obj.isContinuedBend);
			if (obj.bendPoints !== null) o.set("bendpoints", obj.bendPoints?.map((i) => BendPointSerializer.toJson(i)));
			o.set("fret", obj.fret);
			o.set("string", obj.string);
			o.set("showstringnumber", obj.showStringNumber);
			o.set("octave", obj.octave);
			o.set("tone", obj.tone);
			o.set("percussionarticulation", obj.percussionArticulation);
			o.set("isvisible", obj.isVisible);
			o.set("islefthandtapped", obj.isLeftHandTapped);
			o.set("ishammerpullorigin", obj.isHammerPullOrigin);
			o.set("isslurdestination", obj.isSlurDestination);
			o.set("harmonictype", obj.harmonicType);
			o.set("harmonicvalue", obj.harmonicValue);
			o.set("isghost", obj.isGhost);
			o.set("isletring", obj.isLetRing);
			o.set("ispalmmute", obj.isPalmMute);
			o.set("isdead", obj.isDead);
			o.set("isstaccato", obj.isStaccato);
			o.set("slideintype", obj.slideInType);
			o.set("slideouttype", obj.slideOutType);
			o.set("vibrato", obj.vibrato);
			o.set("istiedestination", obj.isTieDestination);
			o.set("lefthandfinger", obj.leftHandFinger);
			o.set("righthandfinger", obj.rightHandFinger);
			o.set("trillvalue", obj.trillValue);
			o.set("trillspeed", obj.trillSpeed);
			o.set("durationpercent", obj.durationPercent);
			o.set("accidentalmode", obj.accidentalMode);
			o.set("dynamics", obj.dynamics);
			o.set("ornament", obj.ornament);
			if (obj.style) o.set("style", NoteStyleSerializer.toJson(obj.style));
			obj.toJson(o);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "id":
					obj.id = v;
					return true;
				case "accentuated":
					obj.accentuated = JsonHelper.parseEnum(v, AccentuationType);
					return true;
				case "bendtype":
					obj.bendType = JsonHelper.parseEnum(v, BendType);
					return true;
				case "bendstyle":
					obj.bendStyle = JsonHelper.parseEnum(v, BendStyle);
					return true;
				case "iscontinuedbend":
					obj.isContinuedBend = v;
					return true;
				case "bendpoints":
					if (v) {
						obj.bendPoints = [];
						for (const o of v) {
							const i = new BendPoint();
							BendPointSerializer.fromJson(i, o);
							obj.addBendPoint(i);
						}
					}
					return true;
				case "fret":
					obj.fret = v;
					return true;
				case "string":
					obj.string = v;
					return true;
				case "showstringnumber":
					obj.showStringNumber = v;
					return true;
				case "octave":
					obj.octave = v;
					return true;
				case "tone":
					obj.tone = v;
					return true;
				case "percussionarticulation":
					obj.percussionArticulation = v;
					return true;
				case "isvisible":
					obj.isVisible = v;
					return true;
				case "islefthandtapped":
					obj.isLeftHandTapped = v;
					return true;
				case "ishammerpullorigin":
					obj.isHammerPullOrigin = v;
					return true;
				case "isslurdestination":
					obj.isSlurDestination = v;
					return true;
				case "harmonictype":
					obj.harmonicType = JsonHelper.parseEnum(v, HarmonicType);
					return true;
				case "harmonicvalue":
					obj.harmonicValue = v;
					return true;
				case "isghost":
					obj.isGhost = v;
					return true;
				case "isletring":
					obj.isLetRing = v;
					return true;
				case "ispalmmute":
					obj.isPalmMute = v;
					return true;
				case "isdead":
					obj.isDead = v;
					return true;
				case "isstaccato":
					obj.isStaccato = v;
					return true;
				case "slideintype":
					obj.slideInType = JsonHelper.parseEnum(v, SlideInType);
					return true;
				case "slideouttype":
					obj.slideOutType = JsonHelper.parseEnum(v, SlideOutType);
					return true;
				case "vibrato":
					obj.vibrato = JsonHelper.parseEnum(v, VibratoType);
					return true;
				case "istiedestination":
					obj.isTieDestination = v;
					return true;
				case "lefthandfinger":
					obj.leftHandFinger = JsonHelper.parseEnum(v, Fingers);
					return true;
				case "righthandfinger":
					obj.rightHandFinger = JsonHelper.parseEnum(v, Fingers);
					return true;
				case "trillvalue":
					obj.trillValue = v;
					return true;
				case "trillspeed":
					obj.trillSpeed = JsonHelper.parseEnum(v, Duration);
					return true;
				case "durationpercent":
					obj.durationPercent = v;
					return true;
				case "accidentalmode":
					obj.accidentalMode = JsonHelper.parseEnum(v, NoteAccidentalMode);
					return true;
				case "dynamics":
					obj.dynamics = JsonHelper.parseEnum(v, DynamicValue);
					return true;
				case "ornament":
					obj.ornament = JsonHelper.parseEnum(v, NoteOrnament);
					return true;
				case "style":
					if (v) {
						obj.style = new NoteStyle();
						NoteStyleSerializer.fromJson(obj.style, v);
					} else obj.style = void 0;
					return true;
			}
			return obj.setProperty(property, v);
		}
	};
	//#endregion
	//#region src/generated/model/TremoloPickingEffectSerializer.ts
	/**
	* @internal
	*/
	var TremoloPickingEffectSerializer = class TremoloPickingEffectSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => TremoloPickingEffectSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("marks", obj.marks);
			o.set("style", obj.style);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "marks":
					obj.marks = v;
					return true;
				case "style":
					obj.style = JsonHelper.parseEnum(v, TremoloPickingStyle);
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/BeatStyleSerializer.ts
	/**
	* @internal
	*/
	var BeatStyleSerializer = class BeatStyleSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => BeatStyleSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			{
				const m = /* @__PURE__ */ new Map();
				o.set("colors", m);
				for (const [k, v] of obj.colors) m.set(k.toString(), Color.toJson(v));
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "colors":
					obj.colors = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.colors.set(JsonHelper.parseEnum(k, BeatSubElement), Color.fromJson(v));
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/BeatSerializer.ts
	/**
	* @internal
	*/
	var BeatSerializer = class BeatSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => BeatSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("id", obj.id);
			o.set("notes", obj.notes.map((i) => NoteSerializer.toJson(i)));
			o.set("isempty", obj.isEmpty);
			o.set("whammystyle", obj.whammyStyle);
			o.set("ottava", obj.ottava);
			o.set("islegatoorigin", obj.isLegatoOrigin);
			o.set("duration", obj.duration);
			o.set("automations", obj.automations.map((i) => AutomationSerializer.toJson(i)));
			o.set("dots", obj.dots);
			o.set("fade", obj.fade);
			o.set("lyrics", obj.lyrics);
			o.set("pop", obj.pop);
			o.set("slap", obj.slap);
			o.set("tap", obj.tap);
			o.set("text", obj.text);
			o.set("slashed", obj.slashed);
			o.set("deadslapped", obj.deadSlapped);
			o.set("brushtype", obj.brushType);
			o.set("brushduration", obj.brushDuration);
			o.set("tupletdenominator", obj.tupletDenominator);
			o.set("tupletnumerator", obj.tupletNumerator);
			o.set("iscontinuedwhammy", obj.isContinuedWhammy);
			o.set("whammybartype", obj.whammyBarType);
			if (obj.whammyBarPoints !== null) o.set("whammybarpoints", obj.whammyBarPoints?.map((i) => BendPointSerializer.toJson(i)));
			o.set("vibrato", obj.vibrato);
			o.set("chordid", obj.chordId);
			o.set("gracetype", obj.graceType);
			o.set("pickstroke", obj.pickStroke);
			if (obj.tremoloPicking) o.set("tremolopicking", TremoloPickingEffectSerializer.toJson(obj.tremoloPicking));
			o.set("crescendo", obj.crescendo);
			o.set("displaystart", obj.displayStart);
			o.set("playbackstart", obj.playbackStart);
			o.set("displayduration", obj.displayDuration);
			o.set("playbackduration", obj.playbackDuration);
			o.set("overridedisplayduration", obj.overrideDisplayDuration);
			o.set("golpe", obj.golpe);
			o.set("dynamics", obj.dynamics);
			o.set("invertbeamdirection", obj.invertBeamDirection);
			o.set("preferredbeamdirection", obj.preferredBeamDirection);
			o.set("beamingmode", obj.beamingMode);
			o.set("wahpedal", obj.wahPedal);
			o.set("barrefret", obj.barreFret);
			o.set("barreshape", obj.barreShape);
			o.set("rasgueado", obj.rasgueado);
			o.set("showtimer", obj.showTimer);
			o.set("timer", obj.timer);
			if (obj.style) o.set("style", BeatStyleSerializer.toJson(obj.style));
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "id":
					obj.id = v;
					return true;
				case "notes":
					obj.notes = [];
					for (const o of v) {
						const i = new Note();
						NoteSerializer.fromJson(i, o);
						obj.addNote(i);
					}
					return true;
				case "isempty":
					obj.isEmpty = v;
					return true;
				case "whammystyle":
					obj.whammyStyle = JsonHelper.parseEnum(v, BendStyle);
					return true;
				case "ottava":
					obj.ottava = JsonHelper.parseEnum(v, Ottavia);
					return true;
				case "islegatoorigin":
					obj.isLegatoOrigin = v;
					return true;
				case "duration":
					obj.duration = JsonHelper.parseEnum(v, Duration);
					return true;
				case "automations":
					obj.automations = [];
					for (const o of v) {
						const i = new Automation();
						AutomationSerializer.fromJson(i, o);
						obj.automations.push(i);
					}
					return true;
				case "dots":
					obj.dots = v;
					return true;
				case "fade":
					obj.fade = JsonHelper.parseEnum(v, FadeType);
					return true;
				case "lyrics":
					obj.lyrics = v;
					return true;
				case "pop":
					obj.pop = v;
					return true;
				case "slap":
					obj.slap = v;
					return true;
				case "tap":
					obj.tap = v;
					return true;
				case "text":
					obj.text = v;
					return true;
				case "slashed":
					obj.slashed = v;
					return true;
				case "deadslapped":
					obj.deadSlapped = v;
					return true;
				case "brushtype":
					obj.brushType = JsonHelper.parseEnum(v, BrushType);
					return true;
				case "brushduration":
					obj.brushDuration = v;
					return true;
				case "tupletdenominator":
					obj.tupletDenominator = v;
					return true;
				case "tupletnumerator":
					obj.tupletNumerator = v;
					return true;
				case "iscontinuedwhammy":
					obj.isContinuedWhammy = v;
					return true;
				case "whammybartype":
					obj.whammyBarType = JsonHelper.parseEnum(v, WhammyType);
					return true;
				case "whammybarpoints":
					if (v) {
						obj.whammyBarPoints = [];
						for (const o of v) {
							const i = new BendPoint();
							BendPointSerializer.fromJson(i, o);
							obj.addWhammyBarPoint(i);
						}
					}
					return true;
				case "vibrato":
					obj.vibrato = JsonHelper.parseEnum(v, VibratoType);
					return true;
				case "chordid":
					obj.chordId = v;
					return true;
				case "gracetype":
					obj.graceType = JsonHelper.parseEnum(v, GraceType);
					return true;
				case "pickstroke":
					obj.pickStroke = JsonHelper.parseEnum(v, PickStroke);
					return true;
				case "tremolopicking":
					if (v) {
						obj.tremoloPicking = new TremoloPickingEffect();
						TremoloPickingEffectSerializer.fromJson(obj.tremoloPicking, v);
					} else obj.tremoloPicking = void 0;
					return true;
				case "crescendo":
					obj.crescendo = JsonHelper.parseEnum(v, CrescendoType);
					return true;
				case "displaystart":
					obj.displayStart = v;
					return true;
				case "playbackstart":
					obj.playbackStart = v;
					return true;
				case "displayduration":
					obj.displayDuration = v;
					return true;
				case "playbackduration":
					obj.playbackDuration = v;
					return true;
				case "overridedisplayduration":
					obj.overrideDisplayDuration = v;
					return true;
				case "golpe":
					obj.golpe = JsonHelper.parseEnum(v, GolpeType);
					return true;
				case "dynamics":
					obj.dynamics = JsonHelper.parseEnum(v, DynamicValue);
					return true;
				case "invertbeamdirection":
					obj.invertBeamDirection = v;
					return true;
				case "preferredbeamdirection":
					obj.preferredBeamDirection = JsonHelper.parseEnum(v, BeamDirection) ?? null;
					return true;
				case "beamingmode":
					obj.beamingMode = JsonHelper.parseEnum(v, BeatBeamingMode);
					return true;
				case "wahpedal":
					obj.wahPedal = JsonHelper.parseEnum(v, WahPedal);
					return true;
				case "barrefret":
					obj.barreFret = v;
					return true;
				case "barreshape":
					obj.barreShape = JsonHelper.parseEnum(v, BarreShape);
					return true;
				case "rasgueado":
					obj.rasgueado = JsonHelper.parseEnum(v, Rasgueado);
					return true;
				case "showtimer":
					obj.showTimer = v;
					return true;
				case "timer":
					obj.timer = v;
					return true;
				case "style":
					if (v) {
						obj.style = new BeatStyle();
						BeatStyleSerializer.fromJson(obj.style, v);
					} else obj.style = void 0;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/VoiceStyleSerializer.ts
	/**
	* @internal
	*/
	var VoiceStyleSerializer = class VoiceStyleSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => VoiceStyleSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			{
				const m = /* @__PURE__ */ new Map();
				o.set("colors", m);
				for (const [k, v] of obj.colors) m.set(k.toString(), Color.toJson(v));
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "colors":
					obj.colors = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.colors.set(JsonHelper.parseEnum(k, VoiceSubElement), Color.fromJson(v));
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/VoiceSerializer.ts
	/**
	* @internal
	*/
	var VoiceSerializer = class VoiceSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => VoiceSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("id", obj.id);
			o.set("beats", obj.beats.map((i) => BeatSerializer.toJson(i)));
			if (obj.style) o.set("style", VoiceStyleSerializer.toJson(obj.style));
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "id":
					obj.id = v;
					return true;
				case "beats":
					obj.beats = [];
					for (const o of v) {
						const i = new Beat();
						BeatSerializer.fromJson(i, o);
						obj.addBeat(i);
					}
					return true;
				case "style":
					if (v) {
						obj.style = new VoiceStyle();
						VoiceStyleSerializer.fromJson(obj.style, v);
					} else obj.style = void 0;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/SustainPedalMarkerSerializer.ts
	/**
	* @internal
	*/
	var SustainPedalMarkerSerializer = class SustainPedalMarkerSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => SustainPedalMarkerSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("ratioposition", obj.ratioPosition);
			o.set("pedaltype", obj.pedalType);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "ratioposition":
					obj.ratioPosition = v;
					return true;
				case "pedaltype":
					obj.pedalType = JsonHelper.parseEnum(v, SustainPedalMarkerType);
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/BarStyleSerializer.ts
	/**
	* @internal
	*/
	var BarStyleSerializer = class BarStyleSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => BarStyleSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			{
				const m = /* @__PURE__ */ new Map();
				o.set("colors", m);
				for (const [k, v] of obj.colors) m.set(k.toString(), Color.toJson(v));
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "colors":
					obj.colors = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.colors.set(JsonHelper.parseEnum(k, BarSubElement), Color.fromJson(v));
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/BarSerializer.ts
	/**
	* @internal
	*/
	var BarSerializer = class BarSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => BarSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("id", obj.id);
			o.set("clef", obj.clef);
			o.set("clefottava", obj.clefOttava);
			o.set("voices", obj.voices.map((i) => VoiceSerializer.toJson(i)));
			o.set("similemark", obj.simileMark);
			o.set("displayscale", obj.displayScale);
			o.set("displaywidth", obj.displayWidth);
			o.set("sustainpedals", obj.sustainPedals.map((i) => SustainPedalMarkerSerializer.toJson(i)));
			o.set("barlineleft", obj.barLineLeft);
			o.set("barlineright", obj.barLineRight);
			o.set("keysignature", obj.keySignature);
			o.set("keysignaturetype", obj.keySignatureType);
			o.set("barnumberdisplay", obj.barNumberDisplay);
			if (obj.style) o.set("style", BarStyleSerializer.toJson(obj.style));
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "id":
					obj.id = v;
					return true;
				case "clef":
					obj.clef = JsonHelper.parseEnum(v, Clef);
					return true;
				case "clefottava":
					obj.clefOttava = JsonHelper.parseEnum(v, Ottavia);
					return true;
				case "voices":
					obj.voices = [];
					for (const o of v) {
						const i = new Voice$1();
						VoiceSerializer.fromJson(i, o);
						obj.addVoice(i);
					}
					return true;
				case "similemark":
					obj.simileMark = JsonHelper.parseEnum(v, SimileMark);
					return true;
				case "displayscale":
					obj.displayScale = v;
					return true;
				case "displaywidth":
					obj.displayWidth = v;
					return true;
				case "sustainpedals":
					obj.sustainPedals = [];
					for (const o of v) {
						const i = new SustainPedalMarker();
						SustainPedalMarkerSerializer.fromJson(i, o);
						obj.sustainPedals.push(i);
					}
					return true;
				case "barlineleft":
					obj.barLineLeft = JsonHelper.parseEnum(v, BarLineStyle);
					return true;
				case "barlineright":
					obj.barLineRight = JsonHelper.parseEnum(v, BarLineStyle);
					return true;
				case "keysignature":
					obj.keySignature = JsonHelper.parseEnum(v, KeySignature);
					return true;
				case "keysignaturetype":
					obj.keySignatureType = JsonHelper.parseEnum(v, KeySignatureType);
					return true;
				case "barnumberdisplay":
					obj.barNumberDisplay = JsonHelper.parseEnum(v, BarNumberDisplay);
					return true;
				case "style":
					if (v) {
						obj.style = new BarStyle();
						BarStyleSerializer.fromJson(obj.style, v);
					} else obj.style = void 0;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/ChordSerializer.ts
	/**
	* @internal
	*/
	var ChordSerializer = class ChordSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => ChordSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("name", obj.name);
			o.set("firstfret", obj.firstFret);
			o.set("strings", obj.strings);
			o.set("barrefrets", obj.barreFrets);
			o.set("showname", obj.showName);
			o.set("showdiagram", obj.showDiagram);
			o.set("showfingering", obj.showFingering);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "name":
					obj.name = v;
					return true;
				case "firstfret":
					obj.firstFret = v;
					return true;
				case "strings":
					obj.strings = v;
					return true;
				case "barrefrets":
					obj.barreFrets = v;
					return true;
				case "showname":
					obj.showName = v;
					return true;
				case "showdiagram":
					obj.showDiagram = v;
					return true;
				case "showfingering":
					obj.showFingering = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/TuningSerializer.ts
	/**
	* @internal
	*/
	var TuningSerializer = class TuningSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => TuningSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("isstandard", obj.isStandard);
			o.set("name", obj.name);
			o.set("tunings", obj.tunings);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "isstandard":
					obj.isStandard = v;
					return true;
				case "name":
					obj.name = v;
					return true;
				case "tunings":
					obj.tunings = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/StaffSerializer.ts
	/**
	* @internal
	*/
	var StaffSerializer = class StaffSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => StaffSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("bars", obj.bars.map((i) => BarSerializer.toJson(i)));
			if (obj.chords !== null) {
				const m = /* @__PURE__ */ new Map();
				o.set("chords", m);
				for (const [k, v] of obj.chords) m.set(k.toString(), ChordSerializer.toJson(v));
			}
			o.set("capo", obj.capo);
			o.set("transpositionpitch", obj.transpositionPitch);
			o.set("displaytranspositionpitch", obj.displayTranspositionPitch);
			o.set("stringtuning", TuningSerializer.toJson(obj.stringTuning));
			o.set("showslash", obj.showSlash);
			o.set("shownumbered", obj.showNumbered);
			o.set("showtablature", obj.showTablature);
			o.set("showstandardnotation", obj.showStandardNotation);
			o.set("ispercussion", obj.isPercussion);
			o.set("standardnotationlinecount", obj.standardNotationLineCount);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "bars":
					obj.bars = [];
					for (const o of v) {
						const i = new Bar();
						BarSerializer.fromJson(i, o);
						obj.addBar(i);
					}
					return true;
				case "chords":
					obj.chords = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						const i = new Chord();
						ChordSerializer.fromJson(i, v);
						obj.addChord(k, i);
					});
					return true;
				case "capo":
					obj.capo = v;
					return true;
				case "transpositionpitch":
					obj.transpositionPitch = v;
					return true;
				case "displaytranspositionpitch":
					obj.displayTranspositionPitch = v;
					return true;
				case "stringtuning":
					TuningSerializer.fromJson(obj.stringTuning, v);
					return true;
				case "showslash":
					obj.showSlash = v;
					return true;
				case "shownumbered":
					obj.showNumbered = v;
					return true;
				case "showtablature":
					obj.showTablature = v;
					return true;
				case "showstandardnotation":
					obj.showStandardNotation = v;
					return true;
				case "ispercussion":
					obj.isPercussion = v;
					return true;
				case "standardnotationlinecount":
					obj.standardNotationLineCount = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/PlaybackInformationSerializer.ts
	/**
	* @internal
	*/
	var PlaybackInformationSerializer = class PlaybackInformationSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => PlaybackInformationSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("volume", obj.volume);
			o.set("balance", obj.balance);
			o.set("port", obj.port);
			o.set("program", obj.program);
			o.set("bank", obj.bank);
			o.set("primarychannel", obj.primaryChannel);
			o.set("secondarychannel", obj.secondaryChannel);
			o.set("ismute", obj.isMute);
			o.set("issolo", obj.isSolo);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "volume":
					obj.volume = v;
					return true;
				case "balance":
					obj.balance = v;
					return true;
				case "port":
					obj.port = v;
					return true;
				case "program":
					obj.program = v;
					return true;
				case "bank":
					obj.bank = v;
					return true;
				case "primarychannel":
					obj.primaryChannel = v;
					return true;
				case "secondarychannel":
					obj.secondaryChannel = v;
					return true;
				case "ismute":
					obj.isMute = v;
					return true;
				case "issolo":
					obj.isSolo = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/InstrumentArticulationSerializer.ts
	/**
	* @internal
	*/
	var InstrumentArticulationSerializer = class InstrumentArticulationSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => InstrumentArticulationSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("id", obj.id);
			o.set("elementtype", obj.elementType);
			o.set("staffline", obj.staffLine);
			o.set("noteheaddefault", obj.noteHeadDefault);
			o.set("noteheadhalf", obj.noteHeadHalf);
			o.set("noteheadwhole", obj.noteHeadWhole);
			o.set("techniquesymbol", obj.techniqueSymbol);
			o.set("techniquesymbolplacement", obj.techniqueSymbolPlacement);
			o.set("outputmidinumber", obj.outputMidiNumber);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "id":
					obj.id = v;
					return true;
				case "elementtype":
					obj.elementType = v;
					return true;
				case "staffline":
					obj.staffLine = v;
					return true;
				case "noteheaddefault":
					obj.noteHeadDefault = JsonHelper.parseEnum(v, MusicFontSymbol);
					return true;
				case "noteheadhalf":
					obj.noteHeadHalf = JsonHelper.parseEnum(v, MusicFontSymbol);
					return true;
				case "noteheadwhole":
					obj.noteHeadWhole = JsonHelper.parseEnum(v, MusicFontSymbol);
					return true;
				case "techniquesymbol":
					obj.techniqueSymbol = JsonHelper.parseEnum(v, MusicFontSymbol);
					return true;
				case "techniquesymbolplacement":
					obj.techniqueSymbolPlacement = JsonHelper.parseEnum(v, TechniqueSymbolPlacement);
					return true;
				case "outputmidinumber":
					obj.outputMidiNumber = v;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/TrackStyleSerializer.ts
	/**
	* @internal
	*/
	var TrackStyleSerializer = class TrackStyleSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => TrackStyleSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			{
				const m = /* @__PURE__ */ new Map();
				o.set("colors", m);
				for (const [k, v] of obj.colors) m.set(k.toString(), Color.toJson(v));
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "colors":
					obj.colors = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.colors.set(JsonHelper.parseEnum(k, TrackSubElement), Color.fromJson(v));
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/TrackSerializer.ts
	/**
	* @internal
	*/
	var TrackSerializer = class TrackSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => TrackSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("staves", obj.staves.map((i) => StaffSerializer.toJson(i)));
			o.set("playbackinfo", PlaybackInformationSerializer.toJson(obj.playbackInfo));
			o.set("color", Color.toJson(obj.color));
			o.set("name", obj.name);
			o.set("isvisibleonmultitrack", obj.isVisibleOnMultiTrack);
			o.set("shortname", obj.shortName);
			o.set("defaultsystemslayout", obj.defaultSystemsLayout);
			o.set("systemslayout", obj.systemsLayout);
			if (obj.lineBreaks !== void 0) {
				const a = [];
				o.set("linebreaks", a);
				for (const v of obj.lineBreaks) a.push(v);
			}
			o.set("percussionarticulations", obj.percussionArticulations.map((i) => InstrumentArticulationSerializer.toJson(i)));
			if (obj.style) o.set("style", TrackStyleSerializer.toJson(obj.style));
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "staves":
					obj.staves = [];
					for (const o of v) {
						const i = new Staff();
						StaffSerializer.fromJson(i, o);
						obj.addStaff(i);
					}
					return true;
				case "playbackinfo":
					PlaybackInformationSerializer.fromJson(obj.playbackInfo, v);
					return true;
				case "color":
					obj.color = Color.fromJson(v);
					return true;
				case "name":
					obj.name = v;
					return true;
				case "isvisibleonmultitrack":
					obj.isVisibleOnMultiTrack = v;
					return true;
				case "shortname":
					obj.shortName = v;
					return true;
				case "defaultsystemslayout":
					obj.defaultSystemsLayout = v;
					return true;
				case "systemslayout":
					obj.systemsLayout = v;
					return true;
				case "linebreaks":
					for (const i of v) obj.addLineBreaks(i);
					return true;
				case "percussionarticulations":
					obj.percussionArticulations = [];
					for (const o of v) {
						const i = new InstrumentArticulation();
						InstrumentArticulationSerializer.fromJson(i, o);
						obj.percussionArticulations.push(i);
					}
					return true;
				case "style":
					if (v) {
						obj.style = new TrackStyle();
						TrackStyleSerializer.fromJson(obj.style, v);
					} else obj.style = void 0;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/RenderStylesheetSerializer.ts
	/**
	* @internal
	*/
	var RenderStylesheetSerializer = class RenderStylesheetSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => RenderStylesheetSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("hidedynamics", obj.hideDynamics);
			o.set("bracketextendmode", obj.bracketExtendMode);
			o.set("usesystemsignseparator", obj.useSystemSignSeparator);
			o.set("globaldisplaytuning", obj.globalDisplayTuning);
			if (obj.perTrackDisplayTuning !== null) {
				const m = /* @__PURE__ */ new Map();
				o.set("pertrackdisplaytuning", m);
				for (const [k, v] of obj.perTrackDisplayTuning) m.set(k.toString(), v);
			}
			o.set("globaldisplaychorddiagramsontop", obj.globalDisplayChordDiagramsOnTop);
			if (obj.perTrackChordDiagramsOnTop !== null) {
				const m = /* @__PURE__ */ new Map();
				o.set("pertrackchorddiagramsontop", m);
				for (const [k, v] of obj.perTrackChordDiagramsOnTop) m.set(k.toString(), v);
			}
			o.set("globaldisplaychorddiagramsinscore", obj.globalDisplayChordDiagramsInScore);
			o.set("singletracktracknamepolicy", obj.singleTrackTrackNamePolicy);
			o.set("multitracktracknamepolicy", obj.multiTrackTrackNamePolicy);
			o.set("firstsystemtracknamemode", obj.firstSystemTrackNameMode);
			o.set("othersystemstracknamemode", obj.otherSystemsTrackNameMode);
			o.set("firstsystemtracknameorientation", obj.firstSystemTrackNameOrientation);
			o.set("othersystemstracknameorientation", obj.otherSystemsTrackNameOrientation);
			o.set("multitrackmultibarrest", obj.multiTrackMultiBarRest);
			if (obj.perTrackMultiBarRest !== null) {
				const a = [];
				o.set("pertrackmultibarrest", a);
				for (const v of obj.perTrackMultiBarRest) a.push(v);
			}
			o.set("extendbarlines", obj.extendBarLines);
			o.set("hideemptystaves", obj.hideEmptyStaves);
			o.set("hideemptystavesinfirstsystem", obj.hideEmptyStavesInFirstSystem);
			o.set("showsinglestaffbrackets", obj.showSingleStaffBrackets);
			o.set("barnumberdisplay", obj.barNumberDisplay);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "hidedynamics":
					obj.hideDynamics = v;
					return true;
				case "bracketextendmode":
					obj.bracketExtendMode = JsonHelper.parseEnum(v, BracketExtendMode);
					return true;
				case "usesystemsignseparator":
					obj.useSystemSignSeparator = v;
					return true;
				case "globaldisplaytuning":
					obj.globalDisplayTuning = v;
					return true;
				case "pertrackdisplaytuning":
					obj.perTrackDisplayTuning = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.perTrackDisplayTuning.set(Number.parseInt(k), v);
					});
					return true;
				case "globaldisplaychorddiagramsontop":
					obj.globalDisplayChordDiagramsOnTop = v;
					return true;
				case "pertrackchorddiagramsontop":
					obj.perTrackChordDiagramsOnTop = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.perTrackChordDiagramsOnTop.set(Number.parseInt(k), v);
					});
					return true;
				case "globaldisplaychorddiagramsinscore":
					obj.globalDisplayChordDiagramsInScore = v;
					return true;
				case "singletracktracknamepolicy":
					obj.singleTrackTrackNamePolicy = JsonHelper.parseEnum(v, TrackNamePolicy);
					return true;
				case "multitracktracknamepolicy":
					obj.multiTrackTrackNamePolicy = JsonHelper.parseEnum(v, TrackNamePolicy);
					return true;
				case "firstsystemtracknamemode":
					obj.firstSystemTrackNameMode = JsonHelper.parseEnum(v, TrackNameMode);
					return true;
				case "othersystemstracknamemode":
					obj.otherSystemsTrackNameMode = JsonHelper.parseEnum(v, TrackNameMode);
					return true;
				case "firstsystemtracknameorientation":
					obj.firstSystemTrackNameOrientation = JsonHelper.parseEnum(v, TrackNameOrientation);
					return true;
				case "othersystemstracknameorientation":
					obj.otherSystemsTrackNameOrientation = JsonHelper.parseEnum(v, TrackNameOrientation);
					return true;
				case "multitrackmultibarrest":
					obj.multiTrackMultiBarRest = v;
					return true;
				case "pertrackmultibarrest":
					obj.perTrackMultiBarRest = new Set(v);
					return true;
				case "extendbarlines":
					obj.extendBarLines = v;
					return true;
				case "hideemptystaves":
					obj.hideEmptyStaves = v;
					return true;
				case "hideemptystavesinfirstsystem":
					obj.hideEmptyStavesInFirstSystem = v;
					return true;
				case "showsinglestaffbrackets":
					obj.showSingleStaffBrackets = v;
					return true;
				case "barnumberdisplay":
					obj.barNumberDisplay = JsonHelper.parseEnum(v, BarNumberDisplay);
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/BackingTrackSerializer.ts
	/**
	* @internal
	*/
	var BackingTrackSerializer = class BackingTrackSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => BackingTrackSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			return /* @__PURE__ */ new Map();
		}
		static setProperty(obj, property, v) {
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/HeaderFooterStyleSerializer.ts
	/**
	* @internal
	*/
	var HeaderFooterStyleSerializer = class HeaderFooterStyleSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => HeaderFooterStyleSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("template", obj.template);
			o.set("isvisible", obj.isVisible);
			o.set("textalign", obj.textAlign);
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "template":
					obj.template = v;
					return true;
				case "isvisible":
					obj.isVisible = v;
					return true;
				case "textalign":
					obj.textAlign = JsonHelper.parseEnum(v, TextAlign);
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/ScoreStyleSerializer.ts
	/**
	* @internal
	*/
	var ScoreStyleSerializer = class ScoreStyleSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => ScoreStyleSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			{
				const m = /* @__PURE__ */ new Map();
				o.set("headerandfooter", m);
				for (const [k, v] of obj.headerAndFooter) m.set(k.toString(), HeaderFooterStyleSerializer.toJson(v));
			}
			{
				const m = /* @__PURE__ */ new Map();
				o.set("colors", m);
				for (const [k, v] of obj.colors) m.set(k.toString(), Color.toJson(v));
			}
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "headerandfooter":
					obj.headerAndFooter = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						const i = new HeaderFooterStyle();
						HeaderFooterStyleSerializer.fromJson(i, v);
						obj.headerAndFooter.set(JsonHelper.parseEnum(k, ScoreSubElement), i);
					});
					return true;
				case "colors":
					obj.colors = /* @__PURE__ */ new Map();
					JsonHelper.forEach(v, (v, k) => {
						obj.colors.set(JsonHelper.parseEnum(k, ScoreSubElement), Color.fromJson(v));
					});
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/generated/model/ScoreSerializer.ts
	/**
	* @internal
	*/
	var ScoreSerializer = class ScoreSerializer {
		static fromJson(obj, m) {
			if (!m) return;
			JsonHelper.forEach(m, (v, k) => ScoreSerializer.setProperty(obj, k, v));
		}
		static toJson(obj) {
			if (!obj) return null;
			const o = /* @__PURE__ */ new Map();
			o.set("album", obj.album);
			o.set("artist", obj.artist);
			o.set("copyright", obj.copyright);
			o.set("instructions", obj.instructions);
			o.set("music", obj.music);
			o.set("notices", obj.notices);
			o.set("subtitle", obj.subTitle);
			o.set("title", obj.title);
			o.set("words", obj.words);
			o.set("tab", obj.tab);
			o.set("masterbars", obj.masterBars.map((i) => MasterBarSerializer.toJson(i)));
			o.set("tracks", obj.tracks.map((i) => TrackSerializer.toJson(i)));
			o.set("defaultsystemslayout", obj.defaultSystemsLayout);
			o.set("systemslayout", obj.systemsLayout);
			o.set("stylesheet", RenderStylesheetSerializer.toJson(obj.stylesheet));
			if (obj.backingTrack) o.set("backingtrack", BackingTrackSerializer.toJson(obj.backingTrack));
			if (obj.style) o.set("style", ScoreStyleSerializer.toJson(obj.style));
			return o;
		}
		static setProperty(obj, property, v) {
			switch (property) {
				case "album":
					obj.album = v;
					return true;
				case "artist":
					obj.artist = v;
					return true;
				case "copyright":
					obj.copyright = v;
					return true;
				case "instructions":
					obj.instructions = v;
					return true;
				case "music":
					obj.music = v;
					return true;
				case "notices":
					obj.notices = v;
					return true;
				case "subtitle":
					obj.subTitle = v;
					return true;
				case "title":
					obj.title = v;
					return true;
				case "words":
					obj.words = v;
					return true;
				case "tab":
					obj.tab = v;
					return true;
				case "masterbars":
					obj.masterBars = [];
					for (const o of v) {
						const i = new MasterBar();
						MasterBarSerializer.fromJson(i, o);
						obj.addMasterBar(i);
					}
					return true;
				case "tracks":
					obj.tracks = [];
					for (const o of v) {
						const i = new Track();
						TrackSerializer.fromJson(i, o);
						obj.addTrack(i);
					}
					return true;
				case "defaultsystemslayout":
					obj.defaultSystemsLayout = v;
					return true;
				case "systemslayout":
					obj.systemsLayout = v;
					return true;
				case "stylesheet":
					RenderStylesheetSerializer.fromJson(obj.stylesheet, v);
					return true;
				case "backingtrack":
					if (v) {
						obj.backingTrack = new BackingTrack();
						BackingTrackSerializer.fromJson(obj.backingTrack, v);
					} else obj.backingTrack = void 0;
					return true;
				case "style":
					if (v) {
						obj.style = new ScoreStyle();
						ScoreStyleSerializer.fromJson(obj.style, v);
					} else obj.style = void 0;
					return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/midi/MidiFile.ts
	/**
	* Lists the different midi file formats which are supported for export.
	* @public
	*/
	var MidiFileFormat = /* @__PURE__ */ function(MidiFileFormat) {
		/**
		* A single track multi channel file (SMF Type 0)
		*/
		MidiFileFormat[MidiFileFormat["SingleTrackMultiChannel"] = 0] = "SingleTrackMultiChannel";
		/**
		* A multi track file (SMF Type 1)
		*/
		MidiFileFormat[MidiFileFormat["MultiTrack"] = 1] = "MultiTrack";
		return MidiFileFormat;
	}({});
	/**
	* @public
	*/
	var MidiTrack = class {
		/**
		* Gets a list of midi events sorted by time.
		*/
		events = [];
		/**
		* Adds the given midi event a the correct time position into the file.
		*/
		addEvent(e) {
			if (this.events.length === 0 || e.tick >= this.events[this.events.length - 1].tick) this.events.push(e);
			else {
				let insertPos = this.events.length;
				while (insertPos > 0) if (this.events[insertPos - 1].tick > e.tick) insertPos--;
				else break;
				this.events.splice(insertPos, 0, e);
			}
		}
		/**
		* Writes the midi track as binary into the given stream.
		* @returns The stream to write to.
		*/
		writeTo(s) {
			const trackData = ByteBuffer.empty();
			let previousTick = 0;
			for (const midiEvent of this.events) {
				const delta = midiEvent.tick - previousTick;
				MidiFile.writeVariableInt(trackData, delta);
				midiEvent.writeTo(trackData);
				previousTick = midiEvent.tick;
			}
			const b = new Uint8Array([
				77,
				84,
				114,
				107
			]);
			s.write(b, 0, b.length);
			const data = trackData.toArray();
			IOHelper.writeInt32BE(s, data.length);
			s.write(data, 0, data.length);
		}
	};
	/**
	* Represents a midi file with a single track that can be played via {@link AlphaSynth}
	* @public
	*/
	var MidiFile = class {
		/**
		* Gets or sets the midi file format to use.
		*/
		format = 0;
		/**
		* Gets or sets the division per quarter notes.
		*/
		division = MidiUtils.QuarterTime;
		/**
		* An indicator by how many midi-ticks the song contents are shifted. 
		* Grace beats at start might require a shift for the first beat to start at 0.
		* This information can be used to translate back the player time axis to the music notation.
		*/
		tickShift = 0;
		/**
		* Gets a list of midi events sorted by time.
		*/
		get events() {
			if (this.tracks.length === 1) return this.tracks[0].events;
			const events = [];
			for (const t of this.tracks) this.events.push(...t.events);
			events.sort((a, b) => a.tick - b.tick);
			return events;
		}
		/**
		* Gets a list of midi tracks.
		*/
		tracks = [];
		_ensureTracks(trackCount) {
			while (this.tracks.length < trackCount) this.tracks.push(new MidiTrack());
		}
		/**
		* Adds the given midi event a the correct time position into the file.
		*/
		addEvent(e) {
			if (this.format === 0) {
				this._ensureTracks(1);
				this.tracks[0].addEvent(e);
			} else {
				this._ensureTracks(e.track + 1);
				this.tracks[e.track].addEvent(e);
			}
		}
		/**
		* Writes the midi file into a binary format.
		* @returns The binary midi file.
		*/
		toBinary() {
			const data = ByteBuffer.empty();
			this.writeTo(data);
			return data.toArray();
		}
		/**
		* Writes the midi file as binary into the given stream.
		* @returns The stream to write to.
		*/
		writeTo(s) {
			const b = new Uint8Array([
				77,
				84,
				104,
				100
			]);
			s.write(b, 0, b.length);
			IOHelper.writeInt32BE(s, 6);
			IOHelper.writeInt16BE(s, this.format);
			IOHelper.writeInt16BE(s, this.tracks.length);
			IOHelper.writeInt16BE(s, this.division);
			for (const track of this.tracks) track.writeTo(s);
		}
		static writeVariableInt(s, value) {
			const array = new Uint8Array(4);
			let n = 0;
			do {
				array[n++] = value & 127;
				value >>= 7;
			} while (value > 0);
			while (n > 0) {
				n--;
				if (n > 0) s.writeByte(array[n] | 128);
				else s.writeByte(array[n]);
			}
		}
	};
	//#endregion
	//#region src/midi/MidiEvent.ts
	/**
	* Lists all midi event types. Based on the type the instance is a specific subclass.
	* @public
	*/
	var MidiEventType = /* @__PURE__ */ function(MidiEventType) {
		MidiEventType[MidiEventType["TimeSignature"] = 88] = "TimeSignature";
		MidiEventType[MidiEventType["NoteOn"] = 128] = "NoteOn";
		MidiEventType[MidiEventType["NoteOff"] = 144] = "NoteOff";
		MidiEventType[MidiEventType["ControlChange"] = 176] = "ControlChange";
		MidiEventType[MidiEventType["ProgramChange"] = 192] = "ProgramChange";
		MidiEventType[MidiEventType["TempoChange"] = 81] = "TempoChange";
		MidiEventType[MidiEventType["PitchBend"] = 224] = "PitchBend";
		MidiEventType[MidiEventType["PerNotePitchBend"] = 96] = "PerNotePitchBend";
		MidiEventType[MidiEventType["EndOfTrack"] = 47] = "EndOfTrack";
		MidiEventType[MidiEventType["AlphaTabRest"] = 241] = "AlphaTabRest";
		MidiEventType[MidiEventType["AlphaTabMetronome"] = 242] = "AlphaTabMetronome";
		/**
		* @deprecated Not used anymore internally. move to the other concrete types.
		*/
		MidiEventType[MidiEventType["SystemExclusive"] = 240] = "SystemExclusive";
		/**
		* @deprecated Not used anymore internally. move to the other concrete types.
		*/
		MidiEventType[MidiEventType["SystemExclusive2"] = 247] = "SystemExclusive2";
		/**
		* @deprecated Not used anymore internally. move to the other concrete types.
		*/
		MidiEventType[MidiEventType["Meta"] = 255] = "Meta";
		return MidiEventType;
	}({});
	/**
	* Represents a midi event.
	* @public
	*/
	var MidiEvent = class {
		/**
		* Gets or sets the track to which the midi event belongs.
		*/
		track;
		/**
		* Gets or sets the absolute tick of this midi event.
		*/
		tick;
		/**
		* Gets or sets the midi command (type) of this event.
		*/
		type;
		/**
		* Initializes a new instance of the {@link MidiEvent} class.
		* @param track The track this event belongs to.
		* @param tick The absolute midi ticks of this event.
		* @param command The type of this event.
		*/
		constructor(track, tick, command) {
			this.track = track;
			this.tick = tick;
			this.type = command;
		}
		/**
		* @deprecated Change to `type`
		*/
		get command() {
			return this.type;
		}
		/**
		* The 32-bit encoded raw midi message. Deprecated {@since 1.3.0}. Use the properties of the subclasses instead.
		* @deprecated Use individual properties to access data.
		*/
		get message() {
			return 0;
		}
		/**
		* The first data byte. Meaning depends on midi event type. (Deprecated {@since 1.3.0}, use the specific properties of the midi event depending on type)
		* @deprecated Use individual properties to access data.
		*/
		get data1() {
			return 0;
		}
		/**
		* The second data byte Meaning depends on midi event type. (Deprecated {@since 1.3.0}, use the specific properties of the midi event depending on type)
		* @deprecated Use individual properties to access data.
		*/
		get data2() {
			return 0;
		}
	};
	/**
	* Represents a time signature change event.
	* @public
	*/
	var TimeSignatureEvent = class extends MidiEvent {
		/**
		* The time signature numerator.
		*/
		numerator;
		/**
		* The denominator index is a negative power of two: 2 represents a quarter-note, 3 represents an eighth-note, etc.
		* Denominator = 2^(index)
		*/
		denominatorIndex;
		/**
		* The number of MIDI clocks in a metronome click
		*/
		midiClocksPerMetronomeClick;
		/**
		* The number of notated 32nd-notes in what MIDI thinks of as a quarter-note (24 MIDI Clocks).
		*/
		thirtySecondNodesInQuarter;
		constructor(track, tick, numerator, denominatorIndex, midiClocksPerMetronomeClick, thirtySecondNodesInQuarter) {
			super(track, tick, 88);
			this.track = track;
			this.tick = tick;
			this.numerator = numerator;
			this.denominatorIndex = denominatorIndex;
			this.midiClocksPerMetronomeClick = midiClocksPerMetronomeClick;
			this.thirtySecondNodesInQuarter = thirtySecondNodesInQuarter;
		}
		writeTo(s) {
			s.writeByte(255);
			s.writeByte(88);
			MidiFile.writeVariableInt(s, 4);
			s.writeByte(this.numerator & 255);
			s.writeByte(this.denominatorIndex & 255);
			s.writeByte(this.midiClocksPerMetronomeClick & 255);
			s.writeByte(this.thirtySecondNodesInQuarter & 255);
		}
	};
	/**
	* The base class for alphaTab specific midi events (like metronomes and rests).
	* @public
	*/
	var AlphaTabSysExEvent = class AlphaTabSysExEvent extends MidiEvent {
		static AlphaTabManufacturerId = 125;
		static MetronomeEventId = 0;
		static RestEventId = 1;
		writeTo(s) {
			s.writeByte(240);
			const data = ByteBuffer.withCapacity(16);
			data.writeByte(AlphaTabSysExEvent.AlphaTabManufacturerId);
			this.writeEventData(data);
			data.writeByte(247);
			MidiFile.writeVariableInt(s, data.length);
			data.copyTo(s);
		}
	};
	/**
	* Represents a metronome event. This event is emitted by the synthesizer only during playback and
	* is typically not part of the midi file itself.
	* @public
	*/
	var AlphaTabMetronomeEvent = class extends AlphaTabSysExEvent {
		/**
		* The metronome counter as per current time signature.
		*/
		metronomeNumerator;
		/**
		* The duration of the metronome tick in MIDI ticks.
		*/
		metronomeDurationInTicks;
		/**
		* The duration of the metronome tick in milliseconds.
		*/
		metronomeDurationInMilliseconds;
		/**
		* Gets a value indicating whether the current event is a metronome event.
		*/
		isMetronome = true;
		constructor(track, tick, counter, durationInTicks, durationInMillis) {
			super(track, tick, 242);
			this.metronomeNumerator = counter;
			this.metronomeDurationInMilliseconds = durationInMillis;
			this.metronomeDurationInTicks = durationInTicks;
		}
		writeEventData(s) {
			s.writeByte(AlphaTabSysExEvent.MetronomeEventId);
			s.writeByte(this.metronomeNumerator);
			IOHelper.writeInt32LE(s, this.metronomeDurationInTicks);
			IOHelper.writeInt32LE(s, this.metronomeDurationInMilliseconds);
		}
	};
	/**
	* Represents a REST beat being 'played'. This event supports alphaTab in placing the cursor.
	* @public
	*/
	var AlphaTabRestEvent = class extends AlphaTabSysExEvent {
		channel;
		constructor(track, tick, channel) {
			super(track, tick, 241);
			this.channel = channel;
		}
		writeEventData(s) {
			s.writeByte(AlphaTabSysExEvent.RestEventId);
			s.writeByte(this.channel);
		}
	};
	/**
	* The base class for note related events.
	* @public
	*/
	var NoteEvent = class extends MidiEvent {
		/**
		* The channel on which the note is played.
		*/
		channel;
		/**
		* The key of the note being played (aka. the note height).
		*/
		noteKey;
		/**
		* The velocity in which the 'key' of the note is pressed (aka. the loudness/intensity of the note).
		*/
		noteVelocity;
		constructor(track, tick, type, channel, noteKey, noteVelocity) {
			super(track, tick, type);
			this.channel = channel;
			this.noteKey = noteKey;
			this.noteVelocity = noteVelocity;
		}
		get data1() {
			return this.noteKey;
		}
		get data2() {
			return this.noteVelocity;
		}
	};
	/**
	* Represents a note being played
	* @public
	*/
	var NoteOnEvent = class extends NoteEvent {
		constructor(track, tick, channel, noteKey, noteVelocity) {
			super(track, tick, 128, channel, noteKey, noteVelocity);
		}
		writeTo(s) {
			s.writeByte(this.channel & 15 | 144);
			s.writeByte(this.noteKey & 255);
			s.writeByte(this.noteVelocity & 255);
		}
	};
	/**
	* Represents a note stop being played.
	* @public
	*/
	var NoteOffEvent = class extends NoteEvent {
		constructor(track, tick, channel, noteKey, noteVelocity) {
			super(track, tick, 144, channel, noteKey, noteVelocity);
		}
		writeTo(s) {
			s.writeByte(this.channel & 15 | 128);
			s.writeByte(this.noteKey & 255);
			s.writeByte(this.noteVelocity & 255);
		}
	};
	/**
	* Represents the change of a value on a midi controller.
	* @public
	*/
	var ControlChangeEvent = class extends MidiEvent {
		/**
		* The channel for which the controller is changing.
		*/
		channel;
		/**
		* The type of the controller which is changing.
		*/
		controller;
		/**
		* The new value of the controller. The meaning is depending on the controller type.
		*/
		value;
		constructor(track, tick, channel, controller, value) {
			super(track, tick, 176);
			this.channel = channel;
			this.controller = controller;
			this.value = value;
		}
		writeTo(s) {
			s.writeByte(this.channel & 15 | 176);
			s.writeByte(this.controller & 255);
			s.writeByte(this.value & 255);
		}
		get data1() {
			return this.controller;
		}
		get data2() {
			return this.value;
		}
	};
	/**
	* Represents the change of the midi program on a channel.
	* @public
	*/
	var ProgramChangeEvent = class extends MidiEvent {
		/**
		* The midi channel for which the program changes.
		*/
		channel;
		/**
		* The numeric value of the program indicating the instrument bank to choose.
		*/
		program;
		constructor(track, tick, channel, program) {
			super(track, tick, 192);
			this.channel = channel;
			this.program = program;
		}
		writeTo(s) {
			s.writeByte(this.channel & 15 | 192);
			s.writeByte(this.program & 255);
		}
		get data1() {
			return this.program;
		}
	};
	/**
	* Represents a change of the tempo in the song.
	* @public
	*/
	var TempoChangeEvent = class extends MidiEvent {
		/**
		* The tempo in microseconds per quarter note (aka USQ). A time format typically for midi.
		*/
		get microSecondsPerQuarterNote() {
			return 6e7 / this.beatsPerMinute;
		}
		/**
		* The tempo in microseconds per quarter note (aka USQ). A time format typically for midi.
		*/
		set microSecondsPerQuarterNote(value) {
			this.beatsPerMinute = 6e7 / value;
		}
		/**
		* The tempo in beats per minute
		*/
		beatsPerMinute = 0;
		constructor(tick, microSecondsPerQuarterNote) {
			super(0, tick, 81);
			this.microSecondsPerQuarterNote = microSecondsPerQuarterNote;
		}
		writeTo(s) {
			s.writeByte(255);
			s.writeByte(81);
			s.writeByte(3);
			s.writeByte(this.microSecondsPerQuarterNote >> 16 & 255);
			s.writeByte(this.microSecondsPerQuarterNote >> 8 & 255);
			s.writeByte(this.microSecondsPerQuarterNote & 255);
		}
	};
	/**
	* Represents a change of the pitch bend (aka. pitch wheel) on a specific channel.
	* @public
	*/
	var PitchBendEvent = class extends MidiEvent {
		/**
		* The channel for which the pitch bend changes.
		*/
		channel;
		/**
		* The value to which the pitch changes. This value is according to the MIDI specification.
		*/
		value;
		constructor(track, tick, channel, value) {
			super(track, tick, 224);
			this.channel = channel;
			this.value = value;
		}
		writeTo(s) {
			s.writeByte(this.channel & 15 | 224);
			s.writeByte(this.value & 127);
			s.writeByte(this.value >> 7 & 127);
		}
		get data1() {
			return this.value & 127;
		}
		get data2() {
			return this.value >> 7 & 127;
		}
	};
	/**
	* Represents a single note pitch bend change.
	* @public
	*/
	var NoteBendEvent = class extends MidiEvent {
		/**
		* The channel on which the note is played for which the pitch changes.
		*/
		channel;
		/**
		* The key of the note for which the pitch changes.
		*/
		noteKey;
		/**
		* The value to which the pitch changes. This value is according to the MIDI specification.
		*/
		value;
		constructor(track, tick, channel, noteKey, value) {
			super(track, tick, 96);
			this.channel = channel;
			this.noteKey = noteKey;
			this.value = value;
		}
		writeTo(_s) {
			throw new AlphaTabError(AlphaTabErrorType.General, "Note Bend (Midi2.0) events cannot be exported to SMF1.0");
		}
	};
	/**
	* Represents the end of the track indicating that no more events for this track follow.
	* @public
	*/
	var EndOfTrackEvent = class extends MidiEvent {
		constructor(track, tick) {
			super(track, tick, 47);
		}
		writeTo(s) {
			s.writeByte(255);
			s.writeByte(47);
			s.writeByte(0);
		}
	};
	//#endregion
	//#region src/model/JsonConverter.ts
	/**
	* This class can convert a full {@link Score} instance to a simple JavaScript object and back for further
	* JSON serialization.
	* @public
	*/
	var JsonConverter = class JsonConverter {
		/**
		* @target web
		*/
		static _jsonReplacer(_, v) {
			if (v instanceof Map) {
				if ("fromEntries" in Object) return Object.fromEntries(v);
				const o = {};
				for (const [k, mv] of v) o[k] = mv;
				return o;
			}
			if (ArrayBuffer.isView(v)) return Array.apply([], [v]);
			return v;
		}
		/**
		* Converts the given score into a JSON encoded string.
		* @param score The score to serialize.
		* @returns A JSON encoded string.
		* @target web
		*/
		static scoreToJson(score) {
			const obj = JsonConverter.scoreToJsObject(score);
			return JSON.stringify(obj, JsonConverter._jsonReplacer);
		}
		/**
		* Converts the given JSON string back to a {@link Score} object.
		* @param json The JSON string
		* @param settings The settings to use during conversion.
		* @returns The converted score object.
		* @target web
		*/
		static jsonToScore(json, settings) {
			return JsonConverter.jsObjectToScore(JSON.parse(json), settings);
		}
		/**
		* Converts the score into a JavaScript object without circular dependencies.
		* @param score The score object to serialize
		* @returns A serialized score object without ciruclar dependencies that can be used for further serializations.
		*/
		static scoreToJsObject(score) {
			return ScoreSerializer.toJson(score);
		}
		/**
		* Converts the given JavaScript object into a score object.
		* @param jsObject The javascript object created via {@link Score}
		* @param settings The settings to use during conversion.
		* @returns The converted score object.
		*/
		static jsObjectToScore(jsObject, settings) {
			const score = new Score();
			ScoreSerializer.fromJson(score, jsObject);
			score.finish(settings ?? new Settings());
			return score;
		}
		/**
		* Converts the given settings into a JSON encoded string.
		* @param settings The settings to serialize.
		* @returns A JSON encoded string.
		* @target web
		*/
		static settingsToJson(settings) {
			const obj = JsonConverter.settingsToJsObject(settings);
			return JSON.stringify(obj, JsonConverter._jsonReplacer);
		}
		/**
		* Converts the given JSON string back to a {@link Score} object.
		* @param json The JSON string
		* @returns The converted settings object.
		* @target web
		*/
		static jsonToSettings(json) {
			return JsonConverter.jsObjectToSettings(JSON.parse(json));
		}
		/**
		* Converts the settings object into a JavaScript object for transmission between components or saving purposes.
		* @param settings The settings object to serialize
		* @returns A serialized settings object without ciruclar dependencies that can be used for further serializations.
		*/
		static settingsToJsObject(settings) {
			return SettingsSerializer.toJson(settings);
		}
		/**
		* Converts the given JavaScript object into a settings object.
		* @param jsObject The javascript object created via {@link Settings}
		* @returns The converted Settings object.
		*/
		static jsObjectToSettings(jsObject) {
			const settings = new Settings();
			SettingsSerializer.fromJson(settings, jsObject);
			return settings;
		}
		/**
		* Converts the given JavaScript object into a MidiFile object.
		* @param jsObject The javascript object to deserialize.
		* @returns The converted MidiFile.
		*/
		static jsObjectToMidiFile(jsObject) {
			const midi2 = new MidiFile();
			JsonHelper.forEach(jsObject, (v, k) => {
				switch (k) {
					case "tickShift":
						midi2.tickShift = v;
						break;
					case "division":
						midi2.division = v;
						break;
					case "tracks":
						for (const midiTrack of v) {
							const midiTrack2 = JsonConverter._jsObjectToMidiTrack(midiTrack);
							midi2.tracks.push(midiTrack2);
						}
						break;
				}
			});
			return midi2;
		}
		static _jsObjectToMidiTrack(jsObject) {
			const midi2 = new MidiTrack();
			JsonHelper.forEach(jsObject, (v, k) => {
				switch (k) {
					case "events":
						for (const midiEvent of v) {
							const midiEvent2 = JsonConverter.jsObjectToMidiEvent(midiEvent);
							midi2.events.push(midiEvent2);
						}
						break;
				}
			});
			return midi2;
		}
		/**
		* Converts the given JavaScript object into a MidiEvent object.
		* @param jsObject The javascript object to deserialize.
		* @returns The converted MidiEvent.
		*/
		static jsObjectToMidiEvent(midiEvent) {
			const track = JsonHelper.getValue(midiEvent, "track");
			const tick = JsonHelper.getValue(midiEvent, "tick");
			const type = JsonHelper.getValue(midiEvent, "type");
			switch (type) {
				case MidiEventType.TimeSignature: return new TimeSignatureEvent(track, tick, JsonHelper.getValue(midiEvent, "numerator"), JsonHelper.getValue(midiEvent, "denominatorIndex"), JsonHelper.getValue(midiEvent, "midiClocksPerMetronomeClick"), JsonHelper.getValue(midiEvent, "thirdySecondNodesInQuarter"));
				case MidiEventType.AlphaTabRest: return new AlphaTabRestEvent(track, tick, JsonHelper.getValue(midiEvent, "channel"));
				case MidiEventType.AlphaTabMetronome: return new AlphaTabMetronomeEvent(track, tick, JsonHelper.getValue(midiEvent, "metronomeNumerator"), JsonHelper.getValue(midiEvent, "metronomeDurationInTicks"), JsonHelper.getValue(midiEvent, "metronomeDurationInMilliseconds"));
				case MidiEventType.NoteOn: return new NoteOnEvent(track, tick, JsonHelper.getValue(midiEvent, "channel"), JsonHelper.getValue(midiEvent, "noteKey"), JsonHelper.getValue(midiEvent, "noteVelocity"));
				case MidiEventType.NoteOff: return new NoteOffEvent(track, tick, JsonHelper.getValue(midiEvent, "channel"), JsonHelper.getValue(midiEvent, "noteKey"), JsonHelper.getValue(midiEvent, "noteVelocity"));
				case MidiEventType.ControlChange: return new ControlChangeEvent(track, tick, JsonHelper.getValue(midiEvent, "channel"), JsonHelper.getValue(midiEvent, "controller"), JsonHelper.getValue(midiEvent, "value"));
				case MidiEventType.ProgramChange: return new ProgramChangeEvent(track, tick, JsonHelper.getValue(midiEvent, "channel"), JsonHelper.getValue(midiEvent, "program"));
				case MidiEventType.TempoChange:
					const tempo = new TempoChangeEvent(tick, 0);
					tempo.beatsPerMinute = JsonHelper.getValue(midiEvent, "beatsPerMinute");
					return tempo;
				case MidiEventType.PitchBend: return new PitchBendEvent(track, tick, JsonHelper.getValue(midiEvent, "channel"), JsonHelper.getValue(midiEvent, "value"));
				case MidiEventType.PerNotePitchBend: return new NoteBendEvent(track, tick, JsonHelper.getValue(midiEvent, "channel"), JsonHelper.getValue(midiEvent, "noteKey"), JsonHelper.getValue(midiEvent, "value"));
				case MidiEventType.EndOfTrack: return new EndOfTrackEvent(track, tick);
			}
			throw new AlphaTabError(AlphaTabErrorType.Format, `Unknown Midi Event type: ${type}`);
		}
		/**
		* Converts the given MidiFile object into a serialized JavaScript object.
		* @param midi The midi file to convert.
		* @returns A serialized MidiFile object without ciruclar dependencies that can be used for further serializations.
		*/
		static midiFileToJsObject(midi) {
			const o = /* @__PURE__ */ new Map();
			o.set("division", midi.division);
			o.set("tickShift", midi.tickShift);
			const tracks = [];
			for (const track of midi.tracks) tracks.push(JsonConverter._midiTrackToJsObject(track));
			o.set("tracks", tracks);
			return o;
		}
		static _midiTrackToJsObject(midi) {
			const o = /* @__PURE__ */ new Map();
			const events = [];
			for (const track of midi.events) events.push(JsonConverter.midiEventToJsObject(track));
			o.set("events", events);
			return o;
		}
		/**
		* Converts the given MidiEvent object into a serialized JavaScript object.
		* @param midi The midi file to convert.
		* @returns A serialized MidiEvent object without ciruclar dependencies that can be used for further serializations.
		*/
		static midiEventToJsObject(midiEvent) {
			const o = /* @__PURE__ */ new Map();
			o.set("track", midiEvent.track);
			o.set("tick", midiEvent.tick);
			o.set("type", midiEvent.type);
			switch (midiEvent.type) {
				case MidiEventType.TimeSignature:
					o.set("numerator", midiEvent.numerator);
					o.set("denominatorIndex", midiEvent.denominatorIndex);
					o.set("midiClocksPerMetronomeClick", midiEvent.midiClocksPerMetronomeClick);
					o.set("thirdySecondNodesInQuarter", midiEvent.thirtySecondNodesInQuarter);
					break;
				case MidiEventType.AlphaTabRest:
					o.set("channel", midiEvent.channel);
					break;
				case MidiEventType.AlphaTabMetronome:
					o.set("metronomeNumerator", midiEvent.metronomeNumerator);
					o.set("metronomeDurationInMilliseconds", midiEvent.metronomeDurationInMilliseconds);
					o.set("metronomeDurationInTicks", midiEvent.metronomeDurationInTicks);
					break;
				case MidiEventType.NoteOn:
				case MidiEventType.NoteOff:
					o.set("channel", midiEvent.channel);
					o.set("noteKey", midiEvent.noteKey);
					o.set("noteVelocity", midiEvent.noteVelocity);
					break;
				case MidiEventType.ControlChange:
					o.set("channel", midiEvent.channel);
					o.set("controller", midiEvent.controller);
					o.set("value", midiEvent.value);
					break;
				case MidiEventType.ProgramChange:
					o.set("channel", midiEvent.channel);
					o.set("program", midiEvent.program);
					break;
				case MidiEventType.TempoChange:
					o.set("beatsPerMinute", midiEvent.beatsPerMinute);
					break;
				case MidiEventType.PitchBend:
					o.set("channel", midiEvent.channel);
					o.set("value", midiEvent.value);
					break;
				case MidiEventType.PerNotePitchBend:
					o.set("channel", midiEvent.channel);
					o.set("noteKey", midiEvent.noteKey);
					o.set("value", midiEvent.value);
					break;
				case MidiEventType.EndOfTrack: break;
			}
			return o;
		}
	};
	//#endregion
	//#region src/synth/MidiEventsPlayedEventArgs.ts
	/**
	* Represents the info when the synthesizer played certain midi events.
	* @public
	*/
	var MidiEventsPlayedEventArgs = class {
		/**
		* Gets the events which were played.
		*/
		events;
		/**
		* Initializes a new instance of the {@link MidiEventsPlayedEventArgs} class.
		* @param events The events which were played.
		*/
		constructor(events) {
			this.events = events;
		}
	};
	//#endregion
	//#region src/synth/PlaybackRangeChangedEventArgs.ts
	/**
	* Represents the info when the playback range changed.
	* @public
	*/
	var PlaybackRangeChangedEventArgs = class {
		/**
		* The new playback range.
		*/
		playbackRange;
		/**
		* Initializes a new instance of the {@link PlaybackRangeChangedEventArgs} class.
		* @param range The range.
		*/
		constructor(playbackRange) {
			this.playbackRange = playbackRange;
		}
	};
	//#endregion
	//#region src/synth/PlayerState.ts
	/**
	* Lists the different states of the player
	* @public
	*/
	var PlayerState = /* @__PURE__ */ function(PlayerState) {
		/**
		* Player is paused
		*/
		PlayerState[PlayerState["Paused"] = 0] = "Paused";
		/**
		* Player is playing
		*/
		PlayerState[PlayerState["Playing"] = 1] = "Playing";
		return PlayerState;
	}({});
	//#endregion
	//#region src/synth/PlayerStateChangedEventArgs.ts
	/**
	* Represents the info when the player state changes.
	* @public
	*/
	var PlayerStateChangedEventArgs = class {
		/**
		* The new state of the player.
		*/
		state;
		/**
		* Gets a value indicating whether the playback was stopped or only paused.
		* @returns true if the playback was stopped, false if the playback was started or paused
		*/
		stopped;
		/**
		* Initializes a new instance of the {@link PlayerStateChangedEventArgs} class.
		* @param state The state.
		*/
		constructor(state, stopped) {
			this.state = state;
			this.stopped = stopped;
		}
	};
	//#endregion
	//#region src/synth/PositionChangedEventArgs.ts
	/**
	* Represents the info when the time in the synthesizer changes.
	* @public
	*/
	var PositionChangedEventArgs = class {
		/**
		* The current time position within the song in milliseconds.
		*/
		currentTime;
		/**
		* The total length of the song in milliseconds.
		*/
		endTime;
		/**
		* The current time position within the song in midi ticks.
		*/
		currentTick;
		/**
		* The total length of the song in midi ticks.
		*/
		endTick;
		/**
		* Whether the position changed because of time seeking.
		* @since 1.2.0
		*/
		isSeek;
		/**
		* The original tempo in which alphaTab internally would be playing right now.
		*/
		originalTempo = 0;
		/**
		* The modified tempo in which the actual playback is happening (e.g. due to playback speed or external audio synchronization)
		*/
		modifiedTempo = 0;
		/**
		* Initializes a new instance of the {@link PositionChangedEventArgs} class.
		* @param currentTime The current time.
		* @param endTime The end time.
		* @param currentTick The current tick.
		* @param endTick The end tick.
		* @param isSeek Whether the time was seeked.
		*/
		constructor(currentTime, endTime, currentTick, endTick, isSeek, originalTempo, modifiedTempo) {
			this.currentTime = currentTime;
			this.endTime = endTime;
			this.currentTick = currentTick;
			this.endTick = endTick;
			this.isSeek = isSeek;
			this.originalTempo = originalTempo;
			this.modifiedTempo = modifiedTempo;
		}
	};
	//#endregion
	//#region src/platform/worker/AlphaSynthWebWorkerApi.ts
	/**
	* a WebWorker based alphaSynth which uses the given player as output.
	* @internal
	*/
	var AlphaSynthWebWorkerApi = class {
		_synth;
		_output;
		_workerIsReadyForPlayback = false;
		_workerIsReady = false;
		_outputIsReady = false;
		_state = PlayerState.Paused;
		_masterVolume = 0;
		_metronomeVolume = 0;
		_countInVolume = 0;
		_playbackSpeed = 0;
		_isLooping = false;
		_playbackRange = null;
		_midiEventsPlayedFilter = [];
		_loadedMidiInfo;
		_currentPosition = new PositionChangedEventArgs(0, 0, 0, 0, false, 120, 120);
		get output() {
			return this._output;
		}
		get isReady() {
			return this._workerIsReady && this._outputIsReady;
		}
		get isReadyForPlayback() {
			return this._workerIsReadyForPlayback;
		}
		get state() {
			return this._state;
		}
		get logLevel() {
			return Logger.logLevel;
		}
		get worker() {
			return this._synth;
		}
		set logLevel(value) {
			Logger.logLevel = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setLogLevel",
				value
			});
		}
		get masterVolume() {
			return this._masterVolume;
		}
		set masterVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this._masterVolume = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setMasterVolume",
				value
			});
		}
		get metronomeVolume() {
			return this._metronomeVolume;
		}
		set metronomeVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this._metronomeVolume = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setMetronomeVolume",
				value
			});
		}
		get countInVolume() {
			return this._countInVolume;
		}
		set countInVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this._countInVolume = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setCountInVolume",
				value
			});
		}
		get midiEventsPlayedFilter() {
			return this._midiEventsPlayedFilter;
		}
		set midiEventsPlayedFilter(value) {
			this._midiEventsPlayedFilter = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setMidiEventsPlayedFilter",
				value: Environment.prepareForPostMessage(value)
			});
		}
		get playbackSpeed() {
			return this._playbackSpeed;
		}
		set playbackSpeed(value) {
			value = ModelUtils.clamp(value, SynthConstants.MinPlaybackSpeed, SynthConstants.MaxPlaybackSpeed);
			this._playbackSpeed = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setPlaybackSpeed",
				value
			});
		}
		get loadedMidiInfo() {
			return this.loadedMidiInfo;
		}
		get currentPosition() {
			return this._currentPosition;
		}
		get tickPosition() {
			return this._currentPosition.currentTick;
		}
		set tickPosition(value) {
			if (value < 0) value = 0;
			this._currentPosition = new PositionChangedEventArgs(this._currentPosition.currentTime, this._currentPosition.endTime, value, this._currentPosition.endTick, true, this._currentPosition.originalTempo, this._currentPosition.modifiedTempo);
			this._synth.postMessage({
				cmd: "alphaSynth.setTickPosition",
				value
			});
		}
		get timePosition() {
			return this._currentPosition.currentTime;
		}
		set timePosition(value) {
			if (value < 0) value = 0;
			this._currentPosition = new PositionChangedEventArgs(value, this._currentPosition.endTime, this._currentPosition.currentTick, this._currentPosition.endTick, true, this._currentPosition.originalTempo, this._currentPosition.modifiedTempo);
			this._synth.postMessage({
				cmd: "alphaSynth.setTimePosition",
				value
			});
		}
		get isLooping() {
			return this._isLooping;
		}
		set isLooping(value) {
			this._isLooping = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setIsLooping",
				value
			});
		}
		get playbackRange() {
			return this._playbackRange;
		}
		set playbackRange(value) {
			if (value) {
				if (value.startTick < 0) value.startTick = 0;
				if (value.endTick < 0) value.endTick = 0;
			}
			this._playbackRange = value;
			this._synth.postMessage({
				cmd: "alphaSynth.setPlaybackRange",
				value: Environment.prepareForPostMessage(value)
			});
		}
		constructor(player, settings, synthWorker) {
			this._workerIsReadyForPlayback = false;
			this._workerIsReady = false;
			this._outputIsReady = false;
			this._state = PlayerState.Paused;
			this._masterVolume = 0;
			this._metronomeVolume = 0;
			this._playbackSpeed = 0;
			this._isLooping = false;
			this._playbackRange = null;
			this._output = player;
			this._output.ready.on(this._onOutputReady.bind(this));
			this._output.samplesPlayed.on(this.onOutputSamplesPlayed.bind(this));
			this._output.sampleRequest.on(this.onOutputSampleRequest.bind(this));
			this._output.open(settings.player.bufferTimeInMilliseconds);
			this._synth = synthWorker;
			this._synth.addEventListener("message", (e) => this.handleWorkerMessage(e));
			this._synth.postMessage({
				cmd: "alphaSynth.initialize",
				sampleRate: this._output.sampleRate,
				logLevel: settings.core.logLevel,
				bufferTimeInMilliseconds: settings.player.bufferTimeInMilliseconds
			});
			this.masterVolume = 1;
			this.playbackSpeed = 1;
			this.metronomeVolume = 0;
		}
		destroy() {
			this._synth.postMessage({ cmd: "alphaSynth.destroy" });
		}
		play() {
			this._output.activate();
			this._synth.postMessage({ cmd: "alphaSynth.play" });
			return true;
		}
		pause() {
			this._synth.postMessage({ cmd: "alphaSynth.pause" });
		}
		playPause() {
			this._output.activate();
			this._synth.postMessage({ cmd: "alphaSynth.playPause" });
		}
		stop() {
			this._synth.postMessage({ cmd: "alphaSynth.stop" });
		}
		playOneTimeMidiFile(midi) {
			this._synth.postMessage({
				cmd: "alphaSynth.playOneTimeMidiFile",
				midi: JsonConverter.midiFileToJsObject(Environment.prepareForPostMessage(midi))
			});
		}
		loadSoundFont(data, append) {
			this._synth.postMessage({
				cmd: "alphaSynth.loadSoundFontBytes",
				data: Environment.prepareForPostMessage(data),
				append
			});
		}
		resetSoundFonts() {
			this._synth.postMessage({ cmd: "alphaSynth.resetSoundFonts" });
		}
		loadMidiFile(midi) {
			this._synth.postMessage({
				cmd: "alphaSynth.loadMidi",
				midi: JsonConverter.midiFileToJsObject(Environment.prepareForPostMessage(midi))
			});
		}
		applyTranspositionPitches(transpositionPitches) {
			this._synth.postMessage({
				cmd: "alphaSynth.applyTranspositionPitches",
				transpositionPitches: Environment.prepareForPostMessage(transpositionPitches)
			});
		}
		setChannelTranspositionPitch(channel, semitones) {
			this._synth.postMessage({
				cmd: "alphaSynth.setChannelTranspositionPitch",
				channel,
				semitones
			});
		}
		setChannelMute(channel, mute) {
			this._synth.postMessage({
				cmd: "alphaSynth.setChannelMute",
				channel,
				mute
			});
		}
		resetChannelStates() {
			this._synth.postMessage({ cmd: "alphaSynth.resetChannelStates" });
		}
		setChannelSolo(channel, solo) {
			this._synth.postMessage({
				cmd: "alphaSynth.setChannelSolo",
				channel,
				solo
			});
		}
		setChannelVolume(channel, volume) {
			volume = Math.max(volume, SynthConstants.MinVolume);
			this._synth.postMessage({
				cmd: "alphaSynth.setChannelVolume",
				channel,
				volume
			});
		}
		handleWorkerMessage(e) {
			const data = e.data;
			switch (data.cmd) {
				case "alphaSynth.ready":
					this._workerIsReady = true;
					this._checkReady();
					break;
				case "alphaSynth.destroyed":
					this._synth.terminate();
					break;
				case "alphaSynth.readyForPlayback":
					this._workerIsReadyForPlayback = true;
					this._checkReadyForPlayback();
					break;
				case "alphaSynth.positionChanged":
					this._currentPosition = data.args;
					this.positionChanged.trigger(this._currentPosition);
					break;
				case "alphaSynth.midiEventsPlayed":
					this.midiEventsPlayed.trigger(new MidiEventsPlayedEventArgs(data.events.map(JsonConverter.jsObjectToMidiEvent)));
					break;
				case "alphaSynth.playerStateChanged":
					this._state = data.state;
					this.stateChanged.trigger(new PlayerStateChangedEventArgs(data.state, data.stopped));
					break;
				case "alphaSynth.playbackRangeChanged":
					this._playbackRange = data.playbackRange;
					this.playbackRangeChanged.trigger(new PlaybackRangeChangedEventArgs(this._playbackRange));
					break;
				case "alphaSynth.finished":
					this.finished.trigger();
					break;
				case "alphaSynth.soundFontLoaded":
					this.soundFontLoaded.trigger();
					break;
				case "alphaSynth.soundFontLoadFailed":
					this.soundFontLoadFailed.trigger(data.error);
					break;
				case "alphaSynth.midiLoaded":
					this._checkReadyForPlayback();
					this._loadedMidiInfo = data.args;
					this.midiLoaded.trigger(this._loadedMidiInfo);
					break;
				case "alphaSynth.midiLoadFailed":
					this._checkReadyForPlayback();
					this.midiLoadFailed.trigger(data.error);
					break;
				case "alphaSynth.output.addSamples":
					this._output.addSamples(data.samples);
					break;
				case "alphaSynth.output.play":
					this._output.play();
					break;
				case "alphaSynth.output.pause":
					this._output.pause();
					break;
				case "alphaSynth.output.destroy":
					this._output.destroy();
					break;
				case "alphaSynth.output.resetSamples":
					this._output.resetSamples();
					break;
			}
		}
		_checkReady() {
			if (this.isReady) this.ready.trigger();
		}
		_checkReadyForPlayback() {
			if (this.isReadyForPlayback) this.readyForPlayback.trigger();
		}
		ready = new EventEmitter();
		readyForPlayback = new EventEmitter();
		finished = new EventEmitter();
		soundFontLoaded = new EventEmitter();
		soundFontLoadFailed = new EventEmitterOfT();
		midiLoaded = new EventEmitterOfT();
		midiLoadFailed = new EventEmitterOfT();
		stateChanged = new EventEmitterOfT();
		positionChanged = new EventEmitterOfT();
		midiEventsPlayed = new EventEmitterOfT();
		playbackRangeChanged = new EventEmitterOfT();
		onOutputSampleRequest() {
			this._synth.postMessage({ cmd: "alphaSynth.output.sampleRequest" });
		}
		onOutputSamplesPlayed(samples) {
			this._synth.postMessage({
				cmd: "alphaSynth.output.samplesPlayed",
				samples
			});
		}
		_onOutputReady() {
			this._outputIsReady = true;
			this._checkReady();
		}
		loadBackingTrack(_score) {}
		updateSyncPoints(_syncPoints) {}
	};
	//#endregion
	//#region src/rendering/utils/BarBounds.ts
	/**
	* Represents the boundaries of a single bar.
	* @public
	*/
	var BarBounds = class {
		/**
		* Gets or sets the reference to the related {@link MasterBarBounds}
		*/
		masterBarBounds;
		/**
		* Gets or sets the bounds covering all visually visible elements spanning this bar.
		*/
		visualBounds;
		/**
		* Gets or sets the actual bounds of the elements in this bar including whitespace areas.
		*/
		realBounds;
		/**
		* Gets or sets the bar related to this boundaries.
		*/
		bar;
		/**
		* Gets or sets a list of the beats contained in this lookup.
		*/
		beats = [];
		/**
		* Adds a new beat to this lookup.
		* @param bounds The beat bounds to add.
		*/
		addBeat(bounds) {
			bounds.barBounds = this;
			this.beats.push(bounds);
			this.masterBarBounds.addBeat(bounds);
		}
		/**
		* Tries to find the beat at the given X-position.
		* @param x The X-position of the beat to find.
		* @returns The beat at the given X-position or null if none was found.
		*/
		findBeatAtPos(x) {
			let beat = null;
			for (const t of this.beats) if (!beat || t.realBounds.x < x) beat = t;
			else if (t.realBounds.x > x) break;
			return beat;
		}
		/**
		* Finishes the lookup object and optimizes itself for fast access.
		*/
		finish(scale = 1) {
			this.realBounds.scaleWith(scale);
			this.visualBounds.scaleWith(scale);
			this.beats.sort((a, b) => a.realBounds.x - b.realBounds.x);
			for (const b of this.beats) b.finish(scale);
		}
	};
	//#endregion
	//#region src/rendering/utils/BeatBounds.ts
	/**
	* Represents the bounds of a single beat.
	* @public
	*/
	var BeatBounds = class {
		/**
		* Gets or sets the reference to the parent {@link BarBounds}.
		*/
		barBounds;
		/**
		* Gets or sets the bounds covering all visually visible elements spanning this beat.
		*/
		visualBounds;
		/**
		* Gets or sets x-position where the timely center of the notes for this beat is.
		* This is where the cursor should be at the time when this beat is played.
		*/
		onNotesX = 0;
		/**
		* Gets or sets the actual bounds of the elements in this beat including whitespace areas.
		*/
		realBounds;
		/**
		* Gets or sets the beat related to this bounds.
		*/
		beat;
		/**
		* Gets or sets the individual note positions of this beat (if {@link CoreSettings.includeNoteBounds} was set to true).
		*/
		notes = null;
		/**
		* Adds a new note to this bounds.
		* @param bounds The note bounds to add.
		*/
		addNote(bounds) {
			if (!this.notes) this.notes = [];
			bounds.beatBounds = this;
			this.notes.push(bounds);
		}
		/**
		* Tries to find a note at the given position.
		* @param x The X-position of the note to find.
		* @param y The Y-position of the note to find.
		* @returns The note at the given position or null if no note was found, or the note lookup was not enabled before rendering.
		*/
		findNoteAtPos(x, y) {
			const notes = this.notes;
			if (!notes) return null;
			for (const note of notes) {
				const bottom = note.noteHeadBounds.y + note.noteHeadBounds.h;
				const right = note.noteHeadBounds.x + note.noteHeadBounds.w;
				if (note.noteHeadBounds.x <= x && note.noteHeadBounds.y <= y && x <= right && y <= bottom) return note.note;
			}
			return null;
		}
		/**
		* Finishes the lookup object and optimizes itself for fast access.
		*/
		finish(scale = 1) {
			this.realBounds.scaleWith(scale);
			this.visualBounds.scaleWith(scale);
			this.onNotesX *= scale;
			if (this.notes) for (const n of this.notes) n.finish(scale);
		}
	};
	//#endregion
	//#region src/rendering/utils/MasterBarBounds.ts
	/**
	* Represents the boundaries of a list of bars related to a single master bar.
	* @public
	*/
	var MasterBarBounds = class {
		/**
		* The MasterBar index within the data model represented by these bounds.
		*/
		index = 0;
		/**
		* Gets or sets a value indicating whether this bounds are the first of the line.
		*/
		isFirstOfLine = false;
		/**
		* Gets or sets the bounds covering all visually visible elements spanning all bars of this master bar.
		*/
		visualBounds;
		/**
		* Gets or sets the actual bounds of the elements in this master bar including whitespace areas.
		*/
		realBounds;
		/**
		* Gets or sets the actual bounds which are exactly aligned with the lines of the staffs.
		*/
		lineAlignedBounds;
		/**
		* Gets or sets the list of individual bars within this lookup.
		*/
		bars = [];
		/**
		* Gets or sets a reference to the parent {@link staffSystemBounds}.
		*/
		staffSystemBounds = null;
		/**
		* Gets or sets a reference to the parent {@link staffSystemBounds}.
		* @deprecated use staffSystemBounds
		*/
		get staveGroupBounds() {
			return this.staffSystemBounds;
		}
		/**
		* Adds a new bar to this lookup.
		* @param bounds The bar bounds to add to this lookup.
		*/
		addBar(bounds) {
			bounds.masterBarBounds = this;
			this.bars.push(bounds);
		}
		/**
		* Tries to find a beat at the given location.
		* @param x The absolute X position where the beat spans across.
		* @returns The beat that spans across the given point, or null if none of the contained bars had a beat at this position.
		*/
		findBeatAtPos(x) {
			let beat = null;
			const distance = 1e7;
			for (const bar of this.bars) {
				const b = bar.findBeatAtPos(x);
				if (b && (!beat || beat.realBounds.x < b.realBounds.x)) {
					const newDistance = Math.abs(b.realBounds.x - x);
					if (!beat || newDistance < distance) beat = b;
				}
			}
			return !beat ? null : beat.beat;
		}
		/**
		* Finishes the lookup object and optimizes itself for fast access.
		*/
		finish(scale = 1) {
			this.realBounds.scaleWith(scale);
			this.visualBounds.scaleWith(scale);
			this.lineAlignedBounds.scaleWith(scale);
			this.bars.sort((a, b) => {
				if (a.realBounds.y < b.realBounds.y) return -1;
				if (a.realBounds.y > b.realBounds.y) return 1;
				if (a.realBounds.x < b.realBounds.x) return -1;
				if (a.realBounds.x > b.realBounds.x) return 1;
				return 0;
			});
			for (const bar of this.bars) bar.finish(scale);
		}
		/**
		* Adds a new beat to the lookup.
		* @param bounds The beat bounds to add.
		*/
		addBeat(bounds) {
			this.staffSystemBounds.boundsLookup.addBeat(bounds);
		}
	};
	//#endregion
	//#region src/rendering/utils/NoteBounds.ts
	/**
	* Represents the bounds of a single note
	* @public
	*/
	var NoteBounds = class {
		/**
		* Gets or sets the reference to the beat boudns this note relates to.
		*/
		beatBounds;
		/**
		* Gets or sets the bounds of the individual note head.
		*/
		noteHeadBounds;
		/**
		* Gets or sets the note related to this instance.
		*/
		note;
		/**
		* Finishes the lookup object and optimizes itself for fast access.
		*/
		finish(scale = 1) {
			this.noteHeadBounds.scaleWith(scale);
		}
	};
	//#endregion
	//#region src/rendering/utils/StaffSystemBounds.ts
	/**
	* Represents the bounds of a staff system.
	* @public
	*/
	var StaffSystemBounds = class {
		/**
		* Gets or sets the index of the bounds within the parent lookup.
		* This allows fast access of the next/previous system.
		*/
		index = 0;
		/**
		* Gets or sets the bounds covering all visually visible elements of this staff system.
		*/
		visualBounds;
		/**
		* Gets or sets the actual bounds of the elements in this staff system including whitespace areas.
		*/
		realBounds;
		/**
		* Gets or sets the list of master bar bounds related to this staff system.
		*/
		bars = [];
		/**
		* Gets or sets a reference to the parent bounds lookup.
		*/
		boundsLookup;
		/**
		* Whether this system's bounds have already been scaled via `finish`. Prevents double-scaling
		* when the parent `BoundsLookup` is preserved across partial renders and `finish` is invoked
		* again on a mix of already-scaled (preserved) and newly-registered (natural-coordinate) systems.
		*/
		isFinished = false;
		/**
		* Finished the lookup for optimized access. Idempotent: once finished, further calls are no-ops
		* so preserved systems survive partial renders without being re-scaled.
		*/
		finish(scale = 1) {
			if (this.isFinished) return;
			this.realBounds.scaleWith(scale);
			this.visualBounds.scaleWith(scale);
			for (const t of this.bars) t.finish(scale);
			this.isFinished = true;
		}
		/**
		* Adds a new master bar to this lookup.
		* @param bounds The master bar bounds to add.
		*/
		addBar(bounds) {
			this.boundsLookup.addMasterBar(bounds);
			bounds.staffSystemBounds = this;
			this.bars.push(bounds);
		}
		/**
		* Tries to find the master bar bounds that are located at the given X-position.
		* @param x The X-position to find a master bar.
		* @returns The master bounds at the given X-position.
		*/
		findBarAtPos(x) {
			let b = null;
			for (const bar of this.bars) if (!b || bar.realBounds.x < x) b = bar;
			else if (x > bar.realBounds.x + bar.realBounds.w) break;
			return b;
		}
	};
	//#endregion
	//#region src/rendering/utils/BoundsLookup.ts
	/**
	* @public
	*/
	var BoundsLookup = class BoundsLookup {
		toJson() {
			const json = /* @__PURE__ */ new Map();
			const systems = [];
			json.set("staffSystems", systems);
			for (const system of this.staffSystems) {
				const g = /* @__PURE__ */ new Map();
				g.set("visualBounds", BoundsLookup._boundsToJson(system.visualBounds));
				g.set("realBounds", BoundsLookup._boundsToJson(system.realBounds));
				const gBars = [];
				g.set("bars", gBars);
				for (const masterBar of system.bars) {
					const mb = /* @__PURE__ */ new Map();
					mb.set("lineAlignedBounds", BoundsLookup._boundsToJson(masterBar.lineAlignedBounds));
					mb.set("visualBounds", BoundsLookup._boundsToJson(masterBar.visualBounds));
					mb.set("realBounds", BoundsLookup._boundsToJson(masterBar.realBounds));
					mb.set("index", masterBar.index);
					mb.set("isFirstOfLine", masterBar.isFirstOfLine);
					const mbBars = [];
					mb.set("bars", mbBars);
					for (const bar of masterBar.bars) {
						const b = /* @__PURE__ */ new Map();
						b.set("visualBounds", BoundsLookup._boundsToJson(bar.visualBounds));
						b.set("realBounds", BoundsLookup._boundsToJson(bar.realBounds));
						const bBeats = [];
						b.set("beats", bBeats);
						for (const beat of bar.beats) {
							const bb = /* @__PURE__ */ new Map();
							bb.set("visualBounds", BoundsLookup._boundsToJson(beat.visualBounds));
							bb.set("realBounds", BoundsLookup._boundsToJson(beat.realBounds));
							bb.set("onNotesX", beat.onNotesX);
							bb.set("beatIndex", beat.beat.index);
							bb.set("voiceIndex", beat.beat.voice.index);
							bb.set("barIndex", beat.beat.voice.bar.index);
							bb.set("staffIndex", beat.beat.voice.bar.staff.index);
							bb.set("trackIndex", beat.beat.voice.bar.staff.track.index);
							if (beat.notes) {
								const notes = [];
								bb.set("notes", notes);
								for (const note of beat.notes) {
									const n = /* @__PURE__ */ new Map();
									n.set("index", note.note.index);
									n.set("noteHeadBounds", BoundsLookup._boundsToJson(note.noteHeadBounds));
									notes.push(n);
								}
							}
							bBeats.push(bb);
						}
						mbBars.push(b);
					}
					gBars.push(mb);
				}
				systems.push(g);
			}
			return json;
		}
		static fromJson(json, score) {
			if (json === null) return null;
			const lookup = new BoundsLookup();
			const staffSystems = json.get("staffSystems");
			for (const staffSystem of staffSystems) {
				const sg = new StaffSystemBounds();
				sg.visualBounds = BoundsLookup._boundsFromJson(staffSystem.get("visualBounds"));
				sg.realBounds = BoundsLookup._boundsFromJson(staffSystem.get("realBounds"));
				lookup.addStaffSystem(sg);
				for (const masterBar of staffSystem.get("bars")) {
					const mb = new MasterBarBounds();
					mb.index = masterBar.get("index");
					mb.isFirstOfLine = masterBar.get("isFirstOfLine");
					mb.lineAlignedBounds = BoundsLookup._boundsFromJson(masterBar.get("lineAlignedBounds"));
					mb.visualBounds = BoundsLookup._boundsFromJson(masterBar.get("visualBounds"));
					mb.realBounds = BoundsLookup._boundsFromJson(masterBar.get("realBounds"));
					lookup.addMasterBar(mb);
					for (const bar of masterBar.get("bars")) {
						const b = new BarBounds();
						b.visualBounds = BoundsLookup._boundsFromJson(bar.get("visualBounds"));
						b.realBounds = BoundsLookup._boundsFromJson(bar.get("realBounds"));
						mb.addBar(b);
						for (const beat of bar.get("beats")) {
							const bb = new BeatBounds();
							bb.visualBounds = BoundsLookup._boundsFromJson(beat.get("visualBounds"));
							bb.realBounds = BoundsLookup._boundsFromJson(beat.get("realBounds"));
							bb.onNotesX = beat.get("onNotesX");
							bb.beat = score.tracks[beat.get("trackIndex")].staves[beat.get("staffIndex")].bars[beat.get("barIndex")].voices[beat.get("voiceIndex")].beats[beat.get("beatIndex")];
							if (beat.has("notes")) {
								bb.notes = [];
								for (const note of beat.get("notes")) {
									const n = new NoteBounds();
									n.note = bb.beat.notes[note.get("index")];
									n.noteHeadBounds = BoundsLookup._boundsFromJson(note.get("noteHeadBounds"));
									bb.addNote(n);
								}
							}
							b.addBeat(bb);
						}
					}
				}
			}
			return lookup;
		}
		static _boundsFromJson(boundsRaw) {
			const b = new Bounds();
			b.x = boundsRaw.get("x");
			b.y = boundsRaw.get("y");
			b.w = boundsRaw.get("w");
			b.h = boundsRaw.get("h");
			return b;
		}
		static _boundsToJson(bounds) {
			const json = /* @__PURE__ */ new Map();
			json.set("x", bounds.x);
			json.set("y", bounds.y);
			json.set("w", bounds.w);
			json.set("h", bounds.h);
			return json;
		}
		_beatLookup = /* @__PURE__ */ new Map();
		_masterBarLookup = /* @__PURE__ */ new Map();
		_currentStaffSystem = null;
		/**
		* Gets a list of all individual staff systems contained in the rendered music notation.
		*/
		staffSystems = [];
		/**
		* Gets or sets a value indicating whether this lookup was finished already.
		*/
		isFinished = false;
		/**
		* Finishes the lookup for optimized access.
		*/
		finish(scale = 1) {
			for (const t of this.staffSystems) t.finish(scale);
			this.isFinished = true;
		}
		/**
		* Re-opens the lookup for registrations without discarding previously registered bounds.
		* Used by the renderer when it preserves this lookup across a partial render so that new
		* bounds for the re-layouted range can be added while preserved systems stay intact.
		* @internal
		*/
		resetForPartialUpdate() {
			this.isFinished = false;
		}
		/**
		* Removes all entries belonging to the given master bar index and any bars after it.
		* Used before a partial render re-registers bounds for the re-layouted range, so the
		* preserved lookup ends up with only the unchanged entries when registration begins.
		*
		* Assumes the layout aligns its re-layouted range to system boundaries - i.e. the first
		* system to clear starts exactly at `masterBarIndex`. Caller is responsible for passing
		* the first master-bar-index of the first re-layouted system.
		* @internal
		*/
		clearFromMasterBar(masterBarIndex) {
			let firstRemovedSystem = -1;
			for (let i = 0; i < this.staffSystems.length; i++) {
				const systemBars = this.staffSystems[i].bars;
				if (systemBars.length > 0 && systemBars[0].index >= masterBarIndex) {
					firstRemovedSystem = i;
					break;
				}
			}
			if (firstRemovedSystem !== -1) this.staffSystems.splice(firstRemovedSystem, this.staffSystems.length - firstRemovedSystem);
			for (const key of Array.from(this._masterBarLookup.keys())) if (key >= masterBarIndex) this._masterBarLookup.delete(key);
			for (const key of Array.from(this._beatLookup.keys())) {
				const list = this._beatLookup.get(key);
				const filtered = list.filter((b) => b.beat.voice.bar.index < masterBarIndex);
				if (filtered.length === 0) this._beatLookup.delete(key);
				else if (filtered.length !== list.length) this._beatLookup.set(key, filtered);
			}
			this._currentStaffSystem = null;
		}
		/**
		* Adds a new staff sytem to the lookup.
		* @param bounds The staff system bounds to add.
		*/
		addStaffSystem(bounds) {
			bounds.index = this.staffSystems.length;
			bounds.boundsLookup = this;
			this.staffSystems.push(bounds);
			this._currentStaffSystem = bounds;
		}
		/**
		* Adds a new master bar to the lookup.
		* @param bounds The master bar bounds to add.
		*/
		addMasterBar(bounds) {
			if (!bounds.staffSystemBounds) {
				bounds.staffSystemBounds = this._currentStaffSystem;
				this._masterBarLookup.set(bounds.index, bounds);
				this._currentStaffSystem.addBar(bounds);
			} else this._masterBarLookup.set(bounds.index, bounds);
		}
		/**
		* Adds a new beat to the lookup.
		* @param bounds The beat bounds to add.
		*/
		addBeat(bounds) {
			if (!this._beatLookup.has(bounds.beat.id)) this._beatLookup.set(bounds.beat.id, []);
			this._beatLookup.get(bounds.beat.id)?.push(bounds);
		}
		/**
		* Tries to find the master bar bounds by a given index.
		* @param index The index of the master bar to find.
		* @returns The master bar bounds if it was rendered, or null if no boundary information is available.
		*/
		findMasterBarByIndex(index) {
			if (this._masterBarLookup.has(index)) return this._masterBarLookup.get(index);
			return null;
		}
		/**
		* Tries to find the master bar bounds by a given master bar.
		* @param bar The master bar to find.
		* @returns The master bar bounds if it was rendered, or null if no boundary information is available.
		*/
		findMasterBar(bar) {
			const id = bar.index;
			if (this._masterBarLookup.has(id)) return this._masterBarLookup.get(id);
			return null;
		}
		/**
		* Tries to find the bounds of a given beat.
		* @param beat The beat to find.
		* @returns The beat bounds if it was rendered, or null if no boundary information is available.
		*/
		findBeat(beat) {
			const all = this.findBeats(beat);
			return all ? all[0] : null;
		}
		/**
		* Tries to find the bounds of a given beat.
		* @param beat The beat to find.
		* @returns The beat bounds if it was rendered, or null if no boundary information is available.
		*/
		findBeats(beat) {
			const id = beat.id;
			if (this._beatLookup.has(id)) return this._beatLookup.get(id);
			return null;
		}
		/**
		* Tries to find a beat at the given absolute position.
		* @param x The absolute X-position of the beat to find.
		* @param y The absolute Y-position of the beat to find.
		* @returns The beat found at the given position or null if no beat could be found.
		*/
		getBeatAtPos(x, y) {
			let bottom = 0;
			let top = this.staffSystems.length - 1;
			let staffSystemIndex = -1;
			while (bottom <= top) {
				const middle = (top + bottom) / 2 | 0;
				const system = this.staffSystems[middle];
				if (y >= system.realBounds.y && y <= system.realBounds.y + system.realBounds.h) {
					staffSystemIndex = middle;
					break;
				}
				if (y < system.realBounds.y) top = middle - 1;
				else bottom = middle + 1;
			}
			if (staffSystemIndex === -1) return null;
			const bar = this.staffSystems[staffSystemIndex].findBarAtPos(x);
			if (bar) return bar.findBeatAtPos(x);
			return null;
		}
		/**
		* Tries to find the note at the given position using the given beat for fast access.
		* Use {@link findBeat} to find a beat for a given position first.
		* @param beat The beat containing the note.
		* @param x The X-position of the note.
		* @param y The Y-position of the note.
		* @returns The note at the given position within the beat.
		*/
		getNoteAtPos(beat, x, y) {
			const beatBounds = this.findBeats(beat);
			if (beatBounds) for (const b of beatBounds) {
				const note = b.findNoteAtPos(x, y);
				if (note) return note;
			}
			return null;
		}
	};
	//#endregion
	//#region src/platform/worker/AlphaTabWorkerScoreRenderer.ts
	/**
	* @internal
	*/
	var AlphaTabWorkerScoreRenderer = class {
		_api;
		_worker;
		_width = 0;
		boundsLookup = null;
		constructor(api, worker) {
			this._api = api;
			this._worker = worker;
			this._worker.postMessage({
				cmd: "alphaTab.initialize",
				settings: this._serializeSettingsForWorker(api.settings)
			});
			this._worker.addEventListener("message", (e) => this._handleWorkerMessage(e));
		}
		destroy() {
			this._worker.terminate();
		}
		updateSettings(settings) {
			this._worker.postMessage({
				cmd: "alphaTab.updateSettings",
				settings: this._serializeSettingsForWorker(settings)
			});
		}
		_serializeSettingsForWorker(settings) {
			const jsObject = JsonConverter.settingsToJsObject(Environment.prepareForPostMessage(settings));
			jsObject.delete("player");
			return jsObject;
		}
		render(renderHints) {
			this._worker.postMessage({
				cmd: "alphaTab.render",
				renderHints
			});
		}
		resizeRender() {
			this._worker.postMessage({ cmd: "alphaTab.resizeRender" });
		}
		renderResult(resultId) {
			this._worker.postMessage({
				cmd: "alphaTab.renderResult",
				resultId
			});
		}
		get width() {
			return this._width;
		}
		set width(value) {
			this._width = value;
			this._worker.postMessage({
				cmd: "alphaTab.setWidth",
				width: value
			});
		}
		_handleWorkerMessage(e) {
			const data = e.data;
			switch (data.cmd) {
				case "alphaTab.preRender":
					this.preRender.trigger(data.resize);
					break;
				case "alphaTab.partialRenderFinished":
					this.partialRenderFinished.trigger(data.result);
					break;
				case "alphaTab.partialLayoutFinished":
					this.partialLayoutFinished.trigger(data.result);
					break;
				case "alphaTab.renderFinished":
					this.renderFinished.trigger(data.result);
					break;
				case "alphaTab.postRenderFinished":
					if (this._api.score && data.boundsLookup) {
						this.boundsLookup = BoundsLookup.fromJson(data.boundsLookup, this._api.score);
						this.boundsLookup?.finish();
					}
					this.postRenderFinished.trigger();
					break;
				case "alphaTab.error":
					this.error.trigger(data.error);
					break;
			}
		}
		renderScore(score, trackIndexes, renderHints) {
			const jsObject = score == null ? null : JsonConverter.scoreToJsObject(Environment.prepareForPostMessage(score));
			this._worker.postMessage({
				cmd: "alphaTab.renderScore",
				score: jsObject,
				trackIndexes: Environment.prepareForPostMessage(trackIndexes),
				fontSizes: FontSizes.fontSizeLookupTables,
				renderHints
			});
		}
		preRender = new EventEmitterOfT();
		partialRenderFinished = new EventEmitterOfT();
		partialLayoutFinished = new EventEmitterOfT();
		renderFinished = new EventEmitterOfT();
		postRenderFinished = new EventEmitter();
		error = new EventEmitterOfT();
	};
	//#endregion
	//#region src/platform/Cursors.ts
	/**
	* This wrapper holds all cursor related elements.
	* @public
	*/
	var Cursors = class {
		/**
		* Gets the element that spans across the whole music sheet and holds the other cursor elements.
		*/
		cursorWrapper;
		/**
		* Gets the element that is positioned above the bar that is currently played.
		*/
		barCursor;
		/**
		* Gets the element that is positioned above the beat that is currently played.
		*/
		beatCursor;
		/**
		* Gets the element that spans across the whole music sheet and will hold any selection related elements.
		*/
		selectionWrapper;
		/**
		* Initializes a new instance of the {@link Cursors} class.
		* @param cursorWrapper
		* @param barCursor
		* @param beatCursor
		* @param selectionWrapper
		*/
		constructor(cursorWrapper, barCursor, beatCursor, selectionWrapper) {
			this.cursorWrapper = cursorWrapper;
			this.barCursor = barCursor;
			this.beatCursor = beatCursor;
			this.selectionWrapper = selectionWrapper;
		}
	};
	//#endregion
	//#region src/platform/javascript/ScalableHtmlElementContainer.ts
	/**
	* An IContainer implementation which can be used for cursors and select ranges
	* where browser scaling is relevant.
	*
	* The problem is that with having 1x1 pixel elements which are sized then to the actual size with a
	* scale transform this cannot be combined properly with a browser zoom.
	*
	* The browser will apply first the browser zoom to the 1x1px element and then apply the scale leaving it always
	* at full scale instead of a 50% browser zoom.
	*
	* This is solved in this container by scaling the element first up to a higher degree (as specified)
	* so that the browser can do a scaling according to typical zoom levels and then the scaling will work.
	* @target web
	* @internal
	*/
	var ScalableHtmlElementContainer = class extends HtmlElementContainer {
		_xscale;
		_yscale;
		centerAtPosition = false;
		constructor(element, xscale, yscale) {
			super(element);
			this._xscale = xscale;
			this._yscale = yscale;
		}
		get width() {
			return this.element.offsetWidth / this._xscale;
		}
		set width(value) {
			this.element.style.width = `${value * this._xscale}px`;
		}
		get height() {
			return this.element.offsetHeight / this._yscale;
		}
		set height(value) {
			if (value >= 0) this.element.style.height = `${value * this._yscale}px`;
			else this.element.style.height = "100%";
		}
		setBounds(x, y, w, h) {
			if (Number.isNaN(x)) x = this.lastBounds.x;
			if (Number.isNaN(y)) y = this.lastBounds.y;
			if (Number.isNaN(w)) w = this.lastBounds.w;
			else w = w / this._xscale;
			if (Number.isNaN(h)) h = this.lastBounds.h;
			else h = h / this._yscale;
			let transform = `translate(${x}px, ${y}px) scale(${w}, ${h})`;
			if (this.centerAtPosition) transform += ` translateX(-50%)`;
			this.element.style.transform = transform;
			this.element.style.transformOrigin = "top left";
			this.lastBounds.x = x;
			this.lastBounds.y = y;
			this.lastBounds.w = w;
			this.lastBounds.h = h;
		}
	};
	//#endregion
	//#region src/platform/javascript/AudioElementBackingTrackSynthOutput.ts
	/**
	* @target web
	* @internal
	*/
	var AudioElementBackingTrackSynthOutput = class {
		sampleRate = 44100;
		audioElement;
		_updateInterval = 0;
		get backingTrackDuration() {
			const duration = this.audioElement.duration ?? 0;
			return Number.isFinite(duration) ? duration * 1e3 : 0;
		}
		get playbackRate() {
			return this.audioElement.playbackRate;
		}
		set playbackRate(value) {
			this.audioElement.playbackRate = value;
		}
		get masterVolume() {
			return this.audioElement.volume;
		}
		set masterVolume(value) {
			this.audioElement.volume = value;
		}
		seekTo(time) {
			this.audioElement.currentTime = time / 1e3;
		}
		loadBackingTrack(backingTrack) {
			if (this.audioElement?.src) URL.revokeObjectURL(this.audioElement.src);
			const blob = new Blob([backingTrack.rawAudioFile]);
			const playbackRate = this.audioElement.playbackRate;
			this.audioElement.src = URL.createObjectURL(blob);
			this.audioElement.playbackRate = playbackRate;
		}
		open(_bufferTimeInMilliseconds) {
			const audioElement = document.createElement("audio");
			audioElement.style.display = "none";
			document.body.appendChild(audioElement);
			audioElement.addEventListener("seeked", () => {
				this._updatePosition();
			});
			audioElement.addEventListener("timeupdate", () => {
				this._updatePosition();
			});
			this.audioElement = audioElement;
			this.ready.trigger();
		}
		_updatePosition() {
			const timePos = this.audioElement.currentTime * 1e3;
			this.timeUpdate.trigger(timePos);
		}
		play() {
			this.audioElement.play();
			this._updateInterval = window.setInterval(() => {
				this._updatePosition();
			}, 50);
		}
		destroy() {
			const audioElement = this.audioElement;
			if (audioElement) document.body.removeChild(audioElement);
		}
		pause() {
			this.audioElement.pause();
			window.clearInterval(this._updateInterval);
		}
		addSamples(_samples) {}
		resetSamples() {}
		activate() {}
		ready = new EventEmitter();
		samplesPlayed = new EventEmitterOfT();
		timeUpdate = new EventEmitterOfT();
		sampleRequest = new EventEmitter();
		async enumerateOutputDevices() {
			return WebAudioHelper.enumerateOutputDevices();
		}
		async setOutputDevice(device) {
			if (!await WebAudioHelper.checkSinkIdSupport()) return;
			if (!device) await this.audioElement.setSinkId("");
			else await this.audioElement.setSinkId(device.deviceId);
		}
		async getOutputDevice() {
			if (!await WebAudioHelper.checkSinkIdSupport()) return null;
			const sinkId = this.audioElement.sinkId;
			if (typeof sinkId !== "string" || sinkId === "" || sinkId === "default") return null;
			let device = WebAudioHelper.findKnownDevice(sinkId);
			if (device) return device;
			const allDevices = await this.enumerateOutputDevices();
			device = allDevices.find((d) => d.deviceId === sinkId);
			if (device) return device;
			Logger.warning("WebAudio", "Could not find output device in device list", sinkId, allDevices);
			return null;
		}
	};
	//#endregion
	//#region src/synth/ds/Queue.ts
	/**
	* @internal
	*/
	var QueueItem = class {
		value;
		next;
		constructor(value) {
			this.value = value;
		}
	};
	/**
	* @internal
	*/
	var Queue = class {
		_head;
		_tail;
		get isEmpty() {
			return this._head === void 0;
		}
		clear() {
			this._head = void 0;
			this._tail = void 0;
		}
		enqueue(item) {
			const queueItem = new QueueItem(item);
			if (this._tail) {
				this._tail.next = queueItem;
				this._tail = queueItem;
			} else {
				this._head = queueItem;
				this._tail = queueItem;
			}
		}
		enqueueFront(item) {
			const queueItem = new QueueItem(item);
			queueItem.next = this._head;
			if (this._head) this._head = queueItem;
			else {
				this._head = queueItem;
				this._tail = queueItem;
			}
		}
		peek() {
			const head = this._head;
			if (!head) return;
			return head.value;
		}
		dequeue() {
			const head = this._head;
			if (!head) return;
			const newHead = head.next;
			this._head = newHead;
			if (!newHead) this._tail = void 0;
			return head.value;
		}
	};
	//#endregion
	//#region src/synth/IAudioExporter.ts
	/**
	* The options controlling how to export the audio.
	* @public
	*/
	var AudioExportOptions = class {
		/**
		* The soundfonts to load and use for generating the audio.
		* If not provided, the already loaded soundfonts of the synthesizer will be used.
		* If no existing synthesizer is initialized, the generated audio might not contain any hearable audio.
		*/
		soundFonts;
		/**
		* The output sample rate.
		* @default `44100`
		*/
		sampleRate = 44100;
		/**
		* Whether to respect sync point information during export.
		* @default `true`
		* @remarks
		* If the song contains sync point information for synchronization with an external media,
		* this option allows controlling whether the synthesized audio is aligned with these points.
		*
		* This is useful when mixing the exported audio together with external media, keeping the same timing.
		*
		* Disable this option if you want the original/exact timing as per music sheet in the exported audio.
		*/
		useSyncPoints = false;
		/**
		* The current master volume as percentage. (range: 0.0-3.0, default 1.0)
		*/
		masterVolume = 1;
		/**
		* The metronome volume. (range: 0.0-3.0, default 0.0)
		*/
		metronomeVolume = 0;
		/**
		* The range of the song that should be exported. Set this to null
		* to play the whole song.
		*/
		playbackRange;
		/**
		* The volume for individual tracks as percentage (range: 0.0-3.0).
		* @remarks
		* The key is the track index, and the value is the relative volume.
		* The configured volume (as per data model) still applies, this is an additional volume control.
		* If no custom value is set, 100% is used.
		* No values from the currently active synthesizer are applied.
		*
		* The meaning of the key changes when used with AlphaSynth directly, in this case the key is the midi channel .
		*/
		trackVolume = /* @__PURE__ */ new Map();
		/**
		* The additional semitone pitch transpose to apply for individual tracks.
		* @remarks
		* The key is the track index, and the value is the number of semitones to apply.
		* No values from the currently active synthesizer are applied.
		*
		* The meaning of the key changes when used with AlphaSynth directly, in this case the key is the midi channel .
		*/
		trackTranspositionPitches = /* @__PURE__ */ new Map();
	};
	/**
	* Represents a single chunk of audio produced.
	* @public
	*/
	var AudioExportChunk = class {
		/**
		* The generated samples for the requested chunk.
		*/
		samples;
		/**
		* The current time position within the song in milliseconds.
		*/
		currentTime = 0;
		/**
		* The total length of the song in milliseconds.
		*/
		endTime = 0;
		/**
		* The current time position within the song in midi ticks.
		*/
		currentTick = 0;
		/**
		* The total length of the song in midi ticks.
		*/
		endTick = 0;
	};
	//#endregion
	//#region src/synth/synthesis/SynthEvent.ts
	/**
	* @internal
	*/
	var SynthEvent = class SynthEvent {
		eventIndex;
		event;
		isMetronome;
		time = 0;
		constructor(eventIndex, e) {
			this.eventIndex = eventIndex;
			this.event = e;
			this.isMetronome = this.event.type === MidiEventType.AlphaTabMetronome;
		}
		static newMetronomeEvent(eventIndex, tick, counter, durationInTicks, durationInMillis) {
			return new SynthEvent(eventIndex, new AlphaTabMetronomeEvent(0, tick, counter, durationInTicks, durationInMillis));
		}
	};
	//#endregion
	//#region src/synth/IAlphaSynth.ts
	/**
	* Rerpresents a point to sync the alphaTab time axis with an external backing track.
	* @public
	*/
	var BackingTrackSyncPoint = class {
		/**
		* The index of the masterbar to which this sync point belongs to.
		* @remarks
		* This property is purely informative for external use like in editors.
		* It has no impact to the synchronization itself.
		*/
		masterBarIndex = 0;
		/**
		* The occurence of the masterbar to which this sync point belongs to. The occurence
		* is 0-based and increases with every repeated play of a masterbar (e.g. on repeats or jumps).
		* @remarks
		* This property is purely informative for external use like in editors.
		* It has no impact to the synchronization itself.
		*/
		masterBarOccurence = 0;
		/**
		* The BPM the synthesizer has at the exact tick position of this sync point.
		*/
		synthBpm = 0;
		/**
		* The millisecond time position of the synthesizer when this sync point is reached.
		*/
		synthTime = 0;
		/**
		* The midi tick position of the synthesizer when this sync point is reached.
		*/
		synthTick = 0;
		/**
		* The millisecond time in the external media marking the synchronization point.
		*/
		syncTime = 0;
		/**
		* The BPM the song will have virtually after this sync point to align the external media time axis
		* with the one from the synthesizer.
		*/
		syncBpm = 0;
		/**
		* Updates the synchronization BPM that will apply after this sync point.
		* @param nextSyncPointSynthTime The synthesizer time of the next sync point after this one.
		* @param nextSyncPointSyncTime The synchronization time of the next sync point after this one.
		*/
		updateSyncBpm(nextSyncPointSynthTime, nextSyncPointSyncTime) {
			const modifiedTempo = (nextSyncPointSynthTime - this.synthTime) / (nextSyncPointSyncTime - this.syncTime) * this.synthBpm;
			this.syncBpm = modifiedTempo;
		}
	};
	//#endregion
	//#region src/synth/MidiFileSequencer.ts
	/**
	* @internal
	*/
	var MidiFileSequencerTempoChange = class {
		bpm;
		ticks;
		time;
		constructor(bpm, ticks, time) {
			this.bpm = bpm;
			this.ticks = ticks;
			this.time = time;
		}
	};
	/**
	* @internal
	*/
	var MidiSequencerState = class {
		tempoChanges = [];
		tempoChangeIndex = 0;
		syncPoints = [];
		firstProgramEventPerChannel = /* @__PURE__ */ new Map();
		firstTimeSignatureNumerator = 0;
		firstTimeSignatureDenominator = 0;
		synthData = [];
		division = MidiUtils.QuarterTime;
		eventIndex = 0;
		currentTime = 0;
		syncPointIndex = 0;
		playbackRange = null;
		playbackRangeStartTime = 0;
		playbackRangeEndTime = 0;
		endTick = 0;
		endTime = 0;
		currentTempo = 0;
		syncPointTempo = 0;
		metronomeChannel = SynthConstants.DefaultChannelCount - 1;
	};
	/**
	* This sequencer dispatches midi events to the synthesizer based on the current
	* synthesize position. The sequencer does not consider the playback speed.
	* @internal
	*/
	var MidiFileSequencer = class MidiFileSequencer {
		_synthesizer;
		_currentState;
		_mainState;
		_oneTimeState = null;
		_countInState = null;
		get metronomeChannel() {
			return this._mainState.metronomeChannel;
		}
		get isPlayingMain() {
			return this._currentState === this._mainState;
		}
		get isPlayingOneTimeMidi() {
			return this._currentState === this._oneTimeState;
		}
		get isPlayingCountIn() {
			return this._currentState === this._countInState;
		}
		constructor(synthesizer) {
			this._synthesizer = synthesizer;
			this._mainState = new MidiSequencerState();
			this._currentState = this._mainState;
		}
		get mainPlaybackRange() {
			return this._mainState.playbackRange;
		}
		set mainPlaybackRange(value) {
			this._mainState.playbackRange = value;
			if (value) {
				this._mainState.playbackRangeStartTime = this._tickPositionToTimePositionWithSpeed(this._mainState, value.startTick, 1);
				this._mainState.playbackRangeEndTime = this._tickPositionToTimePositionWithSpeed(this._mainState, value.endTick, 1);
			}
		}
		isLooping = false;
		get currentTime() {
			return this._currentState.currentTime / this.playbackSpeed;
		}
		/**
		* Gets the duration of the song in ticks.
		*/
		get currentEndTick() {
			return this._currentState.endTick;
		}
		get currentEndTime() {
			return this._currentState.endTime / this.playbackSpeed;
		}
		get currentTempo() {
			return this._currentState.currentTempo;
		}
		get modifiedTempo() {
			return this._currentState.syncPointTempo * this.playbackSpeed;
		}
		get syncPointTempo() {
			return this._currentState.syncPointTempo;
		}
		get currentSyncPoints() {
			return this._currentState.syncPoints;
		}
		/**
		* Gets or sets the playback speed.
		*/
		playbackSpeed = 1;
		mainSeek(timePosition) {
			timePosition *= this.playbackSpeed;
			if (this.mainPlaybackRange) {
				if (timePosition < this._mainState.playbackRangeStartTime) timePosition = this._mainState.playbackRangeStartTime;
				else if (timePosition > this._mainState.playbackRangeEndTime) timePosition = this._mainState.playbackRangeEndTime;
			}
			if (timePosition > this._mainState.currentTime) this._mainSilentProcess(timePosition - this._mainState.currentTime);
			else if (timePosition < this._mainState.currentTime) {
				this._mainState.currentTime = 0;
				this._mainState.eventIndex = 0;
				this._mainState.syncPointIndex = 0;
				this._mainState.tempoChangeIndex = 0;
				this._mainState.currentTempo = this._mainState.tempoChanges[0].bpm;
				this._mainState.syncPointTempo = this._mainState.syncPoints.length > 0 ? this._mainState.syncPoints[0].syncBpm : this._mainState.currentTempo;
				if (this.isPlayingMain) {
					const metronomeVolume = this._synthesizer.metronomeVolume;
					this._synthesizer.noteOffAll(true);
					this._synthesizer.resetSoft();
					this._synthesizer.setupMetronomeChannel(this.metronomeChannel, metronomeVolume);
				}
				this._mainSilentProcess(timePosition);
			}
		}
		_mainSilentProcess(milliseconds) {
			if (milliseconds <= 0) return;
			const start = Date.now();
			const finalTime = this._mainState.currentTime + milliseconds;
			if (this.isPlayingMain) {
				while (this._mainState.currentTime < finalTime) if (this._fillMidiEventQueueLimited(finalTime - this._mainState.currentTime)) this._synthesizer.synthesizeSilent(SynthConstants.MicroBufferSize);
			}
			this._mainState.currentTime = finalTime;
			const duration = Date.now() - start;
			Logger.debug("Sequencer", `Silent seek finished in ${duration}ms (main)`);
		}
		loadOneTimeMidi(midiFile) {
			this._oneTimeState = this.createStateFromFile(midiFile);
			this._currentState = this._oneTimeState;
		}
		instrumentPrograms = /* @__PURE__ */ new Set();
		percussionKeys = /* @__PURE__ */ new Set();
		loadMidi(midiFile) {
			this.instrumentPrograms.clear();
			this.percussionKeys.clear();
			this._mainState = this.createStateFromFile(midiFile);
			this._currentState = this._mainState;
		}
		createStateFromFile(midiFile) {
			const state = new MidiSequencerState();
			this.percussionKeys.add(SynthConstants.MetronomeKey);
			state.tempoChanges = [];
			state.division = midiFile.division;
			state.eventIndex = 0;
			state.currentTime = 0;
			state.synthData = [];
			let bpm = 120;
			let absTick = 0;
			let absTime = 0;
			let metronomeCount = 0;
			let metronomeLengthInTicks = 0;
			let metronomeLengthInMillis = 0;
			let metronomeTick = midiFile.tickShift;
			let metronomeTime = 0;
			let maxChannel = 0;
			let previousTick = 0;
			for (const mEvent of midiFile.events) {
				const synthData = new SynthEvent(state.synthData.length, mEvent);
				state.synthData.push(synthData);
				const deltaTick = mEvent.tick - previousTick;
				absTick += deltaTick;
				absTime += deltaTick * (6e4 / (bpm * midiFile.division));
				synthData.time = absTime;
				previousTick = mEvent.tick;
				if (metronomeLengthInTicks > 0) while (metronomeTick < absTick) {
					const metronome = SynthEvent.newMetronomeEvent(state.synthData.length, metronomeTick, Math.floor(metronomeTick / metronomeLengthInTicks) % metronomeCount, metronomeLengthInTicks, metronomeLengthInMillis);
					state.synthData.push(metronome);
					metronome.time = metronomeTime;
					metronomeTick += metronomeLengthInTicks;
					metronomeTime += metronomeLengthInMillis;
				}
				if (mEvent.type === MidiEventType.TempoChange) {
					const meta = mEvent;
					bpm = MidiFileSequencer._sanitizeBpm(meta.beatsPerMinute);
					state.tempoChanges.push(new MidiFileSequencerTempoChange(bpm, absTick, absTime));
					metronomeLengthInMillis = metronomeLengthInTicks * (6e4 / (bpm * midiFile.division));
				} else if (mEvent.type === MidiEventType.TimeSignature) {
					const meta = mEvent;
					const timeSignatureDenominator = Math.pow(2, meta.denominatorIndex);
					metronomeCount = meta.numerator;
					metronomeLengthInTicks = state.division * (4 / timeSignatureDenominator) | 0;
					metronomeLengthInMillis = metronomeLengthInTicks * (6e4 / (bpm * midiFile.division));
					if (state.firstTimeSignatureDenominator === 0) {
						state.firstTimeSignatureNumerator = meta.numerator;
						state.firstTimeSignatureDenominator = timeSignatureDenominator;
					}
				} else if (mEvent.type === MidiEventType.ProgramChange) {
					const programChange = mEvent;
					const channel = programChange.channel;
					if (!state.firstProgramEventPerChannel.has(channel)) state.firstProgramEventPerChannel.set(channel, synthData);
					if (channel > maxChannel) maxChannel = channel;
					if (!(channel === SynthConstants.PercussionChannel)) this.instrumentPrograms.add(programChange.program);
				} else if (mEvent.type === MidiEventType.NoteOn) {
					const noteOn = mEvent;
					if (noteOn.channel === SynthConstants.PercussionChannel) this.percussionKeys.add(noteOn.noteKey);
					if (noteOn.channel > maxChannel) maxChannel = noteOn.channel;
				}
			}
			state.currentTempo = state.tempoChanges.length > 0 ? state.tempoChanges[0].bpm : bpm;
			state.syncPointTempo = state.currentTempo;
			state.synthData.sort((a, b) => {
				if (a.time > b.time) return 1;
				if (a.time < b.time) return -1;
				return a.eventIndex - b.eventIndex;
			});
			state.endTime = absTime;
			state.endTick = absTick;
			state.metronomeChannel = maxChannel + 1;
			return state;
		}
		fillMidiEventQueue() {
			return this._fillMidiEventQueueLimited(-1);
		}
		fillMidiEventQueueToEndTime(endTime) {
			while (this._mainState.currentTime < endTime) if (this._fillMidiEventQueueLimited(endTime - this._mainState.currentTime)) this._synthesizer.synthesizeSilent(SynthConstants.MicroBufferSize);
			let anyEventsDispatched = false;
			this._currentState.currentTime = endTime;
			while (this._currentState.eventIndex < this._currentState.synthData.length && this._currentState.synthData[this._currentState.eventIndex].time < this._currentState.currentTime) {
				const synthEvent = this._currentState.synthData[this._currentState.eventIndex];
				this._synthesizer.dispatchEvent(synthEvent);
				this._currentState.eventIndex++;
				anyEventsDispatched = true;
			}
			return anyEventsDispatched;
		}
		_fillMidiEventQueueLimited(maxMilliseconds) {
			let millisecondsPerBuffer = SynthConstants.MicroBufferSize / this._synthesizer.outSampleRate * 1e3 * this.playbackSpeed;
			let endTime = this._internalEndTime;
			if (maxMilliseconds > 0) {
				if (maxMilliseconds < millisecondsPerBuffer) millisecondsPerBuffer = maxMilliseconds;
				endTime = Math.min(this._internalEndTime, this._currentState.currentTime + maxMilliseconds);
			}
			let anyEventsDispatched = false;
			this._currentState.currentTime += millisecondsPerBuffer;
			while (this._currentState.eventIndex < this._currentState.synthData.length && this._currentState.synthData[this._currentState.eventIndex].time < this._currentState.currentTime && this._currentState.currentTime < endTime) {
				this._synthesizer.dispatchEvent(this._currentState.synthData[this._currentState.eventIndex]);
				this._currentState.eventIndex++;
				anyEventsDispatched = true;
			}
			return anyEventsDispatched;
		}
		mainTickPositionToTimePosition(tickPosition) {
			return this._tickPositionToTimePositionWithSpeed(this._mainState, tickPosition, this.playbackSpeed);
		}
		mainUpdateSyncPoints(syncPoints) {
			const state = this._mainState;
			syncPoints.sort((a, b) => a.synthTick - b.synthTick);
			state.syncPoints = [];
			if (syncPoints.length >= 0) {
				let bpm = 120;
				let absTick = 0;
				let absTime = 0;
				let tempoChangeIndex = 0;
				for (let i = 0; i < syncPoints.length; i++) {
					const p = syncPoints[i];
					let deltaTick = 0;
					let previousModifiedTempo;
					let previousMillisecondOffset;
					let previousTick;
					if (i === 0) {
						previousModifiedTempo = bpm;
						previousMillisecondOffset = 0;
						previousTick = 0;
					} else {
						const previousSyncPoint = syncPoints[i - 1];
						previousModifiedTempo = MidiFileSequencer._sanitizeBpm(previousSyncPoint.syncBpm);
						previousMillisecondOffset = previousSyncPoint.syncTime;
						previousTick = previousSyncPoint.synthTick;
					}
					while (tempoChangeIndex < state.tempoChanges.length && state.tempoChanges[tempoChangeIndex].ticks <= p.synthTick) {
						deltaTick = state.tempoChanges[tempoChangeIndex].ticks - absTick;
						if (deltaTick > 0) {
							absTick += deltaTick;
							absTime += deltaTick * (6e4 / (bpm * state.division));
							const millisPerTick = (p.syncTime - previousMillisecondOffset) / (p.synthTick - previousTick);
							const interpolatedMillisecondOffset = (absTick - previousTick) * millisPerTick + previousMillisecondOffset;
							const syncPoint = new BackingTrackSyncPoint();
							syncPoint.synthTick = absTick;
							syncPoint.synthBpm = bpm;
							syncPoint.synthTime = absTime;
							syncPoint.syncTime = interpolatedMillisecondOffset;
							syncPoint.syncBpm = previousModifiedTempo;
						}
						bpm = MidiFileSequencer._sanitizeBpm(state.tempoChanges[tempoChangeIndex].bpm);
						tempoChangeIndex++;
					}
					deltaTick = p.synthTick - absTick;
					absTick += deltaTick;
					absTime += deltaTick * (6e4 / (bpm * state.division));
					state.syncPoints.push(p);
				}
			}
			state.syncPointIndex = 0;
			state.syncPointTempo = state.syncPoints.length > 0 ? state.syncPoints[0].syncBpm : state.currentTempo;
		}
		currentTimePositionToTickPosition(timePosition) {
			const state = this._currentState;
			if (state.tempoChanges.length === 0) return 0;
			timePosition *= this.playbackSpeed;
			this._updateCurrentTempo(state, timePosition);
			const lastTempoChange = state.tempoChanges[state.tempoChangeIndex];
			const ticks = (timePosition - lastTempoChange.time) / (6e4 / (MidiFileSequencer._sanitizeBpm(lastTempoChange.bpm) * state.division)) | 0;
			return lastTempoChange.ticks + ticks + 1;
		}
		static _sanitizeBpm(bpm) {
			return Math.max(bpm, 1);
		}
		currentUpdateCurrentTempo(timePosition) {
			this._updateCurrentTempo(this._mainState, timePosition * this.playbackSpeed);
		}
		_updateCurrentTempo(state, timePosition) {
			let tempoChangeIndex = state.tempoChangeIndex;
			if (timePosition < state.tempoChanges[tempoChangeIndex].time) tempoChangeIndex = 0;
			while (tempoChangeIndex + 1 < state.tempoChanges.length && state.tempoChanges[tempoChangeIndex + 1].time <= timePosition) tempoChangeIndex++;
			if (tempoChangeIndex !== state.tempoChangeIndex) {
				state.tempoChangeIndex = tempoChangeIndex;
				state.currentTempo = state.tempoChanges[state.tempoChangeIndex].bpm;
				if (state.syncPoints.length === 0) state.syncPointTempo = state.currentTempo;
			}
		}
		currentUpdateSyncPoints(timePosition) {
			this._updateSyncPoints(this._mainState, timePosition);
		}
		_updateSyncPoints(state, timePosition) {
			const syncPoints = state.syncPoints;
			if (syncPoints.length > 0) {
				let syncPointIndex = Math.min(state.syncPointIndex, syncPoints.length - 1);
				if (timePosition < syncPoints[syncPointIndex].syncTime) syncPointIndex = 0;
				while (syncPointIndex + 1 < syncPoints.length && syncPoints[syncPointIndex + 1].syncTime <= timePosition) syncPointIndex++;
				if (syncPointIndex !== state.syncPointIndex) {
					state.syncPointIndex = syncPointIndex;
					state.syncPointTempo = syncPoints[syncPointIndex].syncBpm;
				}
			} else state.syncPointTempo = state.currentTempo;
		}
		mainTimePositionFromBackingTrack(timePosition, backingTrackLength) {
			const mainState = this._mainState;
			const syncPoints = mainState.syncPoints;
			if (timePosition < 0 || syncPoints.length === 0) return timePosition;
			this._updateSyncPoints(this._mainState, timePosition);
			const syncPointIndex = Math.min(mainState.syncPointIndex, syncPoints.length - 1);
			const currentSyncPoint = syncPoints[syncPointIndex];
			const timeDiff = timePosition - currentSyncPoint.syncTime;
			let alphaTabTimeDiff;
			if (syncPointIndex + 1 < syncPoints.length) {
				const nextSyncPoint = syncPoints[syncPointIndex + 1];
				const relativeTimeDiff = timeDiff / (nextSyncPoint.syncTime - currentSyncPoint.syncTime);
				alphaTabTimeDiff = (nextSyncPoint.synthTime - currentSyncPoint.synthTime) * relativeTimeDiff;
			} else {
				const relativeTimeDiff = timeDiff / (backingTrackLength - currentSyncPoint.syncTime);
				alphaTabTimeDiff = (mainState.endTime - currentSyncPoint.synthTime) * relativeTimeDiff;
			}
			return (currentSyncPoint.synthTime + alphaTabTimeDiff) / this.playbackSpeed;
		}
		mainTimePositionToBackingTrack(timePosition, backingTrackLength) {
			const mainState = this._mainState;
			const syncPoints = mainState.syncPoints;
			if (timePosition < 0 || syncPoints.length === 0) return timePosition;
			timePosition *= this.playbackSpeed;
			let syncPointIndex = Math.min(mainState.syncPointIndex, syncPoints.length - 1);
			if (timePosition < syncPoints[syncPointIndex].synthTime) syncPointIndex = 0;
			while (syncPointIndex + 1 < syncPoints.length && syncPoints[syncPointIndex + 1].synthTime <= timePosition) syncPointIndex++;
			const currentSyncPoint = syncPoints[syncPointIndex];
			const alphaTabTimeDiff = timePosition - currentSyncPoint.synthTime;
			let backingTrackPos;
			if (syncPointIndex + 1 < syncPoints.length) {
				const nextSyncPoint = syncPoints[syncPointIndex + 1];
				const relativeAlphaTabTimeDiff = alphaTabTimeDiff / (nextSyncPoint.synthTime - currentSyncPoint.synthTime);
				const backingTrackDiff = nextSyncPoint.syncTime - currentSyncPoint.syncTime;
				backingTrackPos = currentSyncPoint.syncTime + backingTrackDiff * relativeAlphaTabTimeDiff;
			} else {
				const relativeAlphaTabTimeDiff = alphaTabTimeDiff / (mainState.endTime - currentSyncPoint.synthTime);
				const frameDiff = backingTrackLength - currentSyncPoint.syncTime;
				backingTrackPos = currentSyncPoint.syncTime + frameDiff * relativeAlphaTabTimeDiff;
			}
			return backingTrackPos;
		}
		_tickPositionToTimePositionWithSpeed(state, tickPosition, playbackSpeed) {
			let timePosition = 0;
			let bpm = 120;
			let lastChange = 0;
			for (const c of state.tempoChanges) {
				if (tickPosition < c.ticks) break;
				timePosition = c.time;
				bpm = c.bpm;
				lastChange = c.ticks;
			}
			tickPosition -= lastChange;
			timePosition += tickPosition * (6e4 / (bpm * state.division));
			return timePosition / playbackSpeed;
		}
		get _internalEndTime() {
			if (this.isPlayingMain) return !this.mainPlaybackRange ? this._currentState.endTime : this._currentState.playbackRangeEndTime;
			return this._currentState.endTime;
		}
		get isFinished() {
			return this._currentState.currentTime >= this._internalEndTime;
		}
		stop() {
			if (this.isPlayingMain && this.mainPlaybackRange) this._currentState.currentTime = this.mainPlaybackRange.startTick;
			else this._currentState.currentTime = 0;
			this._currentState.eventIndex = 0;
		}
		resetOneTimeMidi() {
			this._oneTimeState = null;
			this._currentState = this._mainState;
		}
		resetCountIn() {
			this._countInState = null;
			this._currentState = this._mainState;
		}
		startCountIn() {
			this.generateCountInMidi();
			this._currentState = this._countInState;
			this.stop();
			this._synthesizer.noteOffAll(true);
		}
		generateCountInMidi() {
			const state = new MidiSequencerState();
			state.division = this._mainState.division;
			let bpm = 120;
			let timeSignatureNumerator = 4;
			let timeSignatureDenominator = 4;
			if (this._mainState.eventIndex === 0) {
				bpm = this._mainState.tempoChanges[0].bpm;
				timeSignatureNumerator = this._mainState.firstTimeSignatureNumerator;
				timeSignatureDenominator = this._mainState.firstTimeSignatureDenominator;
			} else {
				bpm = this._synthesizer.currentTempo;
				timeSignatureNumerator = this._synthesizer.timeSignatureNumerator;
				timeSignatureDenominator = this._synthesizer.timeSignatureDenominator;
			}
			state.tempoChanges.push(new MidiFileSequencerTempoChange(bpm, 0, 0));
			const metronomeLengthInTicks = state.division * (4 / timeSignatureDenominator) | 0;
			const metronomeLengthInMillis = metronomeLengthInTicks * (6e4 / (bpm * this._mainState.division));
			let metronomeTick = 0;
			let metronomeTime = 0;
			for (let i = 0; i < timeSignatureNumerator; i++) {
				const metronome = SynthEvent.newMetronomeEvent(state.synthData.length, metronomeTick, i, metronomeLengthInTicks, metronomeLengthInMillis);
				state.synthData.push(metronome);
				metronome.time = metronomeTime;
				metronomeTick += metronomeLengthInTicks;
				metronomeTime += metronomeLengthInMillis;
			}
			state.synthData.sort((a, b) => {
				if (a.time > b.time) return 1;
				if (a.time < b.time) return -1;
				return a.eventIndex - b.eventIndex;
			});
			state.endTime = metronomeTime;
			state.endTick = metronomeTick;
			state.currentTempo = bpm;
			state.syncPointTempo = bpm;
			this._countInState = state;
		}
	};
	//#endregion
	//#region src/synth/soundfont/RiffChunk.ts
	/**
	* @internal
	*/
	var RiffChunk = class RiffChunk {
		static HeaderSize = 8;
		id = "";
		size = 0;
		static load(parent, chunk, stream) {
			if (parent && RiffChunk.HeaderSize > parent.size) return false;
			if (stream.position + RiffChunk.HeaderSize >= stream.length) return false;
			chunk.id = IOHelper.read8BitStringLength(stream, 4);
			if (chunk.id.charCodeAt(0) <= 32 || chunk.id.charCodeAt(0) >= 122) return false;
			chunk.size = IOHelper.readUInt32LE(stream);
			if (parent && RiffChunk.HeaderSize + chunk.size > parent.size) return false;
			if (parent) parent.size -= RiffChunk.HeaderSize + chunk.size;
			const isRiff = chunk.id === "RIFF";
			const isList = chunk.id === "LIST";
			if (isRiff && parent) return false;
			if (!isRiff && !isList) return true;
			chunk.id = IOHelper.read8BitStringLength(stream, 4);
			if (chunk.id.charCodeAt(0) <= 32 || chunk.id.charCodeAt(0) >= 122) return false;
			chunk.size -= 4;
			return true;
		}
	};
	//#endregion
	//#region src/synth/vorbis/OggReader.ts
	/**
	* @internal
	*/
	var OggPacket = class {
		packetData;
		isBeginningOfStream;
		isEndOfStream;
		granulePosition;
		constructor(data, isBeginOfStream, isEndOfStream, granulePosition) {
			this.packetData = data;
			this.isBeginningOfStream = isBeginOfStream;
			this.isEndOfStream = isEndOfStream;
			this.granulePosition = isEndOfStream ? granulePosition : null;
		}
		addData(newData) {
			const oldData = this.packetData;
			const newBuffer = new Uint8Array(oldData.length + newData.length);
			newBuffer.set(oldData, 0);
			newBuffer.set(newData, oldData.length);
		}
	};
	/**
	* @internal
	*/
	var OggReader = class {
		_readable;
		constructor(readable) {
			this._readable = readable;
		}
		read() {
			const packets = [];
			while (this._findAndReadPage(packets));
			return packets;
		}
		_findAndReadPage(packets) {
			if (!this._seekPageHeader()) return false;
			return this._readPage(packets);
		}
		_seekPageHeader() {
			for (let i = 0; i < 65536; i++) {
				if (IOHelper.readInt32LE(this._readable) === 1399285583) return true;
				this._readable.position -= 3;
			}
			return false;
		}
		_readPage(packets) {
			const version = this._readable.readByte();
			if (version === -1 || version !== 0) return false;
			const pageFlags = this._readable.readByte();
			const pageGranulePosition = IOHelper.readInt64LE(this._readable);
			this._readable.skip(4);
			this._readable.skip(4);
			this._readable.skip(4);
			const segmentCount = this._readable.readByte();
			if (segmentCount === -1) return false;
			const packetSizes = [];
			let packetIndex = 0;
			for (let i = 0; i < segmentCount; i++) {
				const size = this._readable.readByte();
				if (packetIndex === packetSizes.length) packetSizes.push(0);
				packetSizes[packetIndex] += size;
				if (size < 255) packetIndex++;
			}
			for (let i = 0; i < packetSizes.length; i++) {
				const packetData = new Uint8Array(packetSizes[i]);
				if (this._readable.read(packetData, 0, packetData.length) !== packetData.length) return false;
				if ((pageFlags & 1) !== 0) {
					if (packets.length === 0) throw new AlphaTabError(AlphaTabErrorType.Format, "OGG: Continuation page without any previous packets");
					packets[packets.length - 1].addData(packetData);
				} else {
					const packet = new OggPacket(packetData, (pageFlags & 2) !== 0 && i === 0, (pageFlags & 4) !== 0 && i === packetSizes.length - 1, pageGranulePosition);
					packets.push(packet);
				}
			}
			return true;
		}
	};
	//#endregion
	//#region src/synth/vorbis/VorbisStream.ts
	/**
	* @internal
	*/
	var VorbisStream = class {
		audioChannels = 0;
		audioSampleRate = 0;
		samples = new Float32Array(0);
		bitrateMaximum = 0;
		bitrateNominal = 0;
		bitrateMinimum = 0;
		blocksize0 = 0;
		blocksize1 = 0;
	};
	//#endregion
	//#region src/synth/vorbis/IntBitReader.ts
	/**
	* @internal
	*/
	var IntBitReaderReadResult = class {
		value = 0;
		bitsRead = 0;
	};
	/**
	* @internal
	*/
	var IntBitReader = class IntBitReader {
		static _byteSize = 8;
		_source;
		_bitBucket = 0n;
		_bitCount = 0n;
		_overflowBits = 0n;
		constructor(source) {
			this._source = source;
		}
		readByte() {
			return this.readBits(IntBitReader._byteSize);
		}
		readBit() {
			return this.readBits(1) === 1;
		}
		readBytes(count) {
			const bytes = new Uint8Array(count);
			for (let i = 0; i < count; i++) bytes[i] = this.readByte() & 255;
			return bytes;
		}
		readBits(count) {
			if (count === 0) return 0;
			const result = this.tryPeekBits(count);
			this.skipBits(count);
			return result.value;
		}
		tryPeekBits(count) {
			if (count < 0 || count > 32) throw new AlphaTabError(AlphaTabErrorType.General, "IO: Cannot read more than 32 bits in one go");
			if (count === 0) return new IntBitReaderReadResult();
			const result = new IntBitReaderReadResult();
			while (this._bitCount < count) {
				const val = BigInt(this._source.readByte());
				if (val === -1n) {
					result.bitsRead = Number(this._bitCount);
					result.value = Number(this._bitBucket);
					this._bitBucket = 0n;
					this._bitCount = 0n;
					return result;
				}
				this._bitBucket = (val & 255n) << this._bitCount | this._bitBucket;
				this._bitCount += 8n;
				if (this._bitCount > 32) this._overflowBits = val >> 40n - this._bitCount & 255n;
			}
			let bitBucket = this._bitBucket;
			if (count < 64) bitBucket = bitBucket & (1n << BigInt(count)) - 1n;
			result.value = Number(bitBucket);
			result.bitsRead = count;
			return result;
		}
		skipBits(count) {
			let bigCount = BigInt(count);
			if (count === 0) {} else if (this._bitCount > bigCount) {
				if (count > 31) this._bitBucket = 0n;
				else this._bitBucket = this._bitBucket >> bigCount;
				if (this._bitCount > 32) {
					const overflowCount = this._bitCount - 32n;
					this._bitBucket = this._bitBucket | this._overflowBits << this._bitCount - bigCount - overflowCount;
					if (overflowCount > count) this._overflowBits = this._overflowBits >> bigCount & 255n;
				}
				this._bitCount -= bigCount;
			} else if (this._bitCount === bigCount) {
				this._bitBucket = 0n;
				this._bitCount = 0n;
			} else {
				bigCount -= this._bitCount;
				this._bitCount = 0n;
				this._bitBucket = 0n;
				while (bigCount > 8) {
					if (this._source.readByte() === -1) {
						bigCount = 0n;
						break;
					}
					bigCount -= 8n;
				}
				if (bigCount > 0) {
					const temp = BigInt(this._source.readByte());
					if (temp === -1n) {} else {
						this._bitBucket = temp >> bigCount;
						this._bitCount = 8n - bigCount;
					}
				}
			}
		}
	};
	//#endregion
	//#region src/synth/vorbis/VorbisStreamDecoder.ts
	/**
	* @internal
	*/
	var VorbisSetupHeader = class {
		codebooks = [];
		timeDomainTransforms = [];
		floors = [];
		residues = [];
		mappings = [];
		modes = [];
	};
	/**
	* @internal
	*/
	var VorbisUtils = class {
		static ilog(x) {
			let cnt = 0;
			while (x > 0) {
				++cnt;
				x >>= 1;
			}
			return cnt;
		}
		static bitReverse(on, bits = 32) {
			let bn = BigInt(on);
			bn = (bn & BigInt(2863311530)) >> 1n | (bn & BigInt(1431655765)) << 1n;
			bn = (bn & BigInt(3435973836)) >> 2n | (bn & BigInt(858993459)) << 2n;
			bn = (bn & BigInt(4042322160)) >> 4n | (bn & BigInt(252645135)) << 4n;
			bn = (bn & BigInt(4278255360)) >> 8n | (bn & BigInt(16711935)) << 8n;
			bn = (bn >> 16n | bn << 16n) >> 32n - BigInt(bits);
			return Number(BigInt.asUintN(32, bn));
		}
		static convertFromVorbisFloat32(bits) {
			const big = BigInt(bits);
			let bmantissa = big & BigInt(2097151);
			const bsign = big & BigInt(2147483648);
			const bexponent = (big & BigInt(2145386496)) >> 21n;
			if (bsign !== 0n) bmantissa = -bmantissa;
			return Number(bmantissa) * Math.pow(2, Number(bexponent) - 788);
		}
	};
	/**
	* @internal
	*/
	var FastListArray = class {
		_data;
		constructor(data) {
			this._data = data;
		}
		get(index) {
			return this._data[index];
		}
	};
	/**
	* @internal
	*/
	var FastRange = class FastRange {
		static instance = new FastRange();
		get(index) {
			return index;
		}
	};
	/**
	* @internal
	*/
	var VorbisCodebook = class {
		_lengths;
		_maxBits = 0;
		_overflowList = null;
		_prefixList = null;
		_prefixBitLength = 0;
		_lookupTable;
		dimensions = 0;
		entries = 0;
		mapType = 0;
		constructor(packet, huffman) {
			if (packet.readBits(24) !== 5653314) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Book header had invalid signature!");
			this.dimensions = packet.readBits(16);
			this.entries = packet.readBits(24);
			this._lengths = new Int32Array(this.entries);
			this._initTree(packet, huffman);
			this._initLookupTable(packet);
		}
		get(entry, dim) {
			return this._lookupTable[entry * this.dimensions + dim];
		}
		decodeScalar(packet) {
			let data = packet.tryPeekBits(this._prefixBitLength);
			if (data.bitsRead === 0) return -1;
			let node = this._prefixList[data.value];
			if (node != null) {
				packet.skipBits(node.length);
				return node.value;
			}
			data = packet.tryPeekBits(this._maxBits);
			if (this._overflowList !== null) for (let i = 0; i < this._overflowList.length; i++) {
				node = this._overflowList[i];
				const bits = data.value & node.mask;
				if (node.bits === bits) {
					packet.skipBits(node.length);
					return node.value;
				}
			}
			return -1;
		}
		_initTree(packet, huffman) {
			let sparse;
			let total = 0;
			let maxLen;
			if (packet.readBit()) {
				let len = packet.readBits(5) + 1;
				for (let i = 0; i < this.entries;) {
					let cnt = packet.readBits(VorbisUtils.ilog(this.entries - i));
					while (--cnt >= 0) this._lengths[i++] = len;
					++len;
				}
				total = 0;
				sparse = false;
				maxLen = len;
			} else {
				maxLen = -1;
				sparse = packet.readBit();
				for (let i = 0; i < this.entries; i++) {
					if (!sparse || packet.readBit()) {
						this._lengths[i] = packet.readBits(5) + 1;
						++total;
					} else this._lengths[i] = -1;
					if (this._lengths[i] > maxLen) maxLen = this._lengths[i];
				}
			}
			this._maxBits = maxLen;
			if (maxLen > -1) {
				let codewordLengths = null;
				if (sparse && total >= this.entries >> 2) {
					codewordLengths = new Int32Array(this.entries);
					codewordLengths.set(this._lengths.subarray(0, this.entries), 0);
					sparse = false;
				}
				let sortedCount;
				if (sparse) sortedCount = total;
				else sortedCount = 0;
				let values = null;
				let codewords = null;
				if (!sparse) codewords = new Int32Array(this.entries);
				else if (sortedCount !== 0) {
					codewordLengths = new Int32Array(sortedCount);
					codewords = new Int32Array(sortedCount);
					values = new Int32Array(sortedCount);
				}
				if (!this._computeCodewords(sparse, codewords, codewordLengths, this._lengths, this.entries, values)) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Failed to compute codewords");
				const valueList = values == null ? FastRange.instance : new FastListArray(values);
				huffman.generateTable(valueList, codewordLengths ?? this._lengths, codewords);
				this._prefixList = huffman.prefixTree;
				this._prefixBitLength = huffman.tableBits;
				this._overflowList = huffman.overflowList;
			}
		}
		_computeCodewords(sparse, codewords, codewordLengths, len, n, values) {
			const available = new Uint32Array(32);
			let k = 0;
			let m = 0;
			for (k = 0; k < n; ++k) if (len[k] > 0) break;
			if (k === n) return true;
			this._addEntry(sparse, codewords, codewordLengths, 0, k, m++, len[k], values);
			for (let i = 1; i <= len[k]; ++i) available[i] = 1 << 32 - i;
			for (let i = k + 1; i < n; ++i) {
				let z = len[i];
				if (z <= 0) continue;
				while (z > 0 && available[z] === 0) --z;
				if (z === 0) return false;
				const res = available[z];
				available[z] = 0;
				this._addEntry(sparse, codewords, codewordLengths, VorbisUtils.bitReverse(res), i, m++, len[i], values);
				if (z !== len[i]) for (let y = len[i]; y > z; --y) available[y] = res + (1 << 32 - y);
			}
			return true;
		}
		_addEntry(sparse, codewords, codewordLengths, huffCode, symbol, count, len, values) {
			if (sparse) {
				codewords[count] = huffCode;
				codewordLengths[count] = len;
				values[count] = symbol;
			} else codewords[symbol] = huffCode;
		}
		_initLookupTable(packet) {
			this.mapType = packet.readBits(4);
			if (this.mapType === 0) return;
			const minValue = VorbisUtils.convertFromVorbisFloat32(packet.readBits(32));
			const deltaValue = VorbisUtils.convertFromVorbisFloat32(packet.readBits(32));
			const valueBits = packet.readBits(4) + 1;
			const sequenceP = packet.readBit();
			let lookupValueCount = this.entries * this.dimensions;
			const lookupTable = new Float32Array(lookupValueCount);
			if (this.mapType === 1) lookupValueCount = this._lookup1Values();
			const multiplicands = new Uint32Array(lookupValueCount);
			for (let i = 0; i < lookupValueCount; i++) multiplicands[i] = packet.readBits(valueBits);
			if (this.mapType === 1) for (let idx = 0; idx < this.entries; idx++) {
				let last = 0;
				let idxDiv = 1;
				for (let i = 0; i < this.dimensions; i++) {
					const value = multiplicands[idx / idxDiv % lookupValueCount | 0] * deltaValue + minValue + last;
					lookupTable[idx * this.dimensions + i] = value;
					if (sequenceP) last = value;
					idxDiv *= lookupValueCount;
				}
			}
			else for (let idx = 0; idx < this.entries; idx++) {
				let last = 0;
				let moff = idx * this.dimensions;
				for (let i = 0; i < this.dimensions; i++) {
					const value = multiplicands[moff] * deltaValue + minValue + last;
					lookupTable[idx * this.dimensions + i] = value;
					if (sequenceP) last = value;
					++moff;
				}
			}
			this._lookupTable = lookupTable;
		}
		_lookup1Values() {
			let r = Math.floor(Math.exp(Math.log(this.entries) / this.dimensions));
			if (Math.floor(Math.pow(r + 1, this.dimensions)) <= this.entries) ++r;
			return r;
		}
	};
	/**
	* @internal
	*/
	var HuffmanListNode = class {
		value = 0;
		length = 0;
		bits = 0;
		mask = 0;
	};
	/**
	* @internal
	*/
	var Huffman = class Huffman {
		static maxTableBits = 10;
		tableBits = 0;
		prefixTree = [];
		overflowList = null;
		generateTable(values, lengthList, codeList) {
			const list = new Array(lengthList.length);
			let maxLen = 0;
			for (let i = 0; i < list.length; i++) {
				const node = new HuffmanListNode();
				node.value = values.get(i);
				node.length = lengthList[i] <= 0 ? 99999 : lengthList[i];
				node.bits = codeList[i];
				node.mask = (1 << lengthList[i]) - 1;
				list[i] = node;
				if (lengthList[i] > 0 && maxLen < lengthList[i]) maxLen = lengthList[i];
			}
			list.sort((a, b) => {
				const len = a.length - b.length;
				if (len === 0) return a.bits - b.bits;
				return len;
			});
			const tableBits = maxLen > Huffman.maxTableBits ? Huffman.maxTableBits : maxLen;
			const prefixList = [];
			let overflowList = null;
			for (let i = 0; i < list.length && list[i].length < 99999; i++) {
				const itemBits = list[i].length;
				if (itemBits > tableBits) {
					overflowList = [];
					for (; i < list.length && list[i].length < 99999; i++) overflowList.push(list[i]);
				} else {
					const maxVal = 1 << tableBits - itemBits;
					const item = list[i];
					for (let j = 0; j < maxVal; j++) {
						const idx = j << itemBits | item.bits;
						while (prefixList.length <= idx) prefixList.push(null);
						prefixList[idx] = item;
					}
				}
			}
			while (prefixList.length < 1 << tableBits) prefixList.push(null);
			this.tableBits = tableBits;
			this.prefixTree = prefixList;
			this.overflowList = overflowList;
		}
	};
	/**
	* @internal
	*/
	var VorbisTimeDomainTransform = class {
		constructor(packet) {
			packet.readBits(16);
		}
	};
	/**
	* @internal
	*/
	var VorbisFloorData0 = class {
		coeff;
		amp = 0;
		get executeChannel() {
			return (this.forceEnergy || this.amp > 0) && !this.forceNoEnergy;
		}
		forceEnergy = false;
		forceNoEnergy = false;
		constructor(coeff) {
			this.coeff = coeff;
		}
	};
	/**
	* @internal
	*/
	var VorbisFloor0 = class VorbisFloor0 {
		_order;
		_rate;
		_barkMapSize;
		_ampBits;
		_ampOfs;
		_ampDiv;
		_books;
		_bookBits;
		_wMap;
		_barkMaps;
		constructor(packet, block0Size, block1Size, codebooks) {
			this._order = packet.readBits(8);
			this._rate = packet.readBits(16);
			this._barkMapSize = packet.readBits(16);
			this._ampBits = packet.readBits(6);
			this._ampOfs = packet.readBits(8);
			this._books = new Array(packet.readBits(4) + 1);
			if (this._order < 1 || this._rate < 1 || this._barkMapSize < 1 || this._books.length === 0) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid Floor0 Data");
			this._ampDiv = (1 << this._ampBits) - 1;
			for (let i = 0; i < this._books.length; i++) {
				const num = packet.readBits(8);
				if (num < 0 || num >= codebooks.length) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid Floor0 Data");
				const book = codebooks[num];
				if (book.mapType === 0 || book.dimensions < 1) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid Floor0 Data");
				this._books[i] = book;
			}
			this._bookBits = VorbisUtils.ilog(this._books.length);
			this._barkMaps = new Map([[block0Size, this._synthesizeBarkCurve(block0Size / 2)], [block1Size, this._synthesizeBarkCurve(block1Size / 2)]]);
			this._wMap = new Map([[block0Size, this._synthesizeWDelMap(block0Size / 2)], [block1Size, this._synthesizeWDelMap(block1Size / 2)]]);
		}
		_synthesizeBarkCurve(n) {
			const scale = this._barkMapSize / VorbisFloor0._toBARK(this._rate / 2);
			const map = new Int32Array(n + 1);
			for (let i = 0; i < n - 1; i++) map[i] = Math.min(this._barkMapSize - 1, Math.floor(VorbisFloor0._toBARK(this._rate / 2 / n * i) * scale));
			map[n] = -1;
			return map;
		}
		static _toBARK(lsp) {
			return 13.1 * Math.atan(74e-5 * lsp) + 2.24 * Math.atan(1.85e-8 * lsp * lsp) + 1e-4 * lsp;
		}
		_synthesizeWDelMap(n) {
			const wdel = Math.PI / this._barkMapSize;
			const map = new Float32Array(n);
			for (let i = 0; i < n; i++) map[i] = 2 * Math.cos(wdel * i);
			return map;
		}
		unpack(packet, _blockSize, _channel) {
			const data = new VorbisFloorData0(new Float32Array(this._order + 1));
			data.amp = packet.readBits(this._ampBits);
			if (data.amp > 0) {
				data.amp = data.amp / this._ampDiv * this._ampOfs;
				const bookNum = packet.readBits(this._bookBits);
				if (bookNum >= this._books.length) {
					data.amp = 0;
					return data;
				}
				const book = this._books[bookNum];
				for (let i = 0; i < this._order;) {
					const entry = book.decodeScalar(packet);
					if (entry === -1) {
						data.amp = 0;
						return data;
					}
					for (let j = 0; i < this._order && j < book.dimensions; j++, i++) data.coeff[i] = book.get(entry, j);
				}
				let last = 0;
				for (let j = 0; j < this._order;) {
					for (let k = 0; j < this._order && k < book.dimensions; j++, k++) data.coeff[j] += last;
					last = data.coeff[j - 1];
				}
			}
			return data;
		}
		apply(floorData, blockSize, residue) {
			const data = floorData;
			const n = blockSize / 2;
			if (data.amp > 0) {
				const barkMap = this._barkMaps.get(blockSize);
				const wMap = this._wMap.get(blockSize);
				let i = 0;
				for (i = 0; i < this._order; i++) data.coeff[i] = 2 * Math.cos(data.coeff[i]);
				i = 0;
				while (i < n) {
					let j = 0;
					const k = barkMap[i];
					let p = .5;
					let q = .5;
					const w = wMap[k];
					for (j = 1; j < this._order; j += 2) {
						q *= w - data.coeff[j - 1];
						p *= w - data.coeff[j];
					}
					if (j === this._order) {
						q *= w - data.coeff[j - 1];
						p *= p * (4 - w * w);
						q *= q;
					} else {
						p *= p * (2 - w);
						q *= q * (2 + w);
					}
					q = data.amp / Math.sqrt(p + q) - this._ampOfs;
					q = Math.exp(q * .11512925);
					residue[i] *= q;
					while (barkMap[++i] === k) residue[i] *= q;
				}
			} else residue.fill(0, 0, n);
		}
	};
	/**
	* @internal
	*/
	var VorbisFloor1Data = class {
		posts = new Int32Array(64);
		postCount = 0;
		get executeChannel() {
			return (this.forceEnergy || this.postCount > 0) && !this.forceNoEnergy;
		}
		forceEnergy = false;
		forceNoEnergy = false;
	};
	/**
	* @internal
	*/
	var VorbisFloor1 = class VorbisFloor1 {
		static _rangeLookup = [
			256,
			128,
			86,
			64
		];
		static _yBitsLookup = [
			8,
			7,
			7,
			6
		];
		_partitionClass;
		_classDimensions;
		_classSubclasses;
		_xList;
		_classMasterBookIndex;
		_hNeigh;
		_lNeigh;
		_sortIdx;
		_multiplier;
		_range;
		_yBits;
		_classMasterbooks;
		_subclassBooks;
		_subclassBookIndex;
		constructor(packet, codebooks) {
			let maximumClass = -1;
			this._partitionClass = new Int32Array(packet.readBits(5));
			for (let i = 0; i < this._partitionClass.length; i++) {
				this._partitionClass[i] = packet.readBits(4);
				if (this._partitionClass[i] > maximumClass) maximumClass = this._partitionClass[i];
			}
			++maximumClass;
			this._classDimensions = new Int32Array(maximumClass);
			this._classSubclasses = new Int32Array(maximumClass);
			this._classMasterbooks = new Array(maximumClass);
			this._classMasterBookIndex = new Int32Array(maximumClass);
			this._subclassBooks = new Array(maximumClass);
			this._subclassBookIndex = new Array(maximumClass);
			for (let i = 0; i < maximumClass; i++) {
				this._classDimensions[i] = packet.readBits(3) + 1;
				this._classSubclasses[i] = packet.readBits(2);
				if (this._classSubclasses[i] > 0) {
					this._classMasterBookIndex[i] = packet.readBits(8);
					this._classMasterbooks[i] = codebooks[this._classMasterBookIndex[i]];
				}
				this._subclassBooks[i] = new Array(1 << this._classSubclasses[i]);
				this._subclassBookIndex[i] = new Int32Array(this._subclassBooks[i].length);
				for (let j = 0; j < this._subclassBooks[i].length; j++) {
					const bookNum = packet.readBits(8) - 1;
					if (bookNum >= 0) this._subclassBooks[i][j] = codebooks[bookNum];
					this._subclassBookIndex[i][j] = bookNum;
				}
			}
			this._multiplier = packet.readBits(2);
			this._range = VorbisFloor1._rangeLookup[this._multiplier];
			this._yBits = VorbisFloor1._yBitsLookup[this._multiplier];
			++this._multiplier;
			const rangeBits = packet.readBits(4);
			const xList = [];
			xList.push(0);
			xList.push(1 << rangeBits);
			for (let i = 0; i < this._partitionClass.length; i++) {
				const classNum = this._partitionClass[i];
				for (let j = 0; j < this._classDimensions[classNum]; j++) xList.push(packet.readBits(rangeBits));
			}
			this._xList = new Int32Array(xList);
			this._lNeigh = new Int32Array(xList.length);
			this._hNeigh = new Int32Array(xList.length);
			this._sortIdx = new Int32Array(xList.length);
			this._sortIdx[0] = 0;
			this._sortIdx[1] = 1;
			for (let i = 2; i < this._lNeigh.length; i++) {
				this._lNeigh[i] = 0;
				this._hNeigh[i] = 1;
				this._sortIdx[i] = i;
				for (let j = 2; j < i; j++) {
					const temp = this._xList[j];
					if (temp < this._xList[i]) {
						if (temp > this._xList[this._lNeigh[i]]) this._lNeigh[i] = j;
					} else if (temp < this._xList[this._hNeigh[i]]) this._hNeigh[i] = j;
				}
			}
			for (let i = 0; i < this._sortIdx.length - 1; i++) for (let j = i + 1; j < this._sortIdx.length; j++) {
				if (this._xList[i] === this._xList[j]) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid Floor1 Data");
				if (this._xList[this._sortIdx[i]] > this._xList[this._sortIdx[j]]) {
					const temp = this._sortIdx[i];
					this._sortIdx[i] = this._sortIdx[j];
					this._sortIdx[j] = temp;
				}
			}
		}
		unpack(packet, _blockSize, _channel) {
			const data = new VorbisFloor1Data();
			if (packet.readBit()) {
				let postCount = 2;
				data.posts[0] = packet.readBits(this._yBits);
				data.posts[1] = packet.readBits(this._yBits);
				for (let i = 0; i < this._partitionClass.length; i++) {
					const clsNum = this._partitionClass[i];
					const cdim = this._classDimensions[clsNum];
					const cbits = this._classSubclasses[clsNum];
					const csub = (1 << cbits) - 1;
					let cval = 0;
					if (cbits > 0) {
						cval = this._classMasterbooks[clsNum].decodeScalar(packet);
						if (cval === -1) {
							postCount = 0;
							break;
						}
					}
					for (let j = 0; j < cdim; j++) {
						const book = this._subclassBooks[clsNum][cval & csub];
						cval = cval >> cbits;
						if (book != null) {
							data.posts[postCount] = book.decodeScalar(packet);
							if (data.posts[postCount] === -1) {
								postCount = 0;
								i = this._partitionClass.length;
								break;
							}
						}
						++postCount;
					}
				}
				data.postCount = postCount;
			}
			return data;
		}
		apply(floorData, blockSize, residue) {
			const data = floorData;
			const n = blockSize / 2;
			if (data.postCount > 0) {
				const stepFlags = this._unwrapPosts(data);
				let lx = 0;
				let ly = data.posts[0] * this._multiplier;
				for (let i = 1; i < data.postCount; i++) {
					const idx = this._sortIdx[i];
					if (stepFlags[idx]) {
						const hx = this._xList[idx];
						const hy = data.posts[idx] * this._multiplier;
						if (lx < n) this._renderLineMulti(lx, ly, Math.min(hx, n), hy, residue);
						lx = hx;
						ly = hy;
					}
					if (lx >= n) break;
				}
				if (lx < n) this._renderLineMulti(lx, ly, n, ly, residue);
			} else residue.fill(0, 0, n);
		}
		_unwrapPosts(data) {
			const stepFlags = new Array(64);
			stepFlags.fill(false);
			stepFlags[0] = true;
			stepFlags[1] = true;
			const finalY = new Int32Array(64);
			finalY[0] = data.posts[0];
			finalY[1] = data.posts[1];
			for (let i = 2; i < data.postCount; i++) {
				const lowOfs = this._lNeigh[i];
				const highOfs = this._hNeigh[i];
				const predicted = this._renderPoint(this._xList[lowOfs], finalY[lowOfs], this._xList[highOfs], finalY[highOfs], this._xList[i]);
				const val = data.posts[i];
				const highroom = this._range - predicted;
				const lowroom = predicted;
				let room;
				if (highroom < lowroom) room = highroom * 2;
				else room = lowroom * 2;
				if (val !== 0) {
					stepFlags[lowOfs] = true;
					stepFlags[highOfs] = true;
					stepFlags[i] = true;
					if (val >= room) if (highroom > lowroom) finalY[i] = val - lowroom + predicted;
					else finalY[i] = predicted - val + highroom - 1;
					else if (val % 2 === 1) finalY[i] = predicted - (val + 1) / 2;
					else finalY[i] = predicted + val / 2;
				} else {
					stepFlags[i] = false;
					finalY[i] = predicted;
				}
			}
			for (let i = 0; i < data.postCount; i++) data.posts[i] = finalY[i];
			return stepFlags;
		}
		_renderPoint(x0, y0, x1, y1, X) {
			const dy = y1 - y0;
			const adx = x1 - x0;
			const off = Math.abs(dy) * (X - x0) / adx | 0;
			if (dy < 0) return y0 - off;
			return y0 + off;
		}
		_renderLineMulti(x0, y0, x1, y1, v) {
			const dy = y1 - y0;
			const adx = x1 - x0;
			let ady = Math.abs(dy);
			const sy = 1 - (dy >> 31 & 1) * 2;
			const b = dy / adx | 0;
			let x = x0;
			let y = y0;
			let err = -adx;
			v[x0] *= VorbisFloor1._inverseDbTable[y0];
			ady -= Math.abs(b) * adx;
			while (++x < x1) {
				y += b;
				err += ady;
				if (err >= 0) {
					err -= adx;
					y += sy;
				}
				v[x] *= VorbisFloor1._inverseDbTable[y];
			}
		}
		static _inverseDbTable = new Float32Array([
			1.0649863e-7,
			1.1341951e-7,
			1.2079015e-7,
			1.2863978e-7,
			1.3699951e-7,
			1.4590251e-7,
			1.5538408e-7,
			1.6548181e-7,
			1.7623575e-7,
			1.8768855e-7,
			1.9988561e-7,
			2.128753e-7,
			2.2670913e-7,
			2.4144197e-7,
			2.5713223e-7,
			2.7384213e-7,
			2.9163793e-7,
			3.1059021e-7,
			3.3077411e-7,
			3.5226968e-7,
			3.7516214e-7,
			3.9954229e-7,
			4.255068e-7,
			4.5315863e-7,
			4.8260743e-7,
			5.1396998e-7,
			5.4737065e-7,
			5.8294187e-7,
			6.2082472e-7,
			6.6116941e-7,
			7.0413592e-7,
			7.4989464e-7,
			7.9862701e-7,
			8.505263e-7,
			9.0579828e-7,
			9.6466216e-7,
			10273513e-13,
			10941144e-13,
			11652161e-13,
			12409384e-13,
			13215816e-13,
			14074654e-13,
			14989305e-13,
			15963394e-13,
			17000785e-13,
			18105592e-13,
			19282195e-13,
			20535261e-13,
			21869758e-13,
			23290978e-13,
			24804557e-13,
			26416497e-13,
			2813319e-12,
			29961443e-13,
			31908506e-13,
			33982101e-13,
			36190449e-13,
			38542308e-13,
			41047004e-13,
			4371447e-12,
			46555282e-13,
			49580707e-13,
			5280274e-12,
			5623416e-12,
			59888572e-13,
			63780469e-13,
			67925283e-13,
			72339451e-13,
			77040476e-13,
			82047e-10,
			87378876e-13,
			93057248e-13,
			99104632e-13,
			10554501e-12,
			11240392e-12,
			11970856e-12,
			12748789e-12,
			13577278e-12,
			14459606e-12,
			15399272e-12,
			16400004e-12,
			17465768e-12,
			18600792e-12,
			19809576e-12,
			21096914e-12,
			22467911e-12,
			23928002e-12,
			25482978e-12,
			27139006e-12,
			28902651e-12,
			30780908e-12,
			32781225e-12,
			34911534e-12,
			37180282e-12,
			39596466e-12,
			42169667e-12,
			4491009e-11,
			47828601e-12,
			50936773e-12,
			54246931e-12,
			57772202e-12,
			61526565e-12,
			65524908e-12,
			69783085e-12,
			74317983e-12,
			79147585e-12,
			8429104e-11,
			89768747e-12,
			95602426e-12,
			.00010181521,
			.00010843174,
			.00011547824,
			.00012298267,
			.00013097477,
			.00013948625,
			.00014855085,
			.00015820453,
			.00016848555,
			.00017943469,
			.00019109536,
			.00020351382,
			.00021673929,
			.00023082423,
			.00024582449,
			.00026179955,
			.00027881276,
			.00029693158,
			.00031622787,
			.00033677814,
			.00035866388,
			.00038197188,
			.00040679456,
			.00043323036,
			.00046138411,
			.00049136745,
			.00052329927,
			.00055730621,
			.00059352311,
			.00063209358,
			.00067317058,
			716917e-9,
			.0007635063,
			.00081312324,
			.00086596457,
			.00092223983,
			.00098217216,
			.0010459992,
			.0011139742,
			.0011863665,
			.0012634633,
			.0013455702,
			.0014330129,
			.0015261382,
			.0016253153,
			.0017309374,
			.0018434235,
			.0019632195,
			.0020908006,
			.0022266726,
			.0023713743,
			.0025254795,
			.0026895994,
			.0028643847,
			.0030505286,
			.0032487691,
			.0034598925,
			.0036847358,
			.0039241906,
			.0041792066,
			.004450795,
			.0047400328,
			.0050480668,
			.0053761186,
			.0057254891,
			.0060975636,
			.0064938176,
			.0069158225,
			.0073652516,
			.0078438871,
			.0083536271,
			.0088964928,
			.009474637,
			.010090352,
			.01074608,
			.011444421,
			.012188144,
			.012980198,
			.013823725,
			.014722068,
			.015678791,
			.016697687,
			.017782797,
			.018938423,
			.020169149,
			.021479854,
			.022875735,
			.02436233,
			.025945531,
			.027631618,
			.029427276,
			.031339626,
			.033376252,
			.035545228,
			.037855157,
			.040315199,
			.042935108,
			.045725273,
			.048696758,
			.051861348,
			.055231591,
			.05882085,
			.062643361,
			.066714279,
			.071049749,
			.075666962,
			.080584227,
			.085821044,
			.091398179,
			.097337747,
			.1036633,
			.11039993,
			.11757434,
			.12521498,
			.13335215,
			.14201813,
			.15124727,
			.16107617,
			.1715438,
			.18269168,
			.19456402,
			.20720788,
			.22067342,
			.23501402,
			.25028656,
			.26655159,
			.28387361,
			.30232132,
			.32196786,
			.34289114,
			.36517414,
			.38890521,
			.41417847,
			.44109412,
			.4697589,
			.50028648,
			.53279791,
			.56742212,
			.6042964,
			.64356699,
			.68538959,
			.72993007,
			.77736504,
			.8278826,
			.88168307,
			.9389798,
			1
		]);
	};
	/**
	* @internal
	*/
	var VorbisFloor = class {
		floor;
		constructor(packet, block0Size, block1Size, codebooks) {
			const type = packet.readBits(16);
			switch (type) {
				case 0:
					this.floor = new VorbisFloor0(packet, block0Size, block1Size, codebooks);
					break;
				case 1:
					this.floor = new VorbisFloor1(packet, codebooks);
					break;
				default: throw new AlphaTabError(AlphaTabErrorType.Format, `Vorbis: Invalid Floor type: ${type}`);
			}
		}
		apply(floorData, blockSize, residue) {
			this.floor.apply(floorData, blockSize, residue);
		}
		unpack(packet, blockSize, channel) {
			return this.floor.unpack(packet, blockSize, channel);
		}
	};
	/**
	* @internal
	*/
	var VorbisResidue0 = class VorbisResidue0 {
		_channels;
		_begin;
		_end;
		_partitionSize;
		_classifications;
		_maxStages;
		_books;
		_classBook;
		_cascade;
		_decodeMap;
		constructor(packet, channels, codebooks) {
			this._begin = packet.readBits(24);
			this._end = packet.readBits(24);
			this._partitionSize = packet.readBits(24) + 1;
			this._classifications = packet.readBits(6) + 1;
			this._classBook = codebooks[packet.readBits(8)];
			this._cascade = new Int32Array(this._classifications);
			let acc = 0;
			for (let i = 0; i < this._classifications; i++) {
				const lowBits = packet.readBits(3);
				if (packet.readBit()) this._cascade[i] = packet.readBits(5) << 3 | lowBits;
				else this._cascade[i] = lowBits;
				acc += VorbisResidue0._icount(this._cascade[i]);
			}
			const bookNums = new Int32Array(acc);
			for (let i = 0; i < acc; i++) {
				bookNums[i] = packet.readBits(8);
				if (codebooks[bookNums[i]].mapType === 0) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid Residue 0");
			}
			const entries = this._classBook.entries;
			let dim = this._classBook.dimensions;
			let partvals = 1;
			while (dim > 0) {
				partvals *= this._classifications;
				if (partvals > entries) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid Residue 0");
				--dim;
			}
			this._books = new Array(this._classifications);
			acc = 0;
			let maxstage = 0;
			let stages;
			for (let j = 0; j < this._classifications; j++) {
				stages = VorbisUtils.ilog(this._cascade[j]);
				this._books[j] = new Array(stages);
				if (stages > 0) {
					maxstage = Math.max(maxstage, stages);
					for (let k = 0; k < stages; k++) if ((this._cascade[j] & 1 << k) > 0) this._books[j][k] = codebooks[bookNums[acc++]];
				}
			}
			this._maxStages = maxstage;
			this._decodeMap = new Array(partvals);
			for (let j = 0; j < partvals; j++) {
				let val = j;
				let mult = partvals / this._classifications | 0;
				this._decodeMap[j] = new Int32Array(this._classBook.dimensions);
				for (let k = 0; k < this._classBook.dimensions; k++) {
					const deco = val / mult | 0;
					val -= deco * mult;
					mult = mult / this._classifications | 0;
					this._decodeMap[j][k] = deco;
				}
			}
			this._channels = channels;
		}
		static _icount(v) {
			let ret = 0;
			while (v !== 0) {
				ret += v & 1;
				v >>= 1;
			}
			return ret;
		}
		decode(packet, doNotDecodeChannel, blockSize, buffer) {
			const n = (this._end < blockSize / 2 ? this._end : blockSize / 2) - this._begin;
			if (n > 0 && doNotDecodeChannel.indexOf(false) !== -1) {
				const partitionCount = n / this._partitionSize;
				const partitionWords = (partitionCount + this._classBook.dimensions - 1) / this._classBook.dimensions | 0;
				const partWordCache = [];
				for (let i = 0; i < this._channels; i++) partWordCache.push(new Array(partitionWords));
				for (let stage = 0; stage < this._maxStages; stage++) for (let partitionIdx = 0, entryIdx = 0; partitionIdx < partitionCount; entryIdx++) {
					if (stage === 0) for (let ch = 0; ch < this._channels; ch++) {
						const idx = this._classBook.decodeScalar(packet);
						if (idx >= 0 && idx < this._decodeMap.length) partWordCache[ch][entryIdx] = this._decodeMap[idx];
						else {
							partitionIdx = partitionCount;
							stage = this._maxStages;
							break;
						}
					}
					for (let dimensionIdx = 0; partitionIdx < partitionCount && dimensionIdx < this._classBook.dimensions; dimensionIdx++, partitionIdx++) {
						const offset = this._begin + partitionIdx * this._partitionSize;
						for (let ch = 0; ch < this._channels; ch++) {
							const idx = partWordCache[ch][entryIdx][dimensionIdx];
							if ((this._cascade[idx] & 1 << stage) !== 0) {
								const book = this._books[idx][stage];
								if (book) {
									if (this.writeVectors(book, packet, buffer, ch, offset, this._partitionSize)) {
										partitionIdx = partitionCount;
										stage = this._maxStages;
										break;
									}
								}
							}
						}
					}
				}
			}
		}
		writeVectors(codebook, packet, residue, channel, offset, partitionSize) {
			const res = residue[channel];
			const steps = partitionSize / codebook.dimensions;
			const entryCache = new Int32Array(steps);
			for (let i = 0; i < steps; i++) {
				entryCache[i] = codebook.decodeScalar(packet);
				if (entryCache[i] === -1) return true;
			}
			for (let dim = 0; dim < codebook.dimensions; dim++) for (let step = 0; step < steps; step++, offset++) res[offset] += codebook.get(entryCache[step], dim);
			return false;
		}
	};
	/**
	* @internal
	*/
	var VorbisResidue1 = class extends VorbisResidue0 {
		writeVectors(codebook, packet, residue, channel, offset, partitionSize) {
			const res = residue[channel];
			for (let i = 0; i < partitionSize;) {
				const entry = codebook.decodeScalar(packet);
				if (entry === -1) return true;
				for (let j = 0; j < codebook.dimensions; i++, j++) res[offset + i] += codebook.get(entry, j);
			}
			return false;
		}
	};
	/**
	* @internal
	*/
	var VorbisResidue2 = class extends VorbisResidue0 {
		_realChannels;
		constructor(packet, channels, codebooks) {
			super(packet, 1, codebooks);
			this._realChannels = channels;
		}
		decode(packet, doNotDecodeChannel, blockSize, buffer) {
			super.decode(packet, doNotDecodeChannel, blockSize * this._realChannels, buffer);
		}
		writeVectors(codebook, packet, residue, _channel, offset, partitionSize) {
			let chPtr = 0;
			offset /= this._realChannels;
			for (let c = 0; c < partitionSize;) {
				const entry = codebook.decodeScalar(packet);
				if (entry === -1) return true;
				for (let d = 0; d < codebook.dimensions; d++, c++) {
					residue[chPtr][offset] += codebook.get(entry, d);
					if (++chPtr === this._realChannels) {
						chPtr = 0;
						offset++;
					}
				}
			}
			return false;
		}
	};
	/**
	* @internal
	*/
	var VorbisResidue = class {
		residue;
		constructor(packet, channels, codebooks) {
			const type = packet.readBits(16);
			switch (type) {
				case 0:
					this.residue = new VorbisResidue0(packet, channels, codebooks);
					break;
				case 1:
					this.residue = new VorbisResidue1(packet, channels, codebooks);
					break;
				case 2:
					this.residue = new VorbisResidue2(packet, channels, codebooks);
					break;
				default: throw new AlphaTabError(AlphaTabErrorType.Format, `Vorbis: Invalid Residue type: ${type}`);
			}
		}
		decode(packet, doNotDecodeChannel, blockSize, buffer) {
			this.residue.decode(packet, doNotDecodeChannel, blockSize, buffer);
		}
	};
	/**
	* @internal
	*/
	var VorbisMapping = class {
		_mdct;
		_couplingAngle;
		_couplingMangitude;
		_submapFloor;
		_submapResidue;
		_channelFloor;
		_channelResidue;
		constructor(packet, channels, floors, residues, mdct) {
			if (packet.readBits(16) !== 0) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid mapping type!");
			let submapCount = 1;
			if (packet.readBit()) submapCount += packet.readBits(4);
			let couplingSteps = 0;
			if (packet.readBit()) couplingSteps = packet.readBits(8) + 1;
			const couplingBits = VorbisUtils.ilog(channels - 1);
			this._couplingAngle = new Int32Array(couplingSteps);
			this._couplingMangitude = new Int32Array(couplingSteps);
			for (let j = 0; j < couplingSteps; j++) {
				const magnitude = packet.readBits(couplingBits);
				const angle = packet.readBits(couplingBits);
				if (magnitude === angle || magnitude > channels - 1 || angle > channels - 1) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid magnitude or angle in mapping header!");
				this._couplingAngle[j] = angle;
				this._couplingMangitude[j] = magnitude;
			}
			if (packet.readBits(2) !== 0) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Reserved bits not 0 in mapping header.");
			const mux = new Int32Array(channels);
			if (submapCount > 1) for (let c = 0; c < channels; c++) {
				mux[c] = packet.readBits(4);
				if (mux[c] > submapCount) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid channel mux submap index in mapping header!");
			}
			this._submapFloor = new Array(submapCount);
			this._submapResidue = new Array(submapCount);
			for (let j = 0; j < submapCount; j++) {
				packet.skipBits(8);
				const floorNum = packet.readBits(8);
				if (floorNum >= floors.length) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid floor number in mapping header!");
				const residueNum = packet.readBits(8);
				if (residueNum >= residues.length) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Invalid residue number in mapping header!");
				this._submapFloor[j] = floors[floorNum];
				this._submapResidue[j] = residues[residueNum];
			}
			this._channelFloor = new Array(channels);
			this._channelResidue = new Array(channels);
			for (let c = 0; c < channels; c++) {
				this._channelFloor[c] = this._submapFloor[mux[c]];
				this._channelResidue[c] = this._submapResidue[mux[c]];
			}
			this._mdct = mdct;
		}
		decodePacket(packet, blockSize, buffer) {
			const halfBlockSize = blockSize >> 1;
			const floorData = new Array(this._channelFloor.length);
			const noExecuteChannel = new Array(this._channelFloor.length);
			noExecuteChannel.fill(false);
			for (let i = 0; i < this._channelFloor.length; i++) {
				floorData[i] = this._channelFloor[i].unpack(packet, blockSize, i);
				noExecuteChannel[i] = !floorData[i].executeChannel;
				buffer[i].fill(0, 0, halfBlockSize);
			}
			for (let i = 0; i < this._couplingAngle.length; i++) if (floorData[this._couplingAngle[i]].executeChannel || floorData[this._couplingMangitude[i]].executeChannel) {
				floorData[this._couplingAngle[i]].forceEnergy = true;
				floorData[this._couplingMangitude[i]].forceEnergy = true;
			}
			for (let i = 0; i < this._submapFloor.length; i++) {
				for (let j = 0; j < this._channelFloor.length; j++) if (this._submapFloor[i] !== this._channelFloor[j] || this._submapResidue[i] !== this._channelResidue[j]) floorData[j].forceNoEnergy = true;
				this._submapResidue[i].decode(packet, noExecuteChannel, blockSize, buffer);
			}
			for (let i = this._couplingAngle.length - 1; i >= 0; i--) if (floorData[this._couplingAngle[i]].executeChannel || floorData[this._couplingMangitude[i]].executeChannel) {
				const magnitude = buffer[this._couplingMangitude[i]];
				const angle = buffer[this._couplingAngle[i]];
				for (let j = 0; j < halfBlockSize; j++) {
					let newM;
					let newA;
					const oldM = magnitude[j];
					const oldA = angle[j];
					if (oldM > 0) if (oldA > 0) {
						newM = oldM;
						newA = oldM - oldA;
					} else {
						newA = oldM;
						newM = oldM + oldA;
					}
					else if (oldA > 0) {
						newM = oldM;
						newA = oldM + oldA;
					} else {
						newA = oldM;
						newM = oldM - oldA;
					}
					magnitude[j] = newM;
					angle[j] = newA;
				}
			}
			for (let c = 0; c < this._channelFloor.length; c++) if (floorData[c].executeChannel) {
				this._channelFloor[c].apply(floorData[c], blockSize, buffer[c]);
				this._mdct.reverse(buffer[c], blockSize);
			} else buffer[c].fill(0, halfBlockSize, halfBlockSize * 2);
		}
	};
	/**
	* @internal
	*/
	var VorbisModeOverlapInfo = class {
		packetStartIndex = 0;
		packetTotalLength = 0;
		packetValidLength = 0;
	};
	/**
	* @internal
	*/
	var VorbisModePacketInfo = class {
		overlapInfo = new VorbisModeOverlapInfo();
		windowIndex = 0;
	};
	/**
	* @internal
	*/
	var VorbisReadNextPacketResult = class {
		samplePosition = null;
		constructor(samplePosition = null) {
			this.samplePosition = samplePosition;
		}
	};
	/**
	* @internal
	*/
	var VorbisMode = class VorbisMode {
		static _piHalf = 3.1415926539 / 2;
		_channels;
		_blockFlag;
		_blockSize;
		_mapping;
		_windows;
		_overlapInfo = null;
		constructor(packet, channels, block0Size, block1Size, mappings) {
			this._channels = channels;
			this._blockFlag = packet.readBit();
			if (0 !== packet.readBits(32)) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Mode header had invalid window or transform type!");
			const mappingIdx = packet.readBits(8);
			if (mappingIdx >= mappings.length) throw new AlphaTabError(AlphaTabErrorType.Format, "Vorbis: Mode header had invalid mapping index!");
			this._mapping = mappings[mappingIdx];
			if (this._blockFlag) {
				this._blockSize = block1Size;
				this._windows = [
					VorbisMode._calcWindow(block0Size, block1Size, block0Size),
					VorbisMode._calcWindow(block1Size, block1Size, block0Size),
					VorbisMode._calcWindow(block0Size, block1Size, block1Size),
					VorbisMode._calcWindow(block1Size, block1Size, block1Size)
				];
				this._overlapInfo = [
					VorbisMode._calcOverlap(block0Size, block1Size, block0Size),
					VorbisMode._calcOverlap(block1Size, block1Size, block0Size),
					VorbisMode._calcOverlap(block0Size, block1Size, block1Size),
					VorbisMode._calcOverlap(block1Size, block1Size, block1Size)
				];
			} else {
				this._blockSize = block0Size;
				this._windows = [VorbisMode._calcWindow(block0Size, block0Size, block0Size)];
			}
		}
		decode(reader, buffer) {
			const info = this._getPacketInfo(reader);
			this._mapping.decodePacket(reader, this._blockSize, buffer);
			const window = this._windows[info.windowIndex];
			for (let i = 0; i < this._blockSize; i++) for (let ch = 0; ch < this._channels; ch++) buffer[ch][i] *= window[i];
			return info.overlapInfo;
		}
		_getPacketInfo(reader) {
			const info = new VorbisModePacketInfo();
			if (this._blockFlag) {
				const prevFlag = reader.readBit();
				const nextFlag = reader.readBit();
				info.windowIndex = (prevFlag ? 1 : 0) + (nextFlag ? 2 : 0);
				const overlapInfo = this._overlapInfo[info.windowIndex];
				info.overlapInfo.packetStartIndex = overlapInfo.packetStartIndex;
				info.overlapInfo.packetValidLength = overlapInfo.packetValidLength;
				info.overlapInfo.packetTotalLength = overlapInfo.packetTotalLength;
			} else {
				info.windowIndex = 0;
				info.overlapInfo.packetStartIndex = 0;
				info.overlapInfo.packetValidLength = this._blockSize / 2;
				info.overlapInfo.packetTotalLength = this._blockSize;
			}
			return info;
		}
		static _calcWindow(prevBlockSize, blockSize, nextBlockSize) {
			const array = new Float32Array(blockSize);
			const left = prevBlockSize / 2;
			const wnd = blockSize;
			const right = nextBlockSize / 2;
			const leftbegin = wnd / 4 - left / 2;
			const rightbegin = wnd - wnd / 4 - right / 2;
			for (let i = 0; i < left; i++) {
				let x = Math.sin((i + .5) / left * VorbisMode._piHalf);
				x *= x;
				array[leftbegin + i] = Math.sin(x * VorbisMode._piHalf);
			}
			for (let i = leftbegin + left; i < rightbegin; i++) array[i] = 1;
			for (let i = 0; i < right; i++) {
				let x = Math.sin((right - i - .5) / right * VorbisMode._piHalf);
				x *= x;
				array[rightbegin + i] = Math.sin(x * VorbisMode._piHalf);
			}
			return array;
		}
		static _calcOverlap(prevBlockSize, blockSize, nextBlockSize) {
			const leftOverlapHalfSize = prevBlockSize / 4;
			const rightOverlapHalfSize = nextBlockSize / 4;
			const packetStartIndex = blockSize / 4 - leftOverlapHalfSize;
			const packetTotalLength = blockSize / 4 * 3 + rightOverlapHalfSize;
			const packetValidLength = packetTotalLength - rightOverlapHalfSize * 2;
			const info = new VorbisModeOverlapInfo();
			info.packetStartIndex = packetStartIndex;
			info.packetValidLength = packetValidLength;
			info.packetTotalLength = packetTotalLength;
			return info;
		}
	};
	/**
	* @internal
	*/
	var MdctImpl = class MdctImpl {
		static _pi = 3.141592653589793;
		_n;
		_n2;
		_n4;
		_n8;
		_ld;
		_a;
		_b;
		_c;
		_bitrev;
		constructor(n) {
			this._n = n;
			this._n2 = n >> 1;
			this._n4 = this._n2 >> 1;
			this._n8 = this._n4 >> 1;
			this._ld = VorbisUtils.ilog(n) - 1;
			this._a = new Float32Array(this._n2);
			this._b = new Float32Array(this._n2);
			this._c = new Float32Array(this._n4);
			let k = 0;
			let k2 = 0;
			for (; k < this._n4; ++k, k2 += 2) {
				this._a[k2] = Math.cos(4 * k * MdctImpl._pi / n);
				this._a[k2 + 1] = -Math.sin(4 * k * MdctImpl._pi / n);
				this._b[k2] = Math.cos((k2 + 1) * MdctImpl._pi / n / 2) * .5;
				this._b[k2 + 1] = Math.sin((k2 + 1) * MdctImpl._pi / n / 2) * .5;
			}
			k = 0;
			k2 = 0;
			for (; k < this._n8; ++k, k2 += 2) {
				this._c[k2] = Math.cos(2 * (k2 + 1) * MdctImpl._pi / n);
				this._c[k2 + 1] = -Math.sin(2 * (k2 + 1) * MdctImpl._pi / n);
			}
			this._bitrev = new Uint16Array(this._n8);
			for (let i = 0; i < this._n8; ++i) this._bitrev[i] = TypeConversions.int32ToUint16(VorbisUtils.bitReverse(i, this._ld - 3) << 2);
		}
		calcReverse(buffer) {
			let u;
			let v;
			const buf2 = new Float32Array(this._n2);
			{
				let d = this._n2 - 2;
				let aa = 0;
				let e = 0;
				const eStop = this._n2;
				while (e !== eStop) {
					buf2[d + 1] = buffer[e] * this._a[aa] - buffer[e + 2] * this._a[aa + 1];
					buf2[d] = buffer[e] * this._a[aa + 1] + buffer[e + 2] * this._a[aa];
					d -= 2;
					aa += 2;
					e += 4;
				}
				e = this._n2 - 3;
				while (d >= 0) {
					buf2[d + 1] = -buffer[e + 2] * this._a[aa] - -buffer[e] * this._a[aa + 1];
					buf2[d] = -buffer[e + 2] * this._a[aa + 1] + -buffer[e] * this._a[aa];
					d -= 2;
					aa += 2;
					e -= 4;
				}
			}
			u = buffer;
			v = buf2;
			{
				let aa = this._n2 - 8;
				let e0 = this._n4;
				let e1 = 0;
				let d0 = this._n4;
				let d1 = 0;
				while (aa >= 0) {
					let v4020;
					let v4121;
					v4121 = v[e0 + 1] - v[e1 + 1];
					v4020 = v[e0] - v[e1];
					u[d0 + 1] = v[e0 + 1] + v[e1 + 1];
					u[d0] = v[e0] + v[e1];
					u[d1 + 1] = v4121 * this._a[aa + 4] - v4020 * this._a[aa + 5];
					u[d1] = v4020 * this._a[aa + 4] + v4121 * this._a[aa + 5];
					v4121 = v[e0 + 3] - v[e1 + 3];
					v4020 = v[e0 + 2] - v[e1 + 2];
					u[d0 + 3] = v[e0 + 3] + v[e1 + 3];
					u[d0 + 2] = v[e0 + 2] + v[e1 + 2];
					u[d1 + 3] = v4121 * this._a[aa] - v4020 * this._a[aa + 1];
					u[d1 + 2] = v4020 * this._a[aa] + v4121 * this._a[aa + 1];
					aa -= 8;
					d0 += 4;
					d1 += 4;
					e0 += 4;
					e1 += 4;
				}
			}
			this._step3Iter0Loop(this._n >> 4, u, this._n2 - 1 - this._n4 * 0, -this._n8);
			this._step3Iter0Loop(this._n >> 4, u, this._n2 - 1 - this._n4 * 1, -this._n8);
			this._step3InnerRLoop(this._n >> 5, u, this._n2 - 1 - this._n8 * 0, -(this._n >> 4), 16);
			this._step3InnerRLoop(this._n >> 5, u, this._n2 - 1 - this._n8 * 1, -(this._n >> 4), 16);
			this._step3InnerRLoop(this._n >> 5, u, this._n2 - 1 - this._n8 * 2, -(this._n >> 4), 16);
			this._step3InnerRLoop(this._n >> 5, u, this._n2 - 1 - this._n8 * 3, -(this._n >> 4), 16);
			let l = 2;
			for (; l < this._ld - 3 >> 1; ++l) {
				const k0 = this._n >> l + 2;
				const k02 = k0 >> 1;
				const lim = 1 << l + 1;
				for (let i = 0; i < lim; ++i) this._step3InnerRLoop(this._n >> l + 4, u, this._n2 - 1 - k0 * i, -k02, 1 << l + 3);
			}
			for (; l < this._ld - 6; ++l) {
				const k0 = this._n >> l + 2;
				const k1 = 1 << l + 3;
				const k02 = k0 >> 1;
				const rlim = this._n >> l + 6;
				const lim = 1 << l + 1;
				let iOff = this._n2 - 1;
				let A0 = 0;
				for (let r = rlim; r > 0; --r) {
					this._step3InnerSLoop(lim, u, iOff, -k02, A0, k1, k0);
					A0 += k1 * 4;
					iOff -= 8;
				}
			}
			this._step3InnerSLoopLd654(this._n >> 5, u, this._n2 - 1, this._n);
			{
				let bit = 0;
				let d0 = this._n4 - 4;
				let d1 = this._n2 - 4;
				while (d0 >= 0) {
					let k4;
					k4 = this._bitrev[bit];
					v[d1 + 3] = u[k4];
					v[d1 + 2] = u[k4 + 1];
					v[d0 + 3] = u[k4 + 2];
					v[d0 + 2] = u[k4 + 3];
					k4 = this._bitrev[bit + 1];
					v[d1 + 1] = u[k4];
					v[d1] = u[k4 + 1];
					v[d0 + 1] = u[k4 + 2];
					v[d0] = u[k4 + 3];
					d0 -= 4;
					d1 -= 4;
					bit += 2;
				}
			}
			{
				let c = 0;
				let d = 0;
				let e = this._n2 - 4;
				while (d < e) {
					let a02;
					let a11;
					let b0;
					let b1;
					let b2;
					let b3;
					a02 = v[d] - v[e + 2];
					a11 = v[d + 1] + v[e + 3];
					b0 = this._c[c + 1] * a02 + this._c[c] * a11;
					b1 = this._c[c + 1] * a11 - this._c[c] * a02;
					b2 = v[d] + v[e + 2];
					b3 = v[d + 1] - v[e + 3];
					v[d] = b2 + b0;
					v[d + 1] = b3 + b1;
					v[e + 2] = b2 - b0;
					v[e + 3] = b1 - b3;
					a02 = v[d + 2] - v[e];
					a11 = v[d + 3] + v[e + 1];
					b0 = this._c[c + 3] * a02 + this._c[c + 2] * a11;
					b1 = this._c[c + 3] * a11 - this._c[c + 2] * a02;
					b2 = v[d + 2] + v[e];
					b3 = v[d + 3] - v[e + 1];
					v[d + 2] = b2 + b0;
					v[d + 3] = b3 + b1;
					v[e] = b2 - b0;
					v[e + 1] = b1 - b3;
					c += 4;
					d += 4;
					e -= 4;
				}
			}
			{
				let b = this._n2 - 8;
				let e = this._n2 - 8;
				let d0 = 0;
				let d1 = this._n2 - 4;
				let d2 = this._n2;
				let d3 = this._n - 4;
				while (e >= 0) {
					let p0;
					let p1;
					let p2;
					let p3;
					p3 = buf2[e + 6] * this._b[b + 7] - buf2[e + 7] * this._b[b + 6];
					p2 = -buf2[e + 6] * this._b[b + 6] - buf2[e + 7] * this._b[b + 7];
					buffer[d0] = p3;
					buffer[d1 + 3] = -p3;
					buffer[d2] = p2;
					buffer[d3 + 3] = p2;
					p1 = buf2[e + 4] * this._b[b + 5] - buf2[e + 5] * this._b[b + 4];
					p0 = -buf2[e + 4] * this._b[b + 4] - buf2[e + 5] * this._b[b + 5];
					buffer[d0 + 1] = p1;
					buffer[d1 + 2] = -p1;
					buffer[d2 + 1] = p0;
					buffer[d3 + 2] = p0;
					p3 = buf2[e + 2] * this._b[b + 3] - buf2[e + 3] * this._b[b + 2];
					p2 = -buf2[e + 2] * this._b[b + 2] - buf2[e + 3] * this._b[b + 3];
					buffer[d0 + 2] = p3;
					buffer[d1 + 1] = -p3;
					buffer[d2 + 2] = p2;
					buffer[d3 + 1] = p2;
					p1 = buf2[e] * this._b[b + 1] - buf2[e + 1] * this._b[b];
					p0 = -buf2[e] * this._b[b] - buf2[e + 1] * this._b[b + 1];
					buffer[d0 + 3] = p1;
					buffer[d1] = -p1;
					buffer[d2 + 3] = p0;
					buffer[d3] = p0;
					b -= 8;
					e -= 8;
					d0 += 4;
					d2 += 4;
					d1 -= 4;
					d3 -= 4;
				}
			}
		}
		_step3InnerRLoop(lim, e, d0, kOff, k1) {
			let k0020;
			let k0121;
			let e0 = d0;
			let e2 = e0 + kOff;
			let a = 0;
			for (let i = lim >> 2; i > 0; --i) {
				k0020 = e[e0] - e[e2];
				k0121 = e[e0 - 1] - e[e2 - 1];
				e[e0] += e[e2];
				e[e0 - 1] += e[e2 - 1];
				e[e2] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[e2 - 1] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += k1;
				k0020 = e[e0 - 2] - e[e2 - 2];
				k0121 = e[e0 - 3] - e[e2 - 3];
				e[e0 - 2] += e[e2 - 2];
				e[e0 - 3] += e[e2 - 3];
				e[e2 - 2] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[e2 - 3] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += k1;
				k0020 = e[e0 - 4] - e[e2 - 4];
				k0121 = e[e0 - 5] - e[e2 - 5];
				e[e0 - 4] += e[e2 - 4];
				e[e0 - 5] += e[e2 - 5];
				e[e2 - 4] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[e2 - 5] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += k1;
				k0020 = e[e0 - 6] - e[e2 - 6];
				k0121 = e[e0 - 7] - e[e2 - 7];
				e[e0 - 6] += e[e2 - 6];
				e[e0 - 7] += e[e2 - 7];
				e[e2 - 6] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[e2 - 7] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += k1;
				e0 -= 8;
				e2 -= 8;
			}
		}
		_step3Iter0Loop(n, e, iOff, kOff) {
			let ee0 = iOff;
			let ee2 = ee0 + kOff;
			let a = 0;
			for (let i = n >> 2; i > 0; --i) {
				let k0020;
				let k0121;
				k0020 = e[ee0] - e[ee2];
				k0121 = e[ee0 - 1] - e[ee2 - 1];
				e[ee0] += e[ee2];
				e[ee0 - 1] += e[ee2 - 1];
				e[ee2] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[ee2 - 1] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += 8;
				k0020 = e[ee0 - 2] - e[ee2 - 2];
				k0121 = e[ee0 - 3] - e[ee2 - 3];
				e[ee0 - 2] += e[ee2 - 2];
				e[ee0 - 3] += e[ee2 - 3];
				e[ee2 - 2] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[ee2 - 3] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += 8;
				k0020 = e[ee0 - 4] - e[ee2 - 4];
				k0121 = e[ee0 - 5] - e[ee2 - 5];
				e[ee0 - 4] += e[ee2 - 4];
				e[ee0 - 5] += e[ee2 - 5];
				e[ee2 - 4] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[ee2 - 5] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += 8;
				k0020 = e[ee0 - 6] - e[ee2 - 6];
				k0121 = e[ee0 - 7] - e[ee2 - 7];
				e[ee0 - 6] += e[ee2 - 6];
				e[ee0 - 7] += e[ee2 - 7];
				e[ee2 - 6] = k0020 * this._a[a] - k0121 * this._a[a + 1];
				e[ee2 - 7] = k0121 * this._a[a] + k0020 * this._a[a + 1];
				a += 8;
				ee0 -= 8;
				ee2 -= 8;
			}
		}
		_step3InnerSLoop(n, e, iOff, kOff, a, aOff, k0) {
			const A0 = this._a[a];
			const A1 = this._a[a + 1];
			const A2 = this._a[a + aOff];
			const A3 = this._a[a + aOff + 1];
			const A4 = this._a[a + aOff * 2];
			const A5 = this._a[a + aOff * 2 + 1];
			const A6 = this._a[a + aOff * 3];
			const A7 = this._a[a + aOff * 3 + 1];
			let k00;
			let k11;
			let ee0 = iOff;
			let ee2 = ee0 + kOff;
			for (let i = n; i > 0; --i) {
				k00 = e[ee0] - e[ee2];
				k11 = e[ee0 - 1] - e[ee2 - 1];
				e[ee0] += e[ee2];
				e[ee0 - 1] += e[ee2 - 1];
				e[ee2] = k00 * A0 - k11 * A1;
				e[ee2 - 1] = k11 * A0 + k00 * A1;
				k00 = e[ee0 - 2] - e[ee2 - 2];
				k11 = e[ee0 - 3] - e[ee2 - 3];
				e[ee0 - 2] += e[ee2 - 2];
				e[ee0 - 3] += e[ee2 - 3];
				e[ee2 - 2] = k00 * A2 - k11 * A3;
				e[ee2 - 3] = k11 * A2 + k00 * A3;
				k00 = e[ee0 - 4] - e[ee2 - 4];
				k11 = e[ee0 - 5] - e[ee2 - 5];
				e[ee0 - 4] += e[ee2 - 4];
				e[ee0 - 5] += e[ee2 - 5];
				e[ee2 - 4] = k00 * A4 - k11 * A5;
				e[ee2 - 5] = k11 * A4 + k00 * A5;
				k00 = e[ee0 - 6] - e[ee2 - 6];
				k11 = e[ee0 - 7] - e[ee2 - 7];
				e[ee0 - 6] += e[ee2 - 6];
				e[ee0 - 7] += e[ee2 - 7];
				e[ee2 - 6] = k00 * A6 - k11 * A7;
				e[ee2 - 7] = k11 * A6 + k00 * A7;
				ee0 -= k0;
				ee2 -= k0;
			}
		}
		_step3InnerSLoopLd654(n, e, iOff, baseN) {
			const aOff = baseN >> 3;
			const A2 = this._a[aOff];
			let z = iOff;
			const b = z - 16 * n;
			while (z > b) {
				let k00;
				let k11;
				k00 = e[z] - e[z - 8];
				k11 = e[z - 1] - e[z - 9];
				e[z] += e[z - 8];
				e[z - 1] += e[z - 9];
				e[z - 8] = k00;
				e[z - 9] = k11;
				k00 = e[z - 2] - e[z - 10];
				k11 = e[z - 3] - e[z - 11];
				e[z - 2] += e[z - 10];
				e[z - 3] += e[z - 11];
				e[z - 10] = (k00 + k11) * A2;
				e[z - 11] = (k11 - k00) * A2;
				k00 = e[z - 12] - e[z - 4];
				k11 = e[z - 5] - e[z - 13];
				e[z - 4] += e[z - 12];
				e[z - 5] += e[z - 13];
				e[z - 12] = k11;
				e[z - 13] = k00;
				k00 = e[z - 14] - e[z - 6];
				k11 = e[z - 7] - e[z - 15];
				e[z - 6] += e[z - 14];
				e[z - 7] += e[z - 15];
				e[z - 14] = (k00 + k11) * A2;
				e[z - 15] = (k00 - k11) * A2;
				this._iter54(e, z);
				this._iter54(e, z - 8);
				z -= 16;
			}
		}
		_iter54(e, z) {
			const k00 = e[z] - e[z - 4];
			const y0 = e[z] + e[z - 4];
			const y2 = e[z - 2] + e[z - 6];
			const k22 = e[z - 2] - e[z - 6];
			e[z] = y0 + y2;
			e[z - 2] = y0 - y2;
			const k33 = e[z - 3] - e[z - 7];
			e[z - 4] = k00 + k33;
			e[z - 6] = k00 - k33;
			const k11 = e[z - 1] - e[z - 5];
			const y1 = e[z - 1] + e[z - 5];
			const y3 = e[z - 3] + e[z - 7];
			e[z - 1] = y1 + y3;
			e[z - 3] = y1 - y3;
			e[z - 5] = k11 - k22;
			e[z - 7] = k11 + k22;
		}
	};
	/**
	* @internal
	*/
	var Mdct = class {
		_setupCache = /* @__PURE__ */ new Map();
		reverse(samples, sampleCount) {
			let impl;
			if (this._setupCache.has(sampleCount)) impl = this._setupCache.get(sampleCount);
			else {
				impl = new MdctImpl(sampleCount);
				this._setupCache.set(sampleCount, impl);
			}
			impl.calcReverse(samples);
		}
	};
	/**
	* @internal
	*/
	var VorbisStreamDecoder = class VorbisStreamDecoder {
		_stream;
		_setup;
		_packets;
		_packetIndex = 0;
		_nextPacketBuf;
		_prevPacketBuf;
		_prevPacketStart;
		_prevPacketEnd;
		_prevPacketStop;
		_currentPosition;
		_hasPosition;
		_eosFound;
		_modeFieldBits;
		constructor(stream, setup, packets) {
			this._stream = stream;
			this._setup = setup;
			this._packets = packets;
			this._currentPosition = 0;
			this._prevPacketBuf = null;
			this._prevPacketStart = 0;
			this._prevPacketEnd = 0;
			this._prevPacketStop = 0;
			this._nextPacketBuf = null;
			this._eosFound = false;
			this._hasPosition = false;
			this._modeFieldBits = VorbisUtils.ilog(setup.modes.length - 1);
		}
		decode() {
			let allSamples = new Float32Array(this._packets[this._packets.length - 1].granulePosition * this._stream.audioChannels);
			const buffer = new Float32Array(.2 * this._stream.audioSampleRate * this._stream.audioChannels);
			let cnt = 0;
			let pos = 0;
			while (true) {
				cnt = this.read(buffer, 0, buffer.length);
				if (cnt === 0) break;
				if (pos + cnt >= allSamples.length) {
					const newAllSamples = new Float32Array(allSamples.length + buffer.length);
					newAllSamples.set(allSamples, 0);
					allSamples = newAllSamples;
				}
				allSamples.set(buffer.subarray(0, cnt), pos);
				pos += cnt;
			}
			return allSamples.subarray(0, pos);
		}
		read(buffer, offset, count) {
			if (count === 0) return 0;
			let idx = offset;
			const tgt = offset + count;
			while (idx < tgt) {
				if (this._prevPacketStart === this._prevPacketEnd) {
					if (this._eosFound) {
						this._nextPacketBuf = null;
						this._prevPacketBuf = null;
						break;
					}
					const readResult = this._readNextPacket((idx - offset) / this._stream.audioChannels);
					if (readResult === null) this._prevPacketEnd = this._prevPacketStop;
					if (readResult !== null && readResult.samplePosition !== null && !this._hasPosition) {
						this._hasPosition = true;
						this._currentPosition = readResult.samplePosition - (this._prevPacketEnd - this._prevPacketStart) - (idx - offset) / this._stream.audioChannels;
					}
				}
				const copyLen = Math.min((tgt - idx) / this._stream.audioChannels, this._prevPacketEnd - this._prevPacketStart);
				if (copyLen > 0) idx += this._copyBuffer(buffer, idx, copyLen);
			}
			count = idx - offset;
			this._currentPosition += count / this._stream.audioChannels;
			return count;
		}
		_copyBuffer(target, targetIndex, count) {
			let idx = targetIndex;
			for (; count > 0; this._prevPacketStart++, count--) for (let ch = 0; ch < this._stream.audioChannels; ch++) target[idx++] = this._prevPacketBuf[ch][this._prevPacketStart];
			return idx - targetIndex;
		}
		_readNextPacket(bufferedSamples) {
			const res = this._decodeNextPacket();
			this._eosFound = this._eosFound || res.isEndOfStream;
			if (res.curPacket == null) return null;
			if (res.samplePosition !== null && res.isEndOfStream) {
				const actualEnd = this._currentPosition + bufferedSamples + res.validLen - res.startIndex;
				const diff = res.samplePosition - actualEnd;
				if (diff < 0) {
					res.validLen += diff;
					if (res.validLen < 0) res.validLen = 0;
				}
			}
			if (this._prevPacketEnd > 0) {
				VorbisStreamDecoder._overlapBuffers(this._prevPacketBuf, res.curPacket, this._prevPacketStart, this._prevPacketStop, res.startIndex, this._stream.audioChannels);
				this._prevPacketStart = res.startIndex;
			} else if (this._prevPacketBuf == null) this._prevPacketStart = res.validLen;
			this._nextPacketBuf = this._prevPacketBuf;
			this._prevPacketEnd = res.validLen;
			this._prevPacketStop = res.totalLen;
			this._prevPacketBuf = res.curPacket;
			return new VorbisReadNextPacketResult(res.samplePosition);
		}
		static _overlapBuffers(previous, next, prevStart, prevLen, nextStart, channels) {
			for (; prevStart < prevLen; prevStart++, nextStart++) for (let c = 0; c < channels; c++) next[c][nextStart] += previous[c][prevStart];
		}
		_decodeNextPacket() {
			const res = new DecodeNextPacketInfo();
			let packet = null;
			if (this._packetIndex >= this._packets.length) res.isEndOfStream = true;
			else {
				packet = this._packets[this._packetIndex++];
				const reader = new IntBitReader(ByteBuffer.fromBuffer(packet.packetData));
				res.isEndOfStream = packet.isEndOfStream;
				if (!reader.readBit()) {
					const mode = this._setup.modes[reader.readBits(this._modeFieldBits)];
					if (this._nextPacketBuf == null) {
						this._nextPacketBuf = new Array(this._stream.audioChannels);
						for (let i = 0; i < this._stream.audioChannels; i++) this._nextPacketBuf[i] = new Float32Array(this._stream.blocksize1);
					}
					const decodeRes = mode.decode(reader, this._nextPacketBuf);
					res.startIndex = decodeRes.packetStartIndex;
					res.validLen = decodeRes.packetValidLength;
					res.totalLen = decodeRes.packetTotalLength;
					res.samplePosition = packet.granulePosition;
					res.curPacket = this._nextPacketBuf;
					return res;
				}
			}
			return res;
		}
	};
	/**
	* @internal
	*/
	var DecodeNextPacketInfo = class {
		curPacket = null;
		startIndex = 0;
		validLen = 0;
		totalLen = 0;
		isEndOfStream = false;
		samplePosition = null;
	};
	//#endregion
	//#region src/synth/vorbis/VorbisStreamReader.ts
	/**
	* @internal
	*/
	var VorbisStreamReader = class VorbisStreamReader {
		static vorbisHeaderMarker = new Uint8Array([
			"v".charCodeAt(0),
			"o".charCodeAt(0),
			"r".charCodeAt(0),
			"b".charCodeAt(0),
			"i".charCodeAt(0),
			"s".charCodeAt(0)
		]);
		_packets;
		_packetIndex;
		constructor(packets) {
			this._packetIndex = -1;
			this._packets = packets;
		}
		read() {
			let packet;
			while (true) {
				packet = this._nextPacket();
				if (packet == null) return null;
				if (packet.isBeginningOfStream) {
					const stream = this._readStream(packet);
					if (stream != null) return stream;
				}
			}
		}
		_nextPacket() {
			this._packetIndex++;
			return this._packetIndex < this._packets.length ? this._packets[this._packetIndex] : null;
		}
		_readStream(startPacket) {
			const stream = new VorbisStream();
			if (!this._readIdentificationHeader(stream, startPacket)) return null;
			if (!this._readComments(this._nextPacket())) return null;
			const vorbisSetup = new VorbisSetupHeader();
			if (!this._readSetupHeader(stream, vorbisSetup, this._nextPacket())) return null;
			const streamDataPackets = [];
			let packet;
			while (true) {
				packet = this._nextPacket();
				if (packet == null) break;
				streamDataPackets.push(packet);
				if (packet.isEndOfStream) break;
			}
			stream.samples = new VorbisStreamDecoder(stream, vorbisSetup, streamDataPackets).decode();
			return stream;
		}
		/**
		* https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-610004.2
		* @param packetType
		* @param reader
		* @returns
		*/
		_commonHeaderDecode(packetType, reader) {
			const data = new Uint8Array(7);
			reader.read(data, 0, data.length);
			if (data[0] !== packetType) return false;
			for (let i = 0; i < VorbisStreamReader.vorbisHeaderMarker.length; i++) if (data[1 + i] !== VorbisStreamReader.vorbisHeaderMarker[i]) return false;
			return true;
		}
		/**
		* https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-610004.2
		* @param packetType
		* @param reader
		* @returns
		*/
		_commonHeaderDecodeBit(packetType, reader) {
			const data = reader.readBytes(7);
			if (data[0] !== packetType) return false;
			for (let i = 0; i < VorbisStreamReader.vorbisHeaderMarker.length; i++) if (data[1 + i] !== VorbisStreamReader.vorbisHeaderMarker[i]) return false;
			return true;
		}
		/**
		* https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-630004.2.2
		* @param stream
		* @param packet
		* @returns
		*/
		_readIdentificationHeader(stream, packet) {
			const reader = ByteBuffer.fromBuffer(packet.packetData);
			if (!this._commonHeaderDecode(1, reader)) return false;
			if (IOHelper.readUInt32LE(reader) !== 0) return false;
			stream.audioChannels = reader.readByte();
			stream.audioSampleRate = IOHelper.readUInt32LE(reader);
			if (stream.audioChannels <= 0 || stream.audioSampleRate <= 0) return false;
			stream.bitrateMaximum = IOHelper.readInt32LE(reader);
			stream.bitrateNominal = IOHelper.readInt32LE(reader);
			stream.bitrateMinimum = IOHelper.readInt32LE(reader);
			const blockSize = reader.readByte();
			stream.blocksize0 = 1 << (blockSize & 15);
			stream.blocksize1 = 1 << (blockSize >> 4);
			if (stream.blocksize0 > stream.blocksize1 || !VorbisStreamReader._isAllowedBlockSize(stream.blocksize0) || !VorbisStreamReader._isAllowedBlockSize(stream.blocksize0)) return false;
			if (reader.readByte() === 0) return false;
			return true;
		}
		static _isAllowedBlockSize(blocksize) {
			switch (blocksize) {
				case 64:
				case 128:
				case 256:
				case 512:
				case 1024:
				case 2048:
				case 4096:
				case 8192: return true;
				default: return false;
			}
		}
		/**
		* https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-820005
		* @param packet
		* @returns
		*/
		_readComments(packet) {
			if (packet == null) return false;
			const reader = ByteBuffer.fromBuffer(packet.packetData);
			if (!this._commonHeaderDecode(3, reader)) return false;
			const vendorLength = IOHelper.readUInt32LE(reader);
			reader.skip(vendorLength);
			const userCommentListLength = IOHelper.readUInt32LE(reader);
			for (let index = 0; index < userCommentListLength; index++) {
				const length = IOHelper.readUInt32LE(reader);
				reader.skip(length);
			}
			if (reader.readByte() === 0) return false;
			return true;
		}
		/**
		* https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-650004.2.4
		* @param setup
		* @param packet
		* @returns
		*/
		_readSetupHeader(stream, setup, packet) {
			if (packet == null) return false;
			const bitReader = new IntBitReader(ByteBuffer.fromBuffer(packet.packetData));
			const mdct = new Mdct();
			const huffman = new Huffman();
			if (!this._commonHeaderDecodeBit(5, bitReader)) return false;
			let count = bitReader.readByte() + 1;
			for (let i = 0; i < count; i++) setup.codebooks.push(new VorbisCodebook(bitReader, huffman));
			count = bitReader.readBits(6) + 1;
			for (let i = 0; i < count; i++) setup.timeDomainTransforms.push(new VorbisTimeDomainTransform(bitReader));
			count = bitReader.readBits(6) + 1;
			for (let i = 0; i < count; i++) setup.floors.push(new VorbisFloor(bitReader, stream.blocksize0, stream.blocksize1, setup.codebooks));
			count = bitReader.readBits(6) + 1;
			for (let i = 0; i < count; i++) setup.residues.push(new VorbisResidue(bitReader, stream.audioChannels, setup.codebooks));
			count = bitReader.readBits(6) + 1;
			for (let i = 0; i < count; i++) setup.mappings.push(new VorbisMapping(bitReader, stream.audioChannels, setup.floors, setup.residues, mdct));
			count = bitReader.readBits(6) + 1;
			for (let i = 0; i < count; i++) setup.modes.push(new VorbisMode(bitReader, stream.audioChannels, stream.blocksize0, stream.blocksize1, setup.mappings));
			if (!bitReader.readBit()) return false;
			return true;
		}
	};
	//#endregion
	//#region src/synth/vorbis/VorbisFile.ts
	/**
	* @internal
	*/
	var VorbisFile = class {
		streams = [];
		constructor(readable) {
			const decoder = new VorbisStreamReader(new OggReader(readable).read());
			while (true) {
				const stream = decoder.read();
				if (stream == null) break;
				this.streams.push(stream);
			}
		}
	};
	//#endregion
	//#region src/synth/soundfont/Hydra.ts
	/**
	* @internal
	*/
	var Hydra = class {
		phdrs = [];
		pbags = [];
		pmods = [];
		pgens = [];
		insts = [];
		ibags = [];
		imods = [];
		igens = [];
		sHdrs = [];
		sampleData = new Uint8Array(0);
		_sampleCache = /* @__PURE__ */ new Map();
		decodeSamples(startByte, endByte, decompressVorbis) {
			const key = `${startByte}_${endByte}_${decompressVorbis}`;
			if (!this._sampleCache.has(key)) {
				let samples;
				const sampleBytes = this.sampleData.slice(startByte, endByte);
				if (decompressVorbis) samples = new VorbisFile(ByteBuffer.fromBuffer(sampleBytes)).streams[0].samples;
				else {
					const dataView = new DataView(sampleBytes.buffer, sampleBytes.byteOffset, sampleBytes.length);
					samples = new Float32Array(sampleBytes.length / 2);
					for (let i = 0; i < samples.length; i++) samples[i] = dataView.getInt16(i * 2, true) / 32767;
				}
				this._sampleCache.set(key, samples);
				return samples;
			}
			return this._sampleCache.get(key);
		}
		load(readable) {
			const chunkHead = new RiffChunk();
			const chunkFastList = new RiffChunk();
			if (!RiffChunk.load(null, chunkHead, readable) || chunkHead.id !== "sfbk") throw new FormatError("Soundfont is not a valid Soundfont2 file");
			while (RiffChunk.load(chunkHead, chunkFastList, readable)) {
				const chunk = new RiffChunk();
				if (chunkFastList.id === "pdta") while (RiffChunk.load(chunkFastList, chunk, readable)) switch (chunk.id) {
					case "phdr":
						for (let i = 0, count = chunk.size / HydraPhdr.SizeInFile | 0; i < count; i++) this.phdrs.push(new HydraPhdr(readable));
						break;
					case "pbag":
						for (let i = 0, count = chunk.size / HydraPbag.SizeInFile | 0; i < count; i++) this.pbags.push(new HydraPbag(readable));
						break;
					case "pmod":
						for (let i = 0, count = chunk.size / HydraPmod.SizeInFile | 0; i < count; i++) this.pmods.push(new HydraPmod(readable));
						break;
					case "pgen":
						for (let i = 0, count = chunk.size / HydraPgen.SizeInFile | 0; i < count; i++) this.pgens.push(new HydraPgen(readable));
						break;
					case "inst":
						for (let i = 0, count = chunk.size / HydraInst.SizeInFile | 0; i < count; i++) this.insts.push(new HydraInst(readable));
						break;
					case "ibag":
						for (let i = 0, count = chunk.size / HydraIbag.SizeInFile | 0; i < count; i++) this.ibags.push(new HydraIbag(readable));
						break;
					case "imod":
						for (let i = 0, count = chunk.size / HydraImod.SizeInFile | 0; i < count; i++) this.imods.push(new HydraImod(readable));
						break;
					case "igen":
						for (let i = 0, count = chunk.size / HydraIgen.SizeInFile | 0; i < count; i++) this.igens.push(new HydraIgen(readable));
						break;
					case "shdr":
						for (let i = 0, count = chunk.size / HydraShdr.SizeInFile | 0; i < count; i++) this.sHdrs.push(new HydraShdr(readable));
						break;
					default:
						readable.position += chunk.size;
						break;
				}
				else if (chunkFastList.id === "sdta") while (RiffChunk.load(chunkFastList, chunk, readable)) switch (chunk.id) {
					case "smpl":
						this.sampleData = new Uint8Array(chunk.size);
						readable.read(this.sampleData, 0, chunk.size);
						break;
					default:
						readable.position += chunk.size;
						break;
				}
				else readable.position += chunkFastList.size;
			}
		}
	};
	/**
	* @internal
	*/
	var HydraIbag = class {
		static SizeInFile = 4;
		instGenNdx;
		instModNdx;
		constructor(reader) {
			this.instGenNdx = IOHelper.readUInt16LE(reader);
			this.instModNdx = IOHelper.readUInt16LE(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraImod = class {
		static SizeInFile = 10;
		modSrcOper;
		modDestOper;
		modAmount;
		modAmtSrcOper;
		modTransOper;
		constructor(reader) {
			this.modSrcOper = IOHelper.readUInt16LE(reader);
			this.modDestOper = IOHelper.readUInt16LE(reader);
			this.modAmount = IOHelper.readInt16LE(reader);
			this.modAmtSrcOper = IOHelper.readUInt16LE(reader);
			this.modTransOper = IOHelper.readUInt16LE(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraIgen = class {
		static SizeInFile = 4;
		genOper;
		genAmount;
		constructor(reader) {
			this.genOper = IOHelper.readUInt16LE(reader);
			this.genAmount = new HydraGenAmount(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraInst = class {
		static SizeInFile = 22;
		instName;
		instBagNdx;
		constructor(reader) {
			this.instName = IOHelper.read8BitStringLength(reader, 20);
			this.instBagNdx = IOHelper.readUInt16LE(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraPbag = class {
		static SizeInFile = 4;
		genNdx;
		modNdx;
		constructor(reader) {
			this.genNdx = IOHelper.readUInt16LE(reader);
			this.modNdx = IOHelper.readUInt16LE(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraPgen = class {
		static SizeInFile = 4;
		static GenInstrument = 41;
		static GenKeyRange = 43;
		static GenVelRange = 44;
		static GenSampleId = 53;
		genOper;
		genAmount;
		constructor(reader) {
			this.genOper = IOHelper.readUInt16LE(reader);
			this.genAmount = new HydraGenAmount(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraPhdr = class {
		static SizeInFile = 38;
		presetName;
		preset;
		bank;
		presetBagNdx;
		library;
		genre;
		morphology;
		constructor(reader) {
			this.presetName = IOHelper.read8BitStringLength(reader, 20);
			this.preset = IOHelper.readUInt16LE(reader);
			this.bank = IOHelper.readUInt16LE(reader);
			this.presetBagNdx = IOHelper.readUInt16LE(reader);
			this.library = IOHelper.readUInt32LE(reader);
			this.genre = IOHelper.readUInt32LE(reader);
			this.morphology = IOHelper.readUInt32LE(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraPmod = class {
		static SizeInFile = 10;
		modSrcOper;
		modDestOper;
		modAmount;
		modAmtSrcOper;
		modTransOper;
		constructor(reader) {
			this.modSrcOper = IOHelper.readUInt16LE(reader);
			this.modDestOper = IOHelper.readUInt16LE(reader);
			this.modAmount = IOHelper.readUInt16LE(reader);
			this.modAmtSrcOper = IOHelper.readUInt16LE(reader);
			this.modTransOper = IOHelper.readUInt16LE(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraShdr = class {
		static SizeInFile = 46;
		sampleName;
		start;
		end;
		startLoop;
		endLoop;
		sampleRate;
		originalPitch;
		pitchCorrection;
		sampleLink;
		sampleType;
		constructor(reader) {
			this.sampleName = IOHelper.read8BitStringLength(reader, 20);
			this.start = IOHelper.readUInt32LE(reader);
			this.end = IOHelper.readUInt32LE(reader);
			this.startLoop = IOHelper.readUInt32LE(reader);
			this.endLoop = IOHelper.readUInt32LE(reader);
			this.sampleRate = IOHelper.readUInt32LE(reader);
			this.originalPitch = reader.readByte();
			this.pitchCorrection = IOHelper.readSInt8(reader);
			this.sampleLink = IOHelper.readUInt16LE(reader);
			this.sampleType = IOHelper.readUInt16LE(reader);
		}
	};
	/**
	* @internal
	*/
	var HydraGenAmount = class {
		wordAmount;
		get shortAmount() {
			return TypeConversions.uint16ToInt16(this.wordAmount);
		}
		get lowByteAmount() {
			return this.wordAmount & 255;
		}
		get highByteAmount() {
			return (this.wordAmount & 65280) >> 8 & 255;
		}
		constructor(reader) {
			this.wordAmount = IOHelper.readUInt16LE(reader);
		}
	};
	//#endregion
	//#region src/synth/synthesis/Channel.ts
	/**
	* @internal
	*/
	var Channel = class {
		presetIndex = 0;
		bank = 0;
		pitchWheel = 0;
		perNotePitchWheel = /* @__PURE__ */ new Map();
		midiPan = 0;
		midiVolume = 0;
		midiExpression = 0;
		midiRpn = 0;
		midiData = 0;
		panOffset = 0;
		gainDb = 0;
		pitchRange = 0;
		tuning = 0;
		mixVolume = 0;
		mute = false;
		solo = false;
	};
	//#endregion
	//#region src/synth/synthesis/Channels.ts
	/**
	* @internal
	*/
	var Channels = class {
		activeChannel = 0;
		channelList = [];
		setupVoice(tinySoundFont, voice) {
			const c = this.channelList[this.activeChannel];
			const newpan = voice.region.pan + c.panOffset;
			voice.playingChannel = this.activeChannel;
			voice.mixVolume = c.mixVolume;
			voice.noteGainDb += c.gainDb;
			voice.updatePitchRatio(c, tinySoundFont.outSampleRate);
			if (newpan <= -.5) {
				voice.panFactorLeft = 1;
				voice.panFactorRight = 0;
			} else if (newpan >= .5) {
				voice.panFactorLeft = 0;
				voice.panFactorRight = 1;
			} else {
				voice.panFactorLeft = Math.sqrt(.5 - newpan);
				voice.panFactorRight = Math.sqrt(.5 + newpan);
			}
		}
	};
	//#endregion
	//#region src/synth/synthesis/LoopMode.ts
	/**
	* @internal
	*/
	var LoopMode = /* @__PURE__ */ function(LoopMode) {
		LoopMode[LoopMode["None"] = 0] = "None";
		LoopMode[LoopMode["Continuous"] = 1] = "Continuous";
		LoopMode[LoopMode["Sustain"] = 2] = "Sustain";
		return LoopMode;
	}({});
	//#endregion
	//#region src/synth/synthesis/OutputMode.ts
	/**
	* Supported output modes by the render methods
	* @internal
	*/
	var OutputMode = /* @__PURE__ */ function(OutputMode) {
		/**
		* Two channels with single left/right samples one after another
		*/
		OutputMode[OutputMode["StereoInterleaved"] = 0] = "StereoInterleaved";
		/**
		* Two channels with all samples for the left channel first then right
		*/
		OutputMode[OutputMode["StereoUnweaved"] = 1] = "StereoUnweaved";
		/**
		* A single channel (stereo instruments are mixed into center)
		*/
		OutputMode[OutputMode["Mono"] = 2] = "Mono";
		return OutputMode;
	}({});
	//#endregion
	//#region src/synth/synthesis/Preset.ts
	/**
	* @internal
	*/
	var Preset = class {
		name = "";
		presetNumber = 0;
		bank = 0;
		regions = null;
	};
	//#endregion
	//#region src/synth/SynthHelper.ts
	/**
	* @internal
	*/
	var SynthHelper = class {
		static timecents2Secs(timecents) {
			return Math.pow(2, timecents / 1200);
		}
		static decibelsToGain(db) {
			return db > -100 ? Math.pow(10, db * .05) : 0;
		}
		static gainToDecibels(gain) {
			return gain <= 1e-5 ? -100 : 20 * Math.log10(gain);
		}
		static cents2Hertz(cents) {
			return 8.176 * Math.pow(2, cents / 1200);
		}
	};
	//#endregion
	//#region src/synth/synthesis/Envelope.ts
	/**
	* @internal
	*/
	var Envelope = class {
		delay = 0;
		attack = 0;
		hold = 0;
		decay = 0;
		sustain = 0;
		release = 0;
		keynumToHold = 0;
		keynumToDecay = 0;
		constructor(other) {
			if (other) {
				this.delay = other.delay;
				this.attack = other.attack;
				this.hold = other.hold;
				this.decay = other.decay;
				this.sustain = other.sustain;
				this.release = other.release;
				this.keynumToHold = other.keynumToHold;
				this.keynumToDecay = other.keynumToDecay;
			}
		}
		clear() {
			this.delay = 0;
			this.attack = 0;
			this.hold = 0;
			this.decay = 0;
			this.sustain = 0;
			this.release = 0;
			this.keynumToHold = 0;
			this.keynumToDecay = 0;
		}
		envToSecs(sustainIsGain) {
			this.delay = this.delay < -11950 ? 0 : SynthHelper.timecents2Secs(this.delay);
			this.attack = this.attack < -11950 ? 0 : SynthHelper.timecents2Secs(this.attack);
			this.release = this.release < -11950 ? 0 : SynthHelper.timecents2Secs(this.release);
			if (this.keynumToHold === 0) this.hold = this.hold < -11950 ? 0 : SynthHelper.timecents2Secs(this.hold);
			if (this.keynumToDecay === 0) this.decay = this.decay < -11950 ? 0 : SynthHelper.timecents2Secs(this.decay);
			if (this.sustain < 0) this.sustain = 0;
			else if (sustainIsGain) this.sustain = SynthHelper.decibelsToGain(-this.sustain / 10);
			else this.sustain = 1 - this.sustain / 1e3;
		}
	};
	//#endregion
	//#region src/synth/synthesis/Region.ts
	/**
	* @internal
	*/
	var Region = class Region {
		static _noSamples = new Float32Array(0);
		loopMode = LoopMode.None;
		samples = Region._noSamples;
		sampleRate = 0;
		loKey = 0;
		hiKey = 0;
		loVel = 0;
		hiVel = 0;
		group = 0;
		offset = 0;
		end = 0;
		loopStart = 0;
		loopEnd = 0;
		transpose = 0;
		tune = 0;
		pitchKeyCenter = 0;
		pitchKeyTrack = 0;
		attenuation = 0;
		pan = 0;
		ampEnv = new Envelope();
		modEnv = new Envelope();
		initialFilterQ = 0;
		initialFilterFc = 0;
		modEnvToPitch = 0;
		modEnvToFilterFc = 0;
		modLfoToFilterFc = 0;
		modLfoToVolume = 0;
		delayModLFO = 0;
		freqModLFO = 0;
		modLfoToPitch = 0;
		delayVibLFO = 0;
		freqVibLFO = 0;
		vibLfoToPitch = 0;
		constructor(other) {
			if (other) {
				this.loopMode = other.loopMode;
				this.samples = other.samples;
				this.sampleRate = other.sampleRate;
				this.loKey = other.loKey;
				this.hiKey = other.hiKey;
				this.loVel = other.loVel;
				this.hiVel = other.hiVel;
				this.group = other.group;
				this.offset = other.offset;
				this.end = other.end;
				this.loopStart = other.loopStart;
				this.loopEnd = other.loopEnd;
				this.transpose = other.transpose;
				this.tune = other.tune;
				this.pitchKeyCenter = other.pitchKeyCenter;
				this.pitchKeyTrack = other.pitchKeyTrack;
				this.attenuation = other.attenuation;
				this.pan = other.pan;
				this.ampEnv = new Envelope(other.ampEnv);
				this.modEnv = new Envelope(other.modEnv);
				this.initialFilterQ = other.initialFilterQ;
				this.initialFilterFc = other.initialFilterFc;
				this.modEnvToPitch = other.modEnvToPitch;
				this.modEnvToFilterFc = other.modEnvToFilterFc;
				this.modLfoToFilterFc = other.modLfoToFilterFc;
				this.modLfoToVolume = other.modLfoToVolume;
				this.delayModLFO = other.delayModLFO;
				this.freqModLFO = other.freqModLFO;
				this.modLfoToPitch = other.modLfoToPitch;
				this.delayVibLFO = other.delayVibLFO;
				this.freqVibLFO = other.freqVibLFO;
				this.vibLfoToPitch = other.vibLfoToPitch;
			}
		}
		clear(forRelative) {
			this.loopMode = LoopMode.None;
			this.samples = Region._noSamples;
			this.sampleRate = 0;
			this.loKey = 0;
			this.hiKey = 0;
			this.loVel = 0;
			this.hiVel = 0;
			this.group = 0;
			this.offset = 0;
			this.end = 0;
			this.loopStart = 0;
			this.loopEnd = 0;
			this.transpose = 0;
			this.tune = 0;
			this.pitchKeyCenter = 0;
			this.pitchKeyTrack = 0;
			this.attenuation = 0;
			this.pan = 0;
			this.ampEnv.clear();
			this.modEnv.clear();
			this.initialFilterQ = 0;
			this.initialFilterFc = 0;
			this.modEnvToPitch = 0;
			this.modEnvToFilterFc = 0;
			this.modLfoToFilterFc = 0;
			this.modLfoToVolume = 0;
			this.delayModLFO = 0;
			this.freqModLFO = 0;
			this.modLfoToPitch = 0;
			this.delayVibLFO = 0;
			this.freqVibLFO = 0;
			this.vibLfoToPitch = 0;
			this.hiKey = 127;
			this.hiVel = 127;
			this.pitchKeyCenter = 60;
			if (forRelative) return;
			this.pitchKeyTrack = 100;
			this.pitchKeyCenter = -1;
			this.ampEnv.delay = -12e3;
			this.ampEnv.attack = -12e3;
			this.ampEnv.hold = -12e3;
			this.ampEnv.decay = -12e3;
			this.ampEnv.release = -12e3;
			this.modEnv.delay = -12e3;
			this.modEnv.attack = -12e3;
			this.modEnv.hold = -12e3;
			this.modEnv.decay = -12e3;
			this.modEnv.release = -12e3;
			this.initialFilterFc = 13500;
			this.delayModLFO = -12e3;
			this.delayVibLFO = -12e3;
		}
		operator(genOper, amount) {
			switch (genOper) {
				case 0:
					this.offset += TypeConversions.int16ToUint32(amount.shortAmount);
					break;
				case 1:
					this.end += TypeConversions.int16ToUint32(amount.shortAmount);
					break;
				case 2:
					this.loopStart += TypeConversions.int16ToUint32(amount.shortAmount);
					break;
				case 3:
					this.loopEnd += TypeConversions.int16ToUint32(amount.shortAmount);
					break;
				case 4:
					this.offset += TypeConversions.int16ToUint32(amount.shortAmount) * 32768;
					break;
				case 5:
					this.modLfoToPitch = amount.shortAmount;
					break;
				case 6:
					this.vibLfoToPitch = amount.shortAmount;
					break;
				case 7:
					this.modEnvToPitch = amount.shortAmount;
					break;
				case 8:
					this.initialFilterFc = amount.shortAmount;
					break;
				case 9:
					this.initialFilterQ = amount.shortAmount;
					break;
				case 10:
					this.modLfoToFilterFc = amount.shortAmount;
					break;
				case 11:
					this.modEnvToFilterFc = amount.shortAmount;
					break;
				case 12:
					this.end += TypeConversions.int16ToUint32(amount.shortAmount) * 32768;
					break;
				case 13:
					this.modLfoToVolume = amount.shortAmount;
					break;
				case 17:
					this.pan = amount.shortAmount / 1e3;
					break;
				case 21:
					this.delayModLFO = amount.shortAmount;
					break;
				case 22:
					this.freqModLFO = amount.shortAmount;
					break;
				case 23:
					this.delayVibLFO = amount.shortAmount;
					break;
				case 24:
					this.freqVibLFO = amount.shortAmount;
					break;
				case 25:
					this.modEnv.delay = amount.shortAmount;
					break;
				case 26:
					this.modEnv.attack = amount.shortAmount;
					break;
				case 27:
					this.modEnv.hold = amount.shortAmount;
					break;
				case 28:
					this.modEnv.decay = amount.shortAmount;
					break;
				case 29:
					this.modEnv.sustain = amount.shortAmount;
					break;
				case 30:
					this.modEnv.release = amount.shortAmount;
					break;
				case 31:
					this.modEnv.keynumToHold = amount.shortAmount;
					break;
				case 32:
					this.modEnv.keynumToDecay = amount.shortAmount;
					break;
				case 33:
					this.ampEnv.delay = amount.shortAmount;
					break;
				case 34:
					this.ampEnv.attack = amount.shortAmount;
					break;
				case 35:
					this.ampEnv.hold = amount.shortAmount;
					break;
				case 36:
					this.ampEnv.decay = amount.shortAmount;
					break;
				case 37:
					this.ampEnv.sustain = amount.shortAmount;
					break;
				case 38:
					this.ampEnv.release = amount.shortAmount;
					break;
				case 39:
					this.ampEnv.keynumToHold = amount.shortAmount;
					break;
				case 40:
					this.ampEnv.keynumToDecay = amount.shortAmount;
					break;
				case 43:
					this.loKey = amount.lowByteAmount;
					this.hiKey = amount.highByteAmount;
					break;
				case 44:
					this.loVel = amount.lowByteAmount;
					this.hiVel = amount.highByteAmount;
					break;
				case 45:
					this.loopStart += TypeConversions.int16ToUint32(amount.shortAmount) * 32768;
					break;
				case 48:
					this.attenuation += amount.shortAmount * .1;
					break;
				case 50:
					this.loopEnd += TypeConversions.int16ToUint32(amount.shortAmount) * 32768;
					break;
				case 51:
					this.transpose += amount.shortAmount;
					break;
				case 52:
					this.tune += amount.shortAmount;
					break;
				case 54:
					this.loopMode = (amount.wordAmount & 3) === 3 ? LoopMode.Sustain : (amount.wordAmount & 3) === 1 ? LoopMode.Continuous : LoopMode.None;
					break;
				case 56:
					this.pitchKeyTrack = amount.shortAmount;
					break;
				case 57:
					this.group = amount.wordAmount;
					break;
				case 58:
					this.pitchKeyCenter = amount.shortAmount;
					break;
			}
		}
	};
	//#endregion
	//#region src/synth/synthesis/VoiceEnvelope.ts
	/**
	* @internal
	*/
	var VoiceEnvelopeSegment = /* @__PURE__ */ function(VoiceEnvelopeSegment) {
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["None"] = 0] = "None";
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["Delay"] = 1] = "Delay";
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["Attack"] = 2] = "Attack";
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["Hold"] = 3] = "Hold";
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["Decay"] = 4] = "Decay";
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["Sustain"] = 5] = "Sustain";
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["Release"] = 6] = "Release";
		VoiceEnvelopeSegment[VoiceEnvelopeSegment["Done"] = 7] = "Done";
		return VoiceEnvelopeSegment;
	}({});
	/**
	* @internal
	*/
	var VoiceEnvelope = class VoiceEnvelope {
		static _fastReleaseTime = .01;
		level = 0;
		slope = 0;
		samplesUntilNextSegment = 0;
		segment = 0;
		midiVelocity = 0;
		parameters = null;
		segmentIsExponential = false;
		isAmpEnv = false;
		nextSegment(activeSegment, outSampleRate) {
			if (!this.parameters) return;
			while (true) switch (activeSegment) {
				case 0:
					this.samplesUntilNextSegment = this.parameters.delay * outSampleRate | 0;
					if (this.samplesUntilNextSegment > 0) {
						this.segment = 1;
						this.segmentIsExponential = false;
						this.level = 0;
						this.slope = 0;
						return;
					}
					activeSegment = 1;
					break;
				case 1:
					this.samplesUntilNextSegment = this.parameters.attack * outSampleRate | 0;
					if (this.samplesUntilNextSegment > 0) {
						if (!this.isAmpEnv) this.samplesUntilNextSegment = this.parameters.attack * ((145 - this.midiVelocity) / 144) * outSampleRate | 0;
						this.segment = 2;
						this.segmentIsExponential = false;
						this.level = 0;
						this.slope = 1 / this.samplesUntilNextSegment;
						return;
					}
					activeSegment = 2;
					break;
				case 2:
					this.samplesUntilNextSegment = this.parameters.hold * outSampleRate | 0;
					if (this.samplesUntilNextSegment > 0) {
						this.segment = 3;
						this.segmentIsExponential = false;
						this.level = 1;
						this.slope = 0;
						return;
					}
					activeSegment = 3;
					break;
				case 3:
					this.samplesUntilNextSegment = this.parameters.decay * outSampleRate | 0;
					if (this.samplesUntilNextSegment > 0) {
						this.segment = 4;
						this.level = 1;
						if (this.isAmpEnv) {
							const mysterySlope = -9.226 / this.samplesUntilNextSegment;
							this.slope = Math.exp(mysterySlope);
							this.segmentIsExponential = true;
							if (this.parameters.sustain > 0) this.samplesUntilNextSegment = Math.log(this.parameters.sustain) / mysterySlope | 0;
						} else {
							this.slope = -1 / this.samplesUntilNextSegment;
							this.samplesUntilNextSegment = this.parameters.decay * (1 - this.parameters.sustain) * outSampleRate | 0;
							this.segmentIsExponential = false;
						}
						return;
					}
					activeSegment = 4;
					break;
				case 4:
					this.segment = 5;
					this.level = this.parameters.sustain;
					this.slope = 0;
					this.samplesUntilNextSegment = 2147483647;
					this.segmentIsExponential = false;
					return;
				case 5:
					this.segment = 6;
					this.samplesUntilNextSegment = (this.parameters.release <= 0 ? VoiceEnvelope._fastReleaseTime : this.parameters.release) * outSampleRate | 0;
					if (this.isAmpEnv) {
						const mysterySlope = -9.226 / this.samplesUntilNextSegment;
						this.slope = Math.exp(mysterySlope);
						this.segmentIsExponential = true;
					} else {
						this.slope = -this.level / this.samplesUntilNextSegment;
						this.segmentIsExponential = false;
					}
					return;
				default:
					this.segment = 7;
					this.segmentIsExponential = false;
					this.level = 0;
					this.slope = 0;
					this.samplesUntilNextSegment = 134217727;
					return;
			}
		}
		setup(newParameters, midiNoteNumber, midiVelocity, isAmpEnv, outSampleRate) {
			this.parameters = new Envelope(newParameters);
			if (this.parameters.keynumToHold > 0) {
				this.parameters.hold += this.parameters.keynumToHold * (60 - midiNoteNumber);
				this.parameters.hold = this.parameters.hold < -1e4 ? 0 : SynthHelper.timecents2Secs(this.parameters.hold);
			}
			if (this.parameters.keynumToDecay > 0) {
				this.parameters.decay += this.parameters.keynumToDecay * (60 - midiNoteNumber);
				this.parameters.decay = this.parameters.decay < -1e4 ? 0 : SynthHelper.timecents2Secs(this.parameters.decay);
			}
			this.midiVelocity = midiVelocity | 0;
			this.isAmpEnv = isAmpEnv;
			this.nextSegment(0, outSampleRate);
		}
		process(numSamples, outSampleRate) {
			if (this.slope > 0) if (this.segmentIsExponential) this.level *= Math.pow(this.slope, numSamples);
			else this.level += this.slope * numSamples;
			this.samplesUntilNextSegment -= numSamples;
			if (this.samplesUntilNextSegment <= 0) this.nextSegment(this.segment, outSampleRate);
		}
	};
	//#endregion
	//#region src/synth/synthesis/VoiceLfo.ts
	/**
	* @internal
	*/
	var VoiceLfo = class {
		samplesUntil = 0;
		level = 0;
		delta = 0;
		setup(delay, freqCents, outSampleRate) {
			this.samplesUntil = delay * outSampleRate | 0;
			this.delta = 4 * SynthHelper.cents2Hertz(freqCents) / outSampleRate;
			this.level = 0;
		}
		process(blockSamples) {
			if (this.samplesUntil > blockSamples) {
				this.samplesUntil -= blockSamples;
				return;
			}
			this.level += this.delta * blockSamples;
			if (this.level > 1) {
				this.delta = -this.delta;
				this.level = 2 - this.level;
			} else if (this.level < -1) {
				this.delta = -this.delta;
				this.level = -2 - this.level;
			}
		}
	};
	//#endregion
	//#region src/synth/synthesis/VoiceLowPass.ts
	/**
	* @internal
	*/
	var VoiceLowPass = class {
		qInv = 0;
		a0 = 0;
		a1 = 0;
		b1 = 0;
		b2 = 0;
		z1 = 0;
		z2 = 0;
		active = false;
		constructor(other) {
			if (other) {
				this.qInv = other.qInv;
				this.a0 = other.a0;
				this.a1 = other.a1;
				this.b1 = other.b1;
				this.b2 = other.b2;
				this.z1 = other.z1;
				this.z2 = other.z2;
				this.active = other.active;
			}
		}
		setup(fc) {
			const k = Math.tan(Math.PI * fc);
			const kk = k * k;
			const norm = 1 / (1 + k * this.qInv + kk);
			this.a0 = kk * norm;
			this.a1 = 2 * this.a0;
			this.b1 = 2 * (kk - 1) * norm;
			this.b2 = (1 - k * this.qInv + kk) * norm;
		}
		process(input) {
			const output = input * this.a0 + this.z1;
			this.z1 = input * this.a1 + this.z2 - this.b1 * output;
			this.z2 = input * this.a0 - this.b2 * output;
			return output;
		}
	};
	//#endregion
	//#region src/synth/synthesis/Voice.ts
	/**
	* @internal
	*/
	var Voice = class Voice {
		/**
		* The lower this block size is the more accurate the effects are.
		* Increasing the value significantly lowers the CPU usage of the voice rendering.
		* If LFO affects the low-pass filter it can be hearable even as low as 8.
		*/
		static renderEffectSampleBlock = SynthConstants.MicroBufferSize;
		playingPreset = 0;
		playingKey = 0;
		playingChannel = 0;
		region = null;
		pitchInputTimecents = 0;
		pitchOutputFactor = 0;
		sourceSamplePosition = 0;
		noteGainDb = 0;
		panFactorLeft = 0;
		panFactorRight = 0;
		playIndex = 0;
		loopStart = 0;
		loopEnd = 0;
		ampEnv = new VoiceEnvelope();
		modEnv = new VoiceEnvelope();
		lowPass = new VoiceLowPass();
		modLfo = new VoiceLfo();
		vibLfo = new VoiceLfo();
		mixVolume = 0;
		mute = false;
		updatePitchRatio(c, outSampleRate) {
			let pitchWheel = c.pitchWheel;
			if (c.perNotePitchWheel.has(this.playingKey)) pitchWheel += c.perNotePitchWheel.get(this.playingKey) - 8192;
			const pitchShift = pitchWheel === 8192 ? c.tuning : pitchWheel / 16383 * c.pitchRange * 2 - c.pitchRange + c.tuning;
			this.calcPitchRatio(pitchShift, outSampleRate);
		}
		calcPitchRatio(pitchShift, outSampleRate) {
			if (!this.region) return;
			const note = this.playingKey + this.region.transpose + this.region.tune / 100;
			let adjustedPitch = this.region.pitchKeyCenter + (note - this.region.pitchKeyCenter) * (this.region.pitchKeyTrack / 100);
			if (pitchShift !== 0) adjustedPitch += pitchShift;
			this.pitchInputTimecents = adjustedPitch * 100;
			this.pitchOutputFactor = this.region.sampleRate / (SynthHelper.timecents2Secs(this.region.pitchKeyCenter * 100) * outSampleRate);
		}
		end(outSampleRate) {
			if (!this.region) return;
			this.ampEnv.nextSegment(VoiceEnvelopeSegment.Sustain, outSampleRate);
			this.modEnv.nextSegment(VoiceEnvelopeSegment.Sustain, outSampleRate);
			if (this.region.loopMode === LoopMode.Sustain) this.loopEnd = this.loopStart;
		}
		endQuick(outSampleRate) {
			this.ampEnv.parameters.release = 0;
			this.ampEnv.nextSegment(VoiceEnvelopeSegment.Sustain, outSampleRate);
			this.modEnv.parameters.release = 0;
			this.modEnv.nextSegment(VoiceEnvelopeSegment.Sustain, outSampleRate);
		}
		render(f, outputBuffer, offset, numSamples, isMuted) {
			if (!this.region) return;
			const region = this.region;
			const input = region.samples;
			let outL = 0;
			let outR = f.outputMode === OutputMode.StereoUnweaved ? numSamples : -1;
			const updateModEnv = region.modEnvToPitch !== 0 || region.modEnvToFilterFc !== 0;
			const updateModLFO = this.modLfo.delta > 0 && (region.modLfoToPitch !== 0 || region.modLfoToFilterFc !== 0 || region.modLfoToVolume !== 0);
			const updateVibLFO = this.vibLfo.delta > 0 && region.vibLfoToPitch !== 0;
			const isLooping = this.loopStart < this.loopEnd;
			const tmpLoopStart = this.loopStart;
			const tmpLoopEnd = this.loopEnd;
			const tmpSampleEndDbl = region.end;
			const tmpLoopEndDbl = tmpLoopEnd + 1;
			let tmpSourceSamplePosition = this.sourceSamplePosition;
			const tmpLowpass = new VoiceLowPass(this.lowPass);
			const dynamicLowpass = region.modLfoToFilterFc !== 0 || region.modEnvToFilterFc !== 0;
			let tmpSampleRate = 0;
			let tmpInitialFilterFc = 0;
			let tmpModLfoToFilterFc = 0;
			let tmpModEnvToFilterFc = 0;
			const dynamicPitchRatio = region.modLfoToPitch !== 0 || region.modEnvToPitch !== 0 || region.vibLfoToPitch !== 0;
			let pitchRatio = 0;
			let tmpModLfoToPitch = 0;
			let tmpVibLfoToPitch = 0;
			let tmpModEnvToPitch = 0;
			const dynamicGain = region.modLfoToVolume !== 0;
			let noteGain = 0;
			let tmpModLfoToVolume = 0;
			if (dynamicLowpass) {
				tmpSampleRate = f.outSampleRate;
				tmpInitialFilterFc = region.initialFilterFc;
				tmpModLfoToFilterFc = region.modLfoToFilterFc;
				tmpModEnvToFilterFc = region.modEnvToFilterFc;
			} else {
				tmpSampleRate = 0;
				tmpInitialFilterFc = 0;
				tmpModLfoToFilterFc = 0;
				tmpModEnvToFilterFc = 0;
			}
			if (dynamicPitchRatio) {
				pitchRatio = 0;
				tmpModLfoToPitch = region.modLfoToPitch;
				tmpVibLfoToPitch = region.vibLfoToPitch;
				tmpModEnvToPitch = region.modEnvToPitch;
			} else {
				pitchRatio = SynthHelper.timecents2Secs(this.pitchInputTimecents) * this.pitchOutputFactor;
				tmpModLfoToPitch = 0;
				tmpVibLfoToPitch = 0;
				tmpModEnvToPitch = 0;
			}
			if (dynamicGain) tmpModLfoToVolume = region.modLfoToVolume * .1;
			else {
				noteGain = SynthHelper.decibelsToGain(this.noteGainDb);
				tmpModLfoToVolume = 0;
			}
			while (numSamples > 0) {
				let gainMono;
				let gainLeft;
				let gainRight = 0;
				let blockSamples = numSamples > Voice.renderEffectSampleBlock ? Voice.renderEffectSampleBlock : numSamples;
				numSamples -= blockSamples;
				if (dynamicLowpass) {
					const fres = tmpInitialFilterFc + this.modLfo.level * tmpModLfoToFilterFc + this.modEnv.level * tmpModEnvToFilterFc;
					tmpLowpass.active = fres <= 13500;
					if (tmpLowpass.active) tmpLowpass.setup(SynthHelper.cents2Hertz(fres) / tmpSampleRate);
				}
				if (dynamicPitchRatio) pitchRatio = SynthHelper.timecents2Secs(this.pitchInputTimecents + (this.modLfo.level * tmpModLfoToPitch + this.vibLfo.level * tmpVibLfoToPitch + this.modEnv.level * tmpModEnvToPitch)) * this.pitchOutputFactor;
				if (dynamicGain) noteGain = SynthHelper.decibelsToGain(this.noteGainDb + this.modLfo.level * tmpModLfoToVolume);
				this.ampEnv.process(blockSamples, f.outSampleRate);
				if (updateModEnv) this.modEnv.process(blockSamples, f.outSampleRate);
				gainMono = noteGain * this.ampEnv.level;
				if (isMuted) gainMono = 0;
				else gainMono *= this.mixVolume;
				if (updateModLFO) this.modLfo.process(blockSamples);
				if (updateVibLFO) this.vibLfo.process(blockSamples);
				switch (f.outputMode) {
					case OutputMode.StereoInterleaved:
						gainLeft = gainMono * this.panFactorLeft;
						gainRight = gainMono * this.panFactorRight;
						while (blockSamples-- > 0 && tmpSourceSamplePosition < tmpSampleEndDbl) {
							const pos = tmpSourceSamplePosition | 0;
							const nextPos = pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1;
							const alpha = tmpSourceSamplePosition - pos;
							let value = input[pos] * (1 - alpha) + input[nextPos] * alpha;
							if (tmpLowpass.active) value = tmpLowpass.process(value);
							outputBuffer[offset + outL] += value * gainLeft;
							outL++;
							outputBuffer[offset + outL] += value * gainRight;
							outL++;
							tmpSourceSamplePosition += pitchRatio;
							if (tmpSourceSamplePosition >= tmpLoopEndDbl && isLooping) tmpSourceSamplePosition -= tmpLoopEnd - tmpLoopStart + 1;
						}
						break;
					case OutputMode.StereoUnweaved:
						gainLeft = gainMono * this.panFactorLeft;
						gainRight = gainMono * this.panFactorRight;
						while (blockSamples-- > 0 && tmpSourceSamplePosition < tmpSampleEndDbl) {
							const pos = tmpSourceSamplePosition | 0;
							const nextPos = pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1;
							const alpha = tmpSourceSamplePosition - pos;
							let value = input[pos] * (1 - alpha) + input[nextPos] * alpha;
							if (tmpLowpass.active) value = tmpLowpass.process(value);
							outputBuffer[offset + outL] += value * gainLeft;
							outL++;
							outputBuffer[offset + outR] += value * gainRight;
							outR++;
							tmpSourceSamplePosition += pitchRatio;
							if (tmpSourceSamplePosition >= tmpLoopEndDbl && isLooping) tmpSourceSamplePosition -= tmpLoopEnd - tmpLoopStart + 1;
						}
						break;
					case OutputMode.Mono:
						while (blockSamples-- > 0 && tmpSourceSamplePosition < tmpSampleEndDbl) {
							const pos = tmpSourceSamplePosition | 0;
							const nextPos = pos >= tmpLoopEnd && isLooping ? tmpLoopStart : pos + 1;
							const alpha = tmpSourceSamplePosition - pos;
							let value = input[pos] * (1 - alpha) + input[nextPos] * alpha;
							if (tmpLowpass.active) value = tmpLowpass.process(value);
							outputBuffer[offset + outL] = value * gainMono;
							outL++;
							tmpSourceSamplePosition += pitchRatio;
							if (tmpSourceSamplePosition >= tmpLoopEndDbl && isLooping) tmpSourceSamplePosition -= tmpLoopEnd - tmpLoopStart + 1;
						}
						break;
				}
				const inaudible = this.ampEnv.segment === VoiceEnvelopeSegment.Release && Math.abs(gainMono) < SynthConstants.AudibleLevelThreshold;
				if (tmpSourceSamplePosition >= tmpSampleEndDbl || this.ampEnv.segment === VoiceEnvelopeSegment.Done || inaudible) {
					this.kill();
					return;
				}
			}
			this.sourceSamplePosition = tmpSourceSamplePosition;
			if (tmpLowpass.active || dynamicLowpass) this.lowPass = tmpLowpass;
		}
		kill() {
			this.playingPreset = -1;
		}
	};
	//#endregion
	//#region src/midi/ControllerType.ts
	/**
	* Lists all midi controllers.
	* @public
	*/
	var ControllerType = /* @__PURE__ */ function(ControllerType) {
		/**
		* Bank Select. MSB
		*/
		ControllerType[ControllerType["BankSelectCoarse"] = 0] = "BankSelectCoarse";
		/**
		* Modulation wheel or lever MSB
		*/
		ControllerType[ControllerType["ModulationCoarse"] = 1] = "ModulationCoarse";
		/**
		* Data entry MSB
		*/
		ControllerType[ControllerType["DataEntryCoarse"] = 6] = "DataEntryCoarse";
		/**
		* Channel Volume MSB
		*/
		ControllerType[ControllerType["VolumeCoarse"] = 7] = "VolumeCoarse";
		/**
		* Pan MSB
		*/
		ControllerType[ControllerType["PanCoarse"] = 10] = "PanCoarse";
		/**
		* Expression Controller MSB
		*/
		ControllerType[ControllerType["ExpressionControllerCoarse"] = 11] = "ExpressionControllerCoarse";
		ControllerType[ControllerType["BankSelectFine"] = 32] = "BankSelectFine";
		/**
		* Modulation wheel or level LSB
		*/
		ControllerType[ControllerType["ModulationFine"] = 33] = "ModulationFine";
		/**
		* Data Entry LSB
		*/
		ControllerType[ControllerType["DataEntryFine"] = 38] = "DataEntryFine";
		/**
		* Channel Volume LSB
		*/
		ControllerType[ControllerType["VolumeFine"] = 39] = "VolumeFine";
		/**
		* Pan LSB
		*/
		ControllerType[ControllerType["PanFine"] = 42] = "PanFine";
		/**
		* Expression controller LSB
		*/
		ControllerType[ControllerType["ExpressionControllerFine"] = 43] = "ExpressionControllerFine";
		/**
		* Damper pedal (sustain)
		*/
		ControllerType[ControllerType["HoldPedal"] = 64] = "HoldPedal";
		/**
		* Legato Footswitch
		*/
		ControllerType[ControllerType["LegatoPedal"] = 68] = "LegatoPedal";
		/**
		* Non-Registered Parameter Number LSB
		*/
		ControllerType[ControllerType["NonRegisteredParameterFine"] = 98] = "NonRegisteredParameterFine";
		/**
		* Non-Registered Parameter Number MSB
		*/
		ControllerType[ControllerType["NonRegisteredParameterCourse"] = 99] = "NonRegisteredParameterCourse";
		/**
		* Registered Parameter Number LSB
		*/
		ControllerType[ControllerType["RegisteredParameterFine"] = 100] = "RegisteredParameterFine";
		/**
		* Registered Parameter Number MSB
		*/
		ControllerType[ControllerType["RegisteredParameterCourse"] = 101] = "RegisteredParameterCourse";
		ControllerType[ControllerType["AllSoundOff"] = 120] = "AllSoundOff";
		/**
		* Reset all controllers
		*/
		ControllerType[ControllerType["ResetControllers"] = 121] = "ResetControllers";
		/**
		* All notes of.
		*/
		ControllerType[ControllerType["AllNotesOff"] = 123] = "AllNotesOff";
		return ControllerType;
	}({});
	//#endregion
	//#region src/synth/synthesis/TinySoundFont.ts
	/**
	* This is a tiny soundfont based synthesizer.
	* NOT YET IMPLEMENTED
	*   - Support for ChorusEffectsSend and ReverbEffectsSend generators
	*   - Better low-pass filter without lowering performance too much
	*   - Support for modulators
	* @internal
	*/
	var TinySoundFont = class TinySoundFont {
		_midiEventQueue = new Queue();
		_mutedChannels = /* @__PURE__ */ new Map();
		_soloChannels = /* @__PURE__ */ new Map();
		_isAnySolo = false;
		_transpositionPitches = /* @__PURE__ */ new Map();
		_liveTranspositionPitches = /* @__PURE__ */ new Map();
		currentTempo = 0;
		timeSignatureNumerator = 0;
		timeSignatureDenominator = 0;
		_metronomeChannel = SynthConstants.DefaultChannelCount - 1;
		constructor(sampleRate) {
			this.outSampleRate = sampleRate;
		}
		synthesize(buffer, bufferPos, sampleCount) {
			return this._fillWorkingBuffer(buffer, bufferPos, sampleCount);
		}
		synthesizeSilent(sampleCount) {
			this._fillWorkingBuffer(null, 0, sampleCount);
		}
		channelGetMixVolume(channel) {
			return this._channels && channel < this._channels.channelList.length ? this._channels.channelList[channel].mixVolume : 1;
		}
		channelSetMixVolume(channel, volume) {
			const c = this._channelInit(channel);
			for (const v of this._voices) if (v.playingChannel === channel && v.playingPreset !== -1) v.mixVolume = volume;
			c.mixVolume = volume;
		}
		channelSetMute(channel, mute) {
			if (mute) this._mutedChannels.set(channel, true);
			else this._mutedChannels.delete(channel);
		}
		channelSetSolo(channel, solo) {
			if (solo) this._soloChannels.set(channel, true);
			else this._soloChannels.delete(channel);
			this._isAnySolo = this._soloChannels.size > 0;
		}
		resetChannelStates() {
			this._mutedChannels = /* @__PURE__ */ new Map();
			this._soloChannels = /* @__PURE__ */ new Map();
			this._liveTranspositionPitches = /* @__PURE__ */ new Map();
			this.applyTranspositionPitches(/* @__PURE__ */ new Map());
			this._isAnySolo = false;
		}
		setChannelTranspositionPitch(channel, semitones) {
			let previousTransposition = 0;
			if (this._liveTranspositionPitches.has(channel)) previousTransposition = this._liveTranspositionPitches.get(channel);
			if (semitones === 0) this._liveTranspositionPitches.delete(channel);
			else this._liveTranspositionPitches.set(channel, semitones);
			for (const voice of this._voices) if (voice.playingChannel === channel && voice.playingChannel !== 9) {
				let pitchDifference = 0;
				pitchDifference -= previousTransposition;
				pitchDifference += semitones;
				voice.playingKey += pitchDifference;
				if (this._channels) voice.updatePitchRatio(this._channels.channelList[voice.playingChannel], this.outSampleRate);
			}
		}
		applyTranspositionPitches(transpositionPitches) {
			const previousTransposePitches = this._transpositionPitches;
			for (const voice of this._voices) if (voice.playingChannel >= 0 && voice.playingChannel !== 9) {
				let pitchDifference = 0;
				if (previousTransposePitches.has(voice.playingChannel)) pitchDifference -= previousTransposePitches.get(voice.playingChannel);
				if (transpositionPitches.has(voice.playingChannel)) pitchDifference += transpositionPitches.get(voice.playingChannel);
				voice.playingKey += pitchDifference;
				if (this._channels) voice.updatePitchRatio(this._channels.channelList[voice.playingChannel], this.outSampleRate);
			}
			this._transpositionPitches = transpositionPitches;
		}
		dispatchEvent(synthEvent) {
			this._midiEventQueue.enqueue(synthEvent);
		}
		_fillWorkingBuffer(buffer, bufferPos, sampleCount) {
			const anySolo = this._isAnySolo;
			const processedEvents = [];
			while (!this._midiEventQueue.isEmpty) {
				const m = this._midiEventQueue.dequeue();
				if (m.isMetronome && this.metronomeVolume > 0) {
					this.channelNoteOff(this._metronomeChannel, SynthConstants.MetronomeKey);
					this.channelNoteOn(this._metronomeChannel, SynthConstants.MetronomeKey, 95 / 127);
				} else if (m.event) this.processMidiMessage(m.event);
				processedEvents.push(m);
			}
			for (const voice of this._voices) if (voice.playingPreset !== -1) {
				const channel = voice.playingChannel;
				const isChannelMuted = this._mutedChannels.has(channel) || anySolo && channel !== this._metronomeChannel && !this._soloChannels.has(channel);
				if (!buffer) voice.kill();
				else voice.render(this, buffer, bufferPos, sampleCount, isChannelMuted);
			}
			return processedEvents;
		}
		processMidiMessage(e) {
			switch (e.type) {
				case MidiEventType.TimeSignature:
					const timeSignature = e;
					this.timeSignatureNumerator = timeSignature.numerator;
					this.timeSignatureDenominator = Math.pow(2, timeSignature.denominatorIndex);
					break;
				case MidiEventType.NoteOn:
					const noteOn = e;
					this.channelNoteOn(noteOn.channel, noteOn.noteKey, noteOn.noteVelocity / 127);
					break;
				case MidiEventType.NoteOff:
					const noteOff = e;
					this.channelNoteOff(noteOff.channel, noteOff.noteKey);
					break;
				case MidiEventType.ControlChange:
					const controlChange = e;
					this.channelMidiControl(controlChange.channel, controlChange.controller, controlChange.value);
					break;
				case MidiEventType.ProgramChange:
					const programChange = e;
					this.channelSetPresetNumber(programChange.channel, programChange.program, programChange.channel === 9);
					break;
				case MidiEventType.TempoChange:
					const tempoChange = e;
					this.currentTempo = tempoChange.beatsPerMinute;
					break;
				case MidiEventType.PitchBend:
					const pitchBend = e;
					this.channelSetPitchWheel(pitchBend.channel, pitchBend.value);
					break;
				case MidiEventType.PerNotePitchBend:
					const noteBend = e;
					let perNotePitchWheel = noteBend.value;
					perNotePitchWheel = perNotePitchWheel * SynthConstants.MaxPitchWheel / SynthConstants.MaxPitchWheel20;
					this.channelSetPerNotePitchWheel(noteBend.channel, noteBend.noteKey, perNotePitchWheel);
					break;
			}
		}
		get metronomeVolume() {
			return this.channelGetMixVolume(this._metronomeChannel);
		}
		set metronomeVolume(value) {
			this.setupMetronomeChannel(this._metronomeChannel, value);
		}
		setupMetronomeChannel(channel, volume) {
			this._metronomeChannel = channel;
			this.channelSetMixVolume(channel, volume);
			if (volume > 0) {
				this.channelSetVolume(channel, 1);
				this.channelSetPresetNumber(channel, 0, true);
			}
		}
		get masterVolume() {
			return SynthHelper.decibelsToGain(this.globalGainDb);
		}
		set masterVolume(value) {
			const gainDb = SynthHelper.gainToDecibels(value);
			const gainDBChange = gainDb - this.globalGainDb;
			if (gainDBChange === 0) return;
			for (const v of this._voices) if (v.playingPreset !== -1) v.noteGainDb += gainDBChange;
			this.globalGainDb = gainDb;
		}
		/**
		* Stop all playing notes immediatly and reset all channel parameters but keeps user
		* defined settings
		*/
		resetSoft() {
			for (const v of this._voices) if (v.playingPreset !== -1 && (v.ampEnv.segment < VoiceEnvelopeSegment.Release || v.ampEnv.parameters.release !== 0)) v.endQuick(this.outSampleRate);
			if (this._channels) for (const c of this._channels.channelList) {
				c.presetIndex = 0;
				c.bank = 0;
				c.pitchWheel = 8192;
				c.midiPan = 8192;
				c.perNotePitchWheel.clear();
				c.midiVolume = 16383;
				c.midiExpression = 16383;
				c.midiRpn = 65535;
				c.midiData = 0;
				c.panOffset = 0;
				c.gainDb = 0;
				c.pitchRange = 2;
				c.tuning = 0;
			}
		}
		presets = null;
		_voices = [];
		_channels = null;
		_voicePlayIndex = 0;
		get presetCount() {
			return this.presets?.length ?? 0;
		}
		/**
		* Gets the currently configured output mode.
		*/
		outputMode = OutputMode.StereoInterleaved;
		/**
		* Gets the currently configured sample rate.
		*/
		outSampleRate = 0;
		/**
		* Gets the currently configured global gain in DB.
		*/
		globalGainDb = 0;
		/**
		* Stop all playing notes immediatly and reset all channel parameters
		*/
		reset() {
			for (const v of this._voices) if (v.playingPreset !== -1 && (v.ampEnv.segment < VoiceEnvelopeSegment.Release || v.ampEnv.parameters.release !== 0)) v.endQuick(this.outSampleRate);
			this._channels = null;
		}
		/**
		* Setup the parameters for the voice render methods
		* @param outputMode if mono or stereo and how stereo channel data is ordered
		* @param sampleRate the number of samples per second (output frequency)
		* @param globalGainDb volume gain in decibels (>0 means higher, <0 means lower)
		*/
		setOutput(outputMode, sampleRate, globalGainDb) {
			this.outputMode = outputMode;
			this.outSampleRate = sampleRate >= 1 ? sampleRate : 44100;
			this.globalGainDb = globalGainDb;
		}
		/**
		* Start playing a note
		* @param presetIndex preset index >= 0 and < {@link presetCount}
		* @param key note value between 0 and 127 (60 being middle C)
		* @param vel velocity as a float between 0.0 (equal to note off) and 1.0 (full)
		*/
		noteOn(presetIndex, key, vel) {
			if (!this.presets) return;
			const midiVelocity = vel * 127 | 0;
			if (presetIndex < 0 || presetIndex >= this.presets.length) return;
			if (vel <= 0) {
				this.noteOff(presetIndex, key);
				return;
			}
			const voicePlayIndex = this._voicePlayIndex++;
			for (const region of this.presets[presetIndex].regions) {
				if (key < region.loKey || key > region.hiKey || midiVelocity < region.loVel || midiVelocity > region.hiVel) continue;
				let voice = null;
				if (region.group !== 0) {
					for (const v of this._voices) if (v.playingPreset === presetIndex && v.region.group === region.group) v.endQuick(this.outSampleRate);
					else if (v.playingPreset === -1 && !voice) voice = v;
				} else for (const v of this._voices) if (v.playingPreset === -1) voice = v;
				if (!voice) {
					for (let i = 0; i < 4; i++) {
						const newVoice = new Voice();
						newVoice.playingPreset = -1;
						this._voices.push(newVoice);
					}
					voice = this._voices[this._voices.length - 4];
				}
				voice.region = region;
				voice.playingPreset = presetIndex;
				voice.playingKey = key;
				voice.playIndex = voicePlayIndex;
				voice.noteGainDb = this.globalGainDb - region.attenuation - SynthHelper.gainToDecibels(1 / vel);
				if (this._channels) this._channels.setupVoice(this, voice);
				else {
					voice.calcPitchRatio(0, this.outSampleRate);
					voice.panFactorLeft = Math.sqrt(.5 - region.pan);
					voice.panFactorRight = Math.sqrt(.5 + region.pan);
				}
				voice.sourceSamplePosition = region.offset;
				const doLoop = region.loopMode !== LoopMode.None && region.loopStart < region.loopEnd;
				voice.loopStart = doLoop ? region.loopStart : 0;
				voice.loopEnd = doLoop ? region.loopEnd : 0;
				voice.ampEnv.setup(region.ampEnv, key, midiVelocity, true, this.outSampleRate);
				voice.modEnv.setup(region.modEnv, key, midiVelocity, false, this.outSampleRate);
				const filterQDB = region.initialFilterQ / 10;
				voice.lowPass.qInv = 1 / Math.pow(10, filterQDB / 20);
				voice.lowPass.z1 = 0;
				voice.lowPass.z2 = 0;
				voice.lowPass.active = region.initialFilterFc <= 13500;
				if (voice.lowPass.active) voice.lowPass.setup(SynthHelper.cents2Hertz(region.initialFilterFc) / this.outSampleRate);
				voice.modLfo.setup(region.delayModLFO, region.freqModLFO, this.outSampleRate);
				voice.vibLfo.setup(region.delayVibLFO, region.freqVibLFO, this.outSampleRate);
			}
		}
		/**
		* Start playing a note
		* @param bank instrument bank number (alternative to preset_index)
		* @param presetNumber preset number (alternative to preset_index)
		* @param key note value between 0 and 127 (60 being middle C)
		* @param vel velocity as a float between 0.0 (equal to note off) and 1.0 (full)
		* @returns returns false if preset does not exist, otherwise true
		*/
		bankNoteOn(bank, presetNumber, key, vel) {
			const presetIndex = this._getPresetIndex(bank, presetNumber);
			if (presetIndex === -1) return false;
			this.noteOn(presetIndex, key, vel);
			return true;
		}
		/**
		* Stop playing a note
		*/
		noteOff(presetIndex, key) {
			let matchFirst = null;
			let matchLast = null;
			const matches = [];
			for (const v of this._voices) {
				if (v.playingPreset !== presetIndex || v.playingKey !== key || v.ampEnv.segment >= VoiceEnvelopeSegment.Release) continue;
				if (!matchFirst || v.playIndex < matchFirst.playIndex) {
					matchFirst = v;
					matchLast = v;
					matches.push(v);
				} else if (v.playIndex === matchFirst.playIndex) {
					matchLast = v;
					matches.push(v);
				}
			}
			if (!matchFirst) return;
			for (const v of matches) {
				if (v !== matchFirst && v !== matchLast && (v.playIndex !== matchFirst.playIndex || v.playingPreset !== presetIndex || v.playingKey !== key || v.ampEnv.segment >= VoiceEnvelopeSegment.Release)) continue;
				v.end(this.outSampleRate);
			}
		}
		/**
		* Stop playing a note
		* @returns returns false if preset does not exist, otherwise true
		*/
		bankNoteOff(bank, presetNumber, key) {
			const presetIndex = this._getPresetIndex(bank, presetNumber);
			if (presetIndex === -1) return false;
			this.noteOff(presetIndex, key);
			return true;
		}
		/**
		* Stop playing all notes (end with sustain and release)
		*/
		noteOffAll(immediate) {
			for (const voice of this._voices) if (voice.playingPreset !== -1) {
				if (immediate) voice.endQuick(this.outSampleRate);
				else if (voice.ampEnv.segment < VoiceEnvelopeSegment.Release) voice.end(this.outSampleRate);
			}
		}
		get activeVoiceCount() {
			let count = 0;
			for (const v of this._voices) if (v.playingPreset !== -1) count++;
			return count;
		}
		_channelInit(channel) {
			if (this._channels && channel < this._channels.channelList.length) return this._channels.channelList[channel];
			if (!this._channels) this._channels = new Channels();
			for (let i = this._channels.channelList.length; i <= channel; i++) {
				const c = new Channel();
				c.presetIndex = 0;
				c.bank = 0;
				c.pitchWheel = 8192;
				c.midiPan = 8192;
				c.midiVolume = 16383;
				c.midiExpression = 16383;
				c.midiRpn = 65535;
				c.midiData = 0;
				c.panOffset = 0;
				c.gainDb = 0;
				c.pitchRange = 2;
				c.tuning = 0;
				c.mixVolume = 1;
				this._channels.channelList.push(c);
			}
			return this._channels.channelList[channel];
		}
		/**
		* Returns the preset index from a bank and preset number, or -1 if it does not exist in the loaded SoundFont
		*/
		_getPresetIndex(bank, presetNumber) {
			if (!this.presets) return -1;
			for (let i = this.presets.length - 1; i >= 0; i--) {
				const preset = this.presets[i];
				if (preset.presetNumber === presetNumber && preset.bank === bank) return i;
			}
			return -1;
		}
		/**
		* Returns the name of a preset index >= 0 and < GetPresetName()
		* @param presetIndex
		*/
		getPresetName(presetIndex) {
			if (!this.presets) return null;
			return presetIndex < 0 || presetIndex >= this.presets.length ? null : this.presets[presetIndex].name;
		}
		/**
		* Returns the name of a preset by bank and preset number
		*/
		bankGetPresetName(bank, presetNumber) {
			return this.getPresetName(this._getPresetIndex(bank, presetNumber));
		}
		/**
		* Start playing a note on a channel
		* @param channel channel number
		* @param key note value between 0 and 127 (60 being middle C)
		* @param vel velocity as a float between 0.0 (equal to note off) and 1.0 (full)
		*/
		channelNoteOn(channel, key, vel) {
			if (!this._channels || channel > this._channels.channelList.length) return;
			if (this._transpositionPitches.has(channel)) key += this._transpositionPitches.get(channel);
			if (this._liveTranspositionPitches.has(channel)) key += this._liveTranspositionPitches.get(channel);
			this._channels.activeChannel = channel;
			this.noteOn(this._channels.channelList[channel].presetIndex, key, vel);
		}
		/**
		* Stop playing notes on a channel
		* @param channel channel number
		* @param key note value between 0 and 127 (60 being middle C)
		*/
		channelNoteOff(channel, key) {
			if (this._transpositionPitches.has(channel)) key += this._transpositionPitches.get(channel);
			if (this._liveTranspositionPitches.has(channel)) key += this._liveTranspositionPitches.get(channel);
			const matches = [];
			let matchFirst = null;
			let matchLast = null;
			for (const v of this._voices) {
				if (v.playingPreset === -1 || v.playingChannel !== channel || v.playingKey !== key || v.ampEnv.segment >= VoiceEnvelopeSegment.Release) continue;
				if (!matchFirst || v.playIndex < matchFirst.playIndex) {
					matchFirst = v;
					matchLast = v;
					matches.push(v);
				} else if (v.playIndex === matchFirst.playIndex) {
					matchLast = v;
					matches.push(v);
				}
			}
			this._channelInit(channel).perNotePitchWheel.delete(key);
			if (!matchFirst) return;
			for (const v of matches) {
				if (v !== matchFirst && v !== matchLast && (v.playIndex !== matchFirst.playIndex || v.playingPreset === -1 || v.playingChannel !== channel || v.playingKey !== key || v.ampEnv.segment >= VoiceEnvelopeSegment.Release)) continue;
				v.end(this.outSampleRate);
			}
		}
		/**
		* Stop playing all notes on a channel with sustain and release.
		* @param channel channel number
		*/
		channelNoteOffAll(channel) {
			this._channelInit(channel).perNotePitchWheel.clear();
			for (const v of this._voices) if (v.playingPreset !== -1 && v.playingChannel === channel && v.ampEnv.segment < VoiceEnvelopeSegment.Release) v.end(this.outSampleRate);
		}
		/**
		* Stop playing all notes on a channel immediately
		* @param channel channel number
		*/
		channelSoundsOffAll(channel) {
			this._channelInit(channel).perNotePitchWheel.clear();
			for (const v of this._voices) if (v.playingPreset !== -1 && v.playingChannel === channel && (v.ampEnv.segment < VoiceEnvelopeSegment.Release || v.ampEnv.parameters.release === 0)) v.endQuick(this.outSampleRate);
		}
		/**
		*
		* @param channel channel number
		* @param presetIndex preset index <= 0 and > {@link presetCount}
		*/
		channelSetPresetIndex(channel, presetIndex) {
			this._channelInit(channel).presetIndex = TypeConversions.int32ToUint16(presetIndex);
		}
		/**
		* @param channel channel number
		* @param presetNumber preset number (alternative to preset_index)
		* @param midiDrums false for normal channels, otherwise apply MIDI drum channel rules
		* @returns return false if preset does not exist, otherwise true
		*/
		channelSetPresetNumber(channel, presetNumber, midiDrums = false) {
			const c = this._channelInit(channel);
			let presetIndex = 0;
			if (midiDrums) {
				presetIndex = this._getPresetIndex(128 | c.bank & 32767, presetNumber);
				if (presetIndex === -1) presetIndex = this._getPresetIndex(128, presetNumber);
				if (presetIndex === -1) presetIndex = this._getPresetIndex(128, 0);
				if (presetIndex === -1) presetIndex = this._getPresetIndex(c.bank & 2047, presetNumber);
			} else presetIndex = this._getPresetIndex(c.bank & 2047, presetNumber);
			c.presetIndex = presetIndex;
			return presetIndex !== -1;
		}
		/**
		* @param channel channel number
		* @param bank instrument bank number (alternative to preset_index)
		*/
		channelSetBank(channel, bank) {
			this._channelInit(channel).bank = TypeConversions.int32ToUint16(bank);
		}
		/**
		* @param channel channel number
		* @param bank instrument bank number (alternative to preset_index)
		* @param presetNumber preset number (alternative to preset_index)
		* @returns return false if preset does not exist, otherwise true
		*/
		channelSetBankPreset(channel, bank, presetNumber) {
			const c = this._channelInit(channel);
			const presetIndex = this._getPresetIndex(bank, presetNumber);
			if (presetIndex === -1) return false;
			c.presetIndex = TypeConversions.int32ToUint16(presetIndex);
			c.bank = TypeConversions.int32ToUint16(bank);
			return true;
		}
		/**
		* @param channel channel number
		* @param pan stereo panning value from 0.0 (left) to 1.0 (right) (default 0.5 center)
		*/
		channelSetPan(channel, pan) {
			for (const v of this._voices) if (v.playingChannel === channel && v.playingPreset !== -1) {
				const newPan = v.region.pan + pan - .5;
				if (newPan <= -.5) {
					v.panFactorLeft = 1;
					v.panFactorRight = 0;
				} else if (newPan >= .5) {
					v.panFactorLeft = 0;
					v.panFactorRight = 1;
				} else {
					v.panFactorLeft = Math.sqrt(.5 - newPan);
					v.panFactorRight = Math.sqrt(.5 + newPan);
				}
			}
			this._channelInit(channel).panOffset = pan - .5;
		}
		/**
		* @param channel channel number
		* @param volume linear volume scale factor (default 1.0 full)
		*/
		channelSetVolume(channel, volume) {
			const c = this._channelInit(channel);
			const gainDb = SynthHelper.gainToDecibels(volume);
			const gainDBChange = gainDb - c.gainDb;
			if (gainDBChange === 0) return;
			for (const v of this._voices) if (v.playingChannel === channel && v.playingPreset !== -1) v.noteGainDb += gainDBChange;
			c.gainDb = gainDb;
		}
		/**
		* @param channel channel number
		* @param pitchWheel pitch wheel position 0 to 16383 (default 8192 unpitched)
		*/
		channelSetPitchWheel(channel, pitchWheel) {
			const c = this._channelInit(channel);
			if (c.pitchWheel === pitchWheel) return;
			c.pitchWheel = TypeConversions.int32ToUint16(pitchWheel);
			this._channelApplyPitch(channel, c);
		}
		/**
		* @param channel channel number
		* @param key note value between 0 and 127
		* @param pitchWheel pitch wheel position 0 to 16383 (default 8192 unpitched)
		*/
		channelSetPerNotePitchWheel(channel, key, pitchWheel) {
			if (this._transpositionPitches.has(channel)) key += this._transpositionPitches.get(channel);
			if (this._liveTranspositionPitches.has(channel)) key += this._liveTranspositionPitches.get(channel);
			const c = this._channelInit(channel);
			if (c.perNotePitchWheel.has(key) && c.perNotePitchWheel.get(key) === pitchWheel) return;
			c.perNotePitchWheel.set(key, pitchWheel);
			this._channelApplyPitch(channel, c, key);
		}
		_channelApplyPitch(channel, c, key = -1) {
			for (const v of this._voices) if (v.playingChannel === channel && v.playingPreset !== -1 && (key === -1 || v.playingKey === key)) v.updatePitchRatio(c, this.outSampleRate);
		}
		/**
		* @param channel channel number
		* @param pitchRange range of the pitch wheel in semitones (default 2.0, total +/- 2 semitones)
		*/
		channelSetPitchRange(channel, pitchRange) {
			const c = this._channelInit(channel);
			if (c.pitchRange === pitchRange) return;
			c.pitchRange = pitchRange;
			if (c.pitchWheel !== 8192) this._channelApplyPitch(channel, c);
		}
		/**
		* @param channel channel number
		* @param tuning tuning of all playing voices in semitones (default 0.0, standard (A440) tuning)
		*/
		channelSetTuning(channel, tuning) {
			const c = this._channelInit(channel);
			if (c.tuning === tuning) return;
			c.tuning = tuning;
			this._channelApplyPitch(channel, c);
		}
		/**
		* Apply a MIDI control change to the channel (not all controllers are supported!)
		*/
		channelMidiControl(channel, controller, controlValue) {
			const c = this._channelInit(channel);
			switch (controller) {
				case ControllerType.DataEntryFine:
					c.midiData = TypeConversions.int32ToUint16(c.midiData & 16256 | controlValue);
					if (c.midiRpn === 0) this.channelSetPitchRange(channel, (c.midiData >> 7) + .01 * (c.midiData & 127));
					else if (c.midiRpn === 1) this.channelSetTuning(channel, (c.tuning | 0) + (c.midiData - 8192) / 8192);
					else if (c.midiRpn === 2) this.channelSetTuning(channel, controlValue - 64 + (c.tuning - (c.tuning | 0)));
					return;
				case ControllerType.VolumeCoarse:
					c.midiVolume = TypeConversions.int32ToUint16(c.midiVolume & 127 | controlValue << 7);
					this.channelSetVolume(channel, Math.pow(c.midiVolume / 16383 * (c.midiExpression / 16383), 3));
					return;
				case ControllerType.VolumeFine:
					c.midiVolume = TypeConversions.int32ToUint16(c.midiVolume & 16256 | controlValue);
					this.channelSetVolume(channel, Math.pow(c.midiVolume / 16383 * (c.midiExpression / 16383), 3));
					return;
				case ControllerType.ExpressionControllerCoarse:
					c.midiExpression = TypeConversions.int32ToUint16(c.midiExpression & 127 | controlValue << 7);
					this.channelSetVolume(channel, Math.pow(c.midiVolume / 16383 * (c.midiExpression / 16383), 3));
					return;
				case ControllerType.ExpressionControllerFine:
					c.midiExpression = TypeConversions.int32ToUint16(c.midiExpression & 16256 | controlValue);
					this.channelSetVolume(channel, Math.pow(c.midiVolume / 16383 * (c.midiExpression / 16383), 3));
					return;
				case ControllerType.PanCoarse:
					c.midiPan = TypeConversions.int32ToUint16(c.midiPan & 127 | controlValue << 7);
					this.channelSetPan(channel, c.midiPan / 16383);
					return;
				case ControllerType.PanFine:
					c.midiPan = TypeConversions.int32ToUint16(c.midiPan & 16256 | controlValue);
					this.channelSetPan(channel, c.midiPan / 16383);
					return;
				case ControllerType.DataEntryCoarse:
					c.midiData = TypeConversions.int32ToUint16(c.midiData & 127 | controlValue << 7);
					if (c.midiRpn === 0) this.channelSetPitchRange(channel, (c.midiData >> 7) + .01 * (c.midiData & 127));
					else if (c.midiRpn === 1) this.channelSetTuning(channel, (c.tuning | 0) + (c.midiData - 8192) / 8192);
					else if (c.midiRpn === 2 && controller === ControllerType.DataEntryCoarse) this.channelSetTuning(channel, controlValue - 64 + (c.tuning - (c.tuning | 0)));
					return;
				case ControllerType.BankSelectCoarse:
					c.bank = TypeConversions.int32ToUint16(32768 | controlValue);
					return;
				case ControllerType.BankSelectFine:
					c.bank = TypeConversions.int32ToUint16(((c.bank & 32768) !== 0 ? (c.bank & 127) << 7 : 0) | controlValue);
					return;
				case ControllerType.RegisteredParameterCourse:
					c.midiRpn = TypeConversions.int32ToUint16((c.midiRpn === 65535 ? 0 : c.midiRpn) & 127 | controlValue << 7);
					return;
				case ControllerType.RegisteredParameterFine:
					c.midiRpn = TypeConversions.int32ToUint16((c.midiRpn === 65535 ? 0 : c.midiRpn) & 16256 | controlValue);
					return;
				case ControllerType.NonRegisteredParameterFine:
					c.midiRpn = 65535;
					return;
				case ControllerType.NonRegisteredParameterCourse:
					c.midiRpn = 65535;
					return;
				case ControllerType.AllSoundOff:
					this.channelSoundsOffAll(channel);
					return;
				case ControllerType.AllNotesOff:
					this.channelNoteOffAll(channel);
					return;
				case ControllerType.ResetControllers:
					c.midiVolume = 16383;
					c.midiExpression = 16383;
					c.midiPan = 8192;
					c.bank = 0;
					this.channelSetVolume(channel, 1);
					this.channelSetPan(channel, .5);
					this.channelSetPitchRange(channel, 2);
					return;
			}
		}
		/**
		* Gets the current preset index of the given channel.
		* @param channel The channel index
		* @returns The current preset index of the given channel.
		*/
		channelGetPresetIndex(channel) {
			return this._channels && channel < this._channels.channelList.length ? this._channels.channelList[channel].presetIndex : 0;
		}
		/**
		* Gets the current bank of the given channel.
		* @param channel The channel index
		* @returns The current bank of the given channel.
		*/
		channelGetPresetBank(channel) {
			return this._channels && channel < this._channels.channelList.length ? this._channels.channelList[channel].bank & 32767 : 0;
		}
		/**
		* Gets the current pan of the given channel.
		* @param channel The channel index
		* @returns The current pan of the given channel.
		*/
		channelGetPan(channel) {
			return this._channels && channel < this._channels.channelList.length ? this._channels.channelList[channel].panOffset - .5 : .5;
		}
		/**
		* Gets the current volume of the given channel.
		* @param channel The channel index
		* @returns The current volune of the given channel.
		*/
		channelGetVolume(channel) {
			return this._channels && channel < this._channels.channelList.length ? SynthHelper.decibelsToGain(this._channels.channelList[channel].gainDb) : 1;
		}
		/**
		* Gets the current pitch wheel of the given channel.
		* @param channel The channel index
		* @returns The current pitch wheel of the given channel.
		*/
		channelGetPitchWheel(channel) {
			return this._channels && channel < this._channels.channelList.length ? this._channels.channelList[channel].pitchWheel : 8192;
		}
		/**
		* Gets the current pitch range of the given channel.
		* @param channel The channel index
		* @returns The current pitch range of the given channel.
		*/
		channelGetPitchRange(channel) {
			return this._channels && channel < this._channels.channelList.length ? this._channels.channelList[channel].pitchRange : 2;
		}
		/**
		* Gets the current tuning of the given channel.
		* @param channel The channel index
		* @returns The current tuning of the given channel.
		*/
		channelGetTuning(channel) {
			return this._channels && channel < this._channels.channelList.length ? this._channels.channelList[channel].tuning : 0;
		}
		resetPresets() {
			this.presets = [];
		}
		loadPresets(hydra, instrumentPrograms, percussionKeys, append) {
			const newPresets = [];
			for (let phdrIndex = 0; phdrIndex < hydra.phdrs.length - 1; phdrIndex++) {
				const phdr = hydra.phdrs[phdrIndex];
				let regionIndex = 0;
				const preset = new Preset();
				newPresets.push(preset);
				preset.name = phdr.presetName;
				preset.bank = phdr.bank;
				preset.presetNumber = phdr.preset;
				let regionNum = 0;
				for (let pbagIndex = phdr.presetBagNdx; pbagIndex < hydra.phdrs[phdrIndex + 1].presetBagNdx; pbagIndex++) {
					const pbag = hydra.pbags[pbagIndex];
					let plokey = 0;
					let phikey = 127;
					let plovel = 0;
					let phivel = 127;
					for (let pgenIndex = pbag.genNdx; pgenIndex < hydra.pbags[pbagIndex + 1].genNdx; pgenIndex++) {
						const pgen = hydra.pgens[pgenIndex];
						if (pgen.genOper === HydraPgen.GenKeyRange) {
							plokey = pgen.genAmount.lowByteAmount;
							phikey = pgen.genAmount.highByteAmount;
							continue;
						}
						if (pgen.genOper === HydraPgen.GenVelRange) {
							plovel = pgen.genAmount.lowByteAmount;
							phivel = pgen.genAmount.highByteAmount;
							continue;
						}
						if (pgen.genOper !== HydraPgen.GenInstrument) continue;
						if (pgen.genAmount.wordAmount >= hydra.insts.length) continue;
						const pinst = hydra.insts[pgen.genAmount.wordAmount];
						for (let ibagIndex = pinst.instBagNdx; ibagIndex < hydra.insts[pgen.genAmount.wordAmount + 1].instBagNdx; ibagIndex++) {
							const ibag = hydra.ibags[ibagIndex];
							let ilokey = 0;
							let ihikey = 127;
							let ilovel = 0;
							let ihivel = 127;
							for (let igenIndex = ibag.instGenNdx; igenIndex < hydra.ibags[ibagIndex + 1].instGenNdx; igenIndex++) {
								const igen = hydra.igens[igenIndex];
								if (igen.genOper === HydraPgen.GenKeyRange) {
									ilokey = igen.genAmount.lowByteAmount;
									ihikey = igen.genAmount.highByteAmount;
									continue;
								}
								if (igen.genOper === HydraPgen.GenVelRange) {
									ilovel = igen.genAmount.lowByteAmount;
									ihivel = igen.genAmount.highByteAmount;
									continue;
								}
								if (igen.genOper === 53 && ihikey >= plokey && ilokey <= phikey && ihivel >= plovel && ilovel <= phivel) regionNum++;
							}
						}
					}
				}
				preset.regions = new Array(regionNum);
				let globalRegion = new Region();
				globalRegion.clear(true);
				for (let pbagIndex = phdr.presetBagNdx; pbagIndex < hydra.phdrs[phdrIndex + 1].presetBagNdx; pbagIndex++) {
					const pbag = hydra.pbags[pbagIndex];
					const presetRegion = new Region(globalRegion);
					let hadGenInstrument = false;
					for (let pgenIndex = pbag.genNdx; pgenIndex < hydra.pbags[pbagIndex + 1].genNdx; pgenIndex++) {
						const pgen = hydra.pgens[pgenIndex];
						if (pgen.genOper === HydraPgen.GenInstrument) {
							const whichInst = pgen.genAmount.wordAmount;
							if (whichInst >= hydra.insts.length) continue;
							let instRegion = new Region();
							instRegion.clear(false);
							const inst = hydra.insts[whichInst];
							for (let ibagIndex = inst.instBagNdx; ibagIndex < hydra.insts[whichInst + 1].instBagNdx; ibagIndex++) {
								const ibag = hydra.ibags[ibagIndex];
								const zoneRegion = new Region(instRegion);
								let hadSampleId = false;
								for (let igenIndex = ibag.instGenNdx; igenIndex < hydra.ibags[ibagIndex + 1].instGenNdx; igenIndex++) {
									const igen = hydra.igens[igenIndex];
									if (igen.genOper === HydraPgen.GenSampleId) {
										if (zoneRegion.hiKey < presetRegion.loKey || zoneRegion.loKey > presetRegion.hiKey) continue;
										if (zoneRegion.hiVel < presetRegion.loVel || zoneRegion.loVel > presetRegion.hiVel) continue;
										if (presetRegion.loKey > zoneRegion.loKey) zoneRegion.loKey = presetRegion.loKey;
										if (presetRegion.hiKey < zoneRegion.hiKey) zoneRegion.hiKey = presetRegion.hiKey;
										if (presetRegion.loVel > zoneRegion.loVel) zoneRegion.loVel = presetRegion.loVel;
										if (presetRegion.hiVel < zoneRegion.hiVel) zoneRegion.hiVel = presetRegion.hiVel;
										zoneRegion.offset += presetRegion.offset;
										zoneRegion.end += presetRegion.end;
										zoneRegion.loopStart += presetRegion.loopStart;
										zoneRegion.loopEnd += presetRegion.loopEnd;
										zoneRegion.transpose += presetRegion.transpose;
										zoneRegion.tune += presetRegion.tune;
										zoneRegion.pitchKeyTrack += presetRegion.pitchKeyTrack;
										zoneRegion.attenuation += presetRegion.attenuation;
										zoneRegion.pan += presetRegion.pan;
										zoneRegion.ampEnv.delay += presetRegion.ampEnv.delay;
										zoneRegion.ampEnv.attack += presetRegion.ampEnv.attack;
										zoneRegion.ampEnv.hold += presetRegion.ampEnv.hold;
										zoneRegion.ampEnv.decay += presetRegion.ampEnv.decay;
										zoneRegion.ampEnv.sustain += presetRegion.ampEnv.sustain;
										zoneRegion.ampEnv.release += presetRegion.ampEnv.release;
										zoneRegion.modEnv.delay += presetRegion.modEnv.delay;
										zoneRegion.modEnv.attack += presetRegion.modEnv.attack;
										zoneRegion.modEnv.hold += presetRegion.modEnv.hold;
										zoneRegion.modEnv.decay += presetRegion.modEnv.decay;
										zoneRegion.modEnv.sustain += presetRegion.modEnv.sustain;
										zoneRegion.modEnv.release += presetRegion.modEnv.release;
										zoneRegion.initialFilterQ += presetRegion.initialFilterQ;
										zoneRegion.initialFilterFc += presetRegion.initialFilterFc;
										zoneRegion.modEnvToPitch += presetRegion.modEnvToPitch;
										zoneRegion.modEnvToFilterFc += presetRegion.modEnvToFilterFc;
										zoneRegion.delayModLFO += presetRegion.delayModLFO;
										zoneRegion.freqModLFO += presetRegion.freqModLFO;
										zoneRegion.modLfoToPitch += presetRegion.modLfoToPitch;
										zoneRegion.modLfoToFilterFc += presetRegion.modLfoToFilterFc;
										zoneRegion.modLfoToVolume += presetRegion.modLfoToVolume;
										zoneRegion.delayVibLFO += presetRegion.delayVibLFO;
										zoneRegion.freqVibLFO += presetRegion.freqVibLFO;
										zoneRegion.vibLfoToPitch += presetRegion.vibLfoToPitch;
										zoneRegion.ampEnv.envToSecs(true);
										zoneRegion.modEnv.envToSecs(false);
										zoneRegion.delayModLFO = zoneRegion.delayModLFO < -11950 ? 0 : SynthHelper.timecents2Secs(zoneRegion.delayModLFO);
										zoneRegion.delayVibLFO = zoneRegion.delayVibLFO < -11950 ? 0 : SynthHelper.timecents2Secs(zoneRegion.delayVibLFO);
										if (zoneRegion.pan < -.5) zoneRegion.pan = -.5;
										else if (zoneRegion.pan > .5) zoneRegion.pan = .5;
										if (zoneRegion.initialFilterQ < 1500 || zoneRegion.initialFilterQ > 13500) zoneRegion.initialFilterQ = 0;
										const shdr = hydra.sHdrs[igen.genAmount.wordAmount];
										zoneRegion.offset += shdr.start;
										zoneRegion.end += shdr.end;
										zoneRegion.loopStart += shdr.startLoop;
										zoneRegion.loopEnd += shdr.endLoop;
										if (shdr.endLoop > 0) zoneRegion.loopEnd -= 1;
										if (zoneRegion.pitchKeyCenter === -1) zoneRegion.pitchKeyCenter = shdr.originalPitch;
										zoneRegion.tune += shdr.pitchCorrection;
										zoneRegion.sampleRate = shdr.sampleRate;
										const isPercussion = phdr.bank === SynthConstants.PercussionBank;
										if (!(isPercussion && TinySoundFont._setContainsRange(percussionKeys, zoneRegion.loKey, zoneRegion.hiKey) || !isPercussion && instrumentPrograms.has(phdr.preset))) {
											Logger.debug("AlphaSynth", `Skipping load of unused sample ${shdr.sampleName} for preset ${phdr.presetName} (bank ${preset.bank} program ${preset.presetNumber})`);
											zoneRegion.samples = new Float32Array(0);
										} else if ((shdr.sampleType & 1) !== 0) {
											Logger.debug("AlphaSynth", `Loading of used sample ${shdr.sampleName} for preset ${phdr.presetName} (bank ${preset.bank} program ${preset.presetNumber})`);
											if ((shdr.sampleType & 16) !== 0) zoneRegion.samples = hydra.decodeSamples(shdr.start, shdr.end, true);
											else {
												zoneRegion.samples = hydra.decodeSamples(zoneRegion.offset * 2, zoneRegion.end * 2, false);
												if (zoneRegion.loopStart > 0) zoneRegion.loopStart -= zoneRegion.offset;
												if (zoneRegion.loopEnd > 0) zoneRegion.loopEnd -= zoneRegion.offset;
											}
											zoneRegion.offset = 0;
											zoneRegion.end = zoneRegion.samples.length - 1;
										} else {
											Logger.warning("AlphaSynth", `Skipping load of unsupported sample ${shdr.sampleName} for preset ${phdr.presetName}, sample type ${shdr.sampleType} is not supported (bank ${preset.bank} program ${preset.presetNumber})`);
											zoneRegion.samples = new Float32Array(0);
										}
										preset.regions[regionIndex] = new Region(zoneRegion);
										regionIndex++;
										hadSampleId = true;
									} else zoneRegion.operator(igen.genOper, igen.genAmount);
								}
								if (ibag === hydra.ibags[inst.instBagNdx] && !hadSampleId) instRegion = new Region(zoneRegion);
							}
							hadGenInstrument = true;
						} else presetRegion.operator(pgen.genOper, pgen.genAmount);
					}
					if (pbag === hydra.pbags[phdr.presetBagNdx] && !hadGenInstrument) globalRegion = presetRegion;
				}
			}
			if (!append || !this.presets) this.presets = newPresets;
			else for (const preset of newPresets) this.presets.push(preset);
		}
		static _setContainsRange(x, lo, hi) {
			for (let i = lo; i <= hi; i++) if (x.has(i)) return true;
			return false;
		}
		hasSamplesForProgram(program) {
			const presets = this.presets;
			if (!presets) return false;
			for (const preset of presets) if (preset.presetNumber === program) {
				for (const region of preset.regions) if (region.samples.length > 0) return true;
			}
			return false;
		}
		hasSamplesForPercussion(key) {
			const presets = this.presets;
			if (!presets) return false;
			for (const preset of presets) if (preset.bank === SynthConstants.PercussionBank) {
				for (const region of preset.regions) if (region.loKey >= key && region.hiKey <= key && region.samples.length > 0) return true;
			}
			return false;
		}
	};
	//#endregion
	//#region src/synth/AlphaSynth.ts
	/**
	* This is the base class for synthesizer components which can be used to
	* play a {@link MidiFile} via a {@link ISynthOutput}.
	* @public
	*/
	var AlphaSynthBase = class {
		/**
		* @internal
		*/
		sequencer;
		/**
		* @internal
		*/
		synthesizer;
		isSoundFontLoaded = false;
		_isMidiLoaded = false;
		_tickPosition = 0;
		_timePosition = 0;
		_metronomeVolume = 0;
		_countInVolume = 0;
		/**
		* @internal
		*/
		playedEventsQueue = new Queue();
		midiEventsPlayedFilterSet = /* @__PURE__ */ new Set();
		_notPlayedSamples = 0;
		_synthStopping = false;
		_output;
		_loadedMidiInfo;
		_currentPosition = new PositionChangedEventArgs(0, 0, 0, 0, false, 120, 120);
		get output() {
			return this._output;
		}
		isReady = false;
		get isReadyForPlayback() {
			return this.isReady && this.isSoundFontLoaded && this._isMidiLoaded;
		}
		state = PlayerState.Paused;
		get logLevel() {
			return Logger.logLevel;
		}
		set logLevel(value) {
			Logger.logLevel = value;
		}
		get masterVolume() {
			return this.synthesizer.masterVolume;
		}
		set masterVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this.updateMasterVolume(value);
		}
		updateMasterVolume(value) {
			this.synthesizer.masterVolume = value;
		}
		get metronomeVolume() {
			return this._metronomeVolume;
		}
		set metronomeVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this._metronomeVolume = value;
			this.synthesizer.metronomeVolume = value;
		}
		get countInVolume() {
			return this._countInVolume;
		}
		set countInVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this._countInVolume = value;
		}
		get midiEventsPlayedFilter() {
			return Array.from(this.midiEventsPlayedFilterSet);
		}
		set midiEventsPlayedFilter(value) {
			this.midiEventsPlayedFilterSet = new Set(value);
		}
		get playbackSpeed() {
			return this.sequencer.playbackSpeed;
		}
		set playbackSpeed(value) {
			value = ModelUtils.clamp(value, SynthConstants.MinPlaybackSpeed, SynthConstants.MaxPlaybackSpeed);
			this.updatePlaybackSpeed(value);
		}
		updatePlaybackSpeed(value) {
			const oldSpeed = this.sequencer.playbackSpeed;
			this.sequencer.playbackSpeed = value;
			this.timePosition = this.timePosition * (oldSpeed / value);
		}
		get loadedMidiInfo() {
			return this._loadedMidiInfo;
		}
		get currentPosition() {
			return this._currentPosition;
		}
		get tickPosition() {
			return this._tickPosition;
		}
		set tickPosition(value) {
			this.timePosition = this.sequencer.mainTickPositionToTimePosition(value);
		}
		get timePosition() {
			return this._timePosition;
		}
		set timePosition(value) {
			Logger.debug("AlphaSynth", `Seeking to position ${value}ms (main)`);
			this.sequencer.mainSeek(value);
			this.updateTimePosition(value, true);
			if (this.sequencer.isPlayingMain) {
				this._notPlayedSamples = 0;
				this.output.resetSamples();
			}
		}
		get playbackRange() {
			return this.sequencer.mainPlaybackRange;
		}
		set playbackRange(value) {
			this.sequencer.mainPlaybackRange = value;
			if (value) this.tickPosition = value.startTick;
			this.playbackRangeChanged.trigger(new PlaybackRangeChangedEventArgs(value));
		}
		get isLooping() {
			return this.sequencer.isLooping;
		}
		set isLooping(value) {
			this.sequencer.isLooping = value;
		}
		destroy() {
			Logger.debug("AlphaSynth", "Destroying player");
			this.stop();
			this.output.destroy();
		}
		/**
		* Initializes a new instance of the {@link AlphaSynthBase} class.
		* @param output The output to use for playing the generated samples.
		* @internal
		*/
		constructor(output, synthesizer, bufferTimeInMilliseconds) {
			Logger.debug("AlphaSynth", "Initializing player");
			this.state = PlayerState.Paused;
			this.ready = new EventEmitter(() => this.isReady);
			this.readyForPlayback = new EventEmitter(() => this.isReadyForPlayback);
			this.midiLoaded = new EventEmitterOfT(() => {
				if (this._loadedMidiInfo) return this._loadedMidiInfo;
				return null;
			});
			this.stateChanged = new EventEmitterOfT(() => {
				return new PlayerStateChangedEventArgs(this.state, false);
			});
			this.positionChanged = new EventEmitterOfT(() => {
				return this._currentPosition;
			});
			this.playbackRangeChanged = new EventEmitterOfT(() => {
				if (this.playbackRange) return new PlaybackRangeChangedEventArgs(this.playbackRange);
				return null;
			});
			Logger.debug("AlphaSynth", "Creating output");
			this._output = output;
			Logger.debug("AlphaSynth", "Creating synthesizer");
			this.synthesizer = synthesizer;
			this.sequencer = new MidiFileSequencer(this.synthesizer);
			Logger.debug("AlphaSynth", "Opening output");
			this.output.ready.on(() => {
				this.isReady = true;
				this.ready.trigger();
				this._checkReadyForPlayback();
			});
			this.output.sampleRequest.on(() => {
				this.onSampleRequest();
			});
			this.output.samplesPlayed.on(this._onSamplesPlayed.bind(this));
			this.output.open(bufferTimeInMilliseconds);
		}
		onSampleRequest() {
			if (this.state === PlayerState.Playing && (!this.sequencer.isFinished || this.synthesizer.activeVoiceCount > 0)) {
				let samples = new Float32Array(SynthConstants.MicroBufferSize * SynthConstants.MicroBufferCount * SynthConstants.AudioChannels);
				let bufferPos = 0;
				for (let i = 0; i < SynthConstants.MicroBufferCount; i++) {
					this.sequencer.fillMidiEventQueue();
					const synthesizedEvents = this.synthesizer.synthesize(samples, bufferPos, SynthConstants.MicroBufferSize);
					bufferPos += SynthConstants.MicroBufferSize * SynthConstants.AudioChannels;
					for (const e of synthesizedEvents) if (this.midiEventsPlayedFilterSet.has(e.event.type)) this.playedEventsQueue.enqueue(e);
					if (this.sequencer.isFinished) break;
				}
				if (bufferPos < samples.length) samples = samples.subarray(0, bufferPos);
				this._notPlayedSamples += samples.length;
				this.output.addSamples(samples);
				if (this.sequencer.isFinished) this.synthesizer.noteOffAll(true);
			} else {
				const samples = new Float32Array(0);
				this.output.addSamples(samples);
			}
		}
		play() {
			if (this.state !== PlayerState.Paused || !this._isMidiLoaded) return false;
			this.output.activate();
			this._playInternal();
			if (this._countInVolume > 0) {
				Logger.debug("AlphaSynth", "Starting countin");
				this.sequencer.startCountIn();
				this.synthesizer.setupMetronomeChannel(this.sequencer.metronomeChannel, this._countInVolume);
				this.updateTimePosition(0, true);
			}
			this.output.play();
			return true;
		}
		_playInternal() {
			if (this.sequencer.isPlayingOneTimeMidi) {
				Logger.debug("AlphaSynth", "Cancelling one time midi");
				this._stopOneTimeMidi();
			}
			Logger.debug("AlphaSynth", "Starting playback");
			this.synthesizer.setupMetronomeChannel(this.sequencer.metronomeChannel, this.metronomeVolume);
			this._synthStopping = false;
			this.state = PlayerState.Playing;
			this.stateChanged.trigger(new PlayerStateChangedEventArgs(this.state, false));
		}
		pause() {
			if (this.state === PlayerState.Paused || !this._isMidiLoaded) return;
			Logger.debug("AlphaSynth", "Pausing playback");
			this.state = PlayerState.Paused;
			this.stateChanged.trigger(new PlayerStateChangedEventArgs(this.state, false));
			this.output.pause();
			this.synthesizer.noteOffAll(false);
		}
		playPause() {
			if (this.state !== PlayerState.Paused || !this._isMidiLoaded) this.pause();
			else this.play();
		}
		stop() {
			if (!this._isMidiLoaded) return;
			Logger.debug("AlphaSynth", "Stopping playback");
			this.state = PlayerState.Paused;
			this.output.pause();
			this._notPlayedSamples = 0;
			this.sequencer.stop();
			this.synthesizer.noteOffAll(true);
			this.tickPosition = this.sequencer.mainPlaybackRange ? this.sequencer.mainPlaybackRange.startTick : 0;
			this.stateChanged.trigger(new PlayerStateChangedEventArgs(this.state, true));
		}
		playOneTimeMidiFile(midi) {
			if (this.sequencer.isPlayingOneTimeMidi) this._stopOneTimeMidi();
			else this.pause();
			this.sequencer.loadOneTimeMidi(midi);
			this.synthesizer.noteOffAll(true);
			this.updateTimePosition(0, true);
			this._notPlayedSamples = 0;
			this.output.resetSamples();
			this.output.activate();
			this._synthStopping = false;
			this.state = PlayerState.Playing;
			this.output.play();
		}
		resetSoundFonts() {
			this.stop();
			this.synthesizer.resetPresets();
			this._loadedSoundFonts = [];
			this.isSoundFontLoaded = false;
			this.soundFontLoaded.trigger();
		}
		_loadedSoundFonts = [];
		loadSoundFont(data, append) {
			this.pause();
			const input = ByteBuffer.fromBuffer(data);
			try {
				Logger.debug("AlphaSynth", "Loading soundfont from bytes");
				const soundFont = new Hydra();
				soundFont.load(input);
				if (!append) this._loadedSoundFonts = [];
				this._loadedSoundFonts.push(soundFont);
				this.isSoundFontLoaded = true;
				this.soundFontLoaded.trigger();
				Logger.debug("AlphaSynth", "soundFont successfully loaded");
				this._checkReadyForPlayback();
			} catch (e) {
				Logger.error("AlphaSynth", `Could not load soundfont from bytes ${e}`);
				this.soundFontLoadFailed.trigger(e);
			}
		}
		_checkReadyForPlayback() {
			if (this.isReadyForPlayback) {
				this.synthesizer.setupMetronomeChannel(this.sequencer.metronomeChannel, this.metronomeVolume);
				const programs = this.sequencer.instrumentPrograms;
				const percussionKeys = this.sequencer.percussionKeys;
				let append = false;
				for (const soundFont of this._loadedSoundFonts) {
					this.synthesizer.loadPresets(soundFont, programs, percussionKeys, append);
					append = true;
				}
				this.readyForPlayback.trigger();
			}
		}
		/**
		* Loads the given midi file for playback.
		* @param midi The midi file to load
		*/
		loadMidiFile(midi) {
			this.stop();
			try {
				Logger.debug("AlphaSynth", "Loading midi from model");
				this.sequencer.loadMidi(midi);
				this._isMidiLoaded = true;
				this._loadedMidiInfo = new PositionChangedEventArgs(0, this.sequencer.currentEndTime, 0, this.sequencer.currentEndTick, false, this.sequencer.currentTempo, this.sequencer.modifiedTempo);
				this.midiLoaded.trigger(this._loadedMidiInfo);
				Logger.debug("AlphaSynth", "Midi successfully loaded");
				this._checkReadyForPlayback();
				this.tickPosition = 0;
			} catch (e) {
				Logger.error("AlphaSynth", `Could not load midi from model ${e}`);
				this.midiLoadFailed.trigger(e);
			}
		}
		applyTranspositionPitches(transpositionPitches) {
			this.synthesizer.applyTranspositionPitches(transpositionPitches);
		}
		setChannelTranspositionPitch(channel, semitones) {
			this.synthesizer.setChannelTranspositionPitch(channel, semitones);
		}
		setChannelMute(channel, mute) {
			this.synthesizer.channelSetMute(channel, mute);
		}
		resetChannelStates() {
			this.synthesizer.resetChannelStates();
		}
		setChannelSolo(channel, solo) {
			this.synthesizer.channelSetSolo(channel, solo);
		}
		setChannelVolume(channel, volume) {
			volume = Math.max(volume, SynthConstants.MinVolume);
			this.synthesizer.channelSetMixVolume(channel, volume);
		}
		_onSamplesPlayed(sampleCount) {
			if (sampleCount === 0) return;
			const playedMillis = sampleCount / this.synthesizer.outSampleRate * 1e3;
			this._notPlayedSamples -= sampleCount * SynthConstants.AudioChannels;
			this.updateTimePosition(this._timePosition + playedMillis, false);
			this.checkForFinish();
		}
		checkForFinish() {
			let startTick = 0;
			let endTick = 0;
			if (this.playbackRange && this.sequencer.isPlayingMain) {
				startTick = this.playbackRange.startTick;
				endTick = this.playbackRange.endTick;
			} else endTick = this.sequencer.currentEndTick;
			if (this._tickPosition >= endTick) {
				if (this._notPlayedSamples <= 0) {
					this._notPlayedSamples = 0;
					if (this.sequencer.isPlayingCountIn) {
						Logger.debug("AlphaSynth", "Finished playback (count-in)");
						this.sequencer.resetCountIn();
						this.timePosition = this.sequencer.currentTime;
						this._playInternal();
						this.output.resetSamples();
					} else if (this.sequencer.isPlayingOneTimeMidi) {
						Logger.debug("AlphaSynth", "Finished playback (one time)");
						this.output.resetSamples();
						this.state = PlayerState.Paused;
						this._stopOneTimeMidi();
					} else if (this.isLooping) {
						Logger.debug("AlphaSynth", "Finished playback (main looping)");
						this.finished.trigger();
						this.tickPosition = startTick;
						this._synthStopping = false;
					} else if (this.synthesizer.activeVoiceCount > 0) {
						if (!this._synthStopping) {
							Logger.debug("AlphaSynth", "Signaling synth to stop all voices (all samples played)");
							this.synthesizer.noteOffAll(true);
							this._synthStopping = true;
						}
					} else {
						this._synthStopping = false;
						Logger.debug("AlphaSynth", "Finished playback (main)");
						this.finished.trigger();
						this.stop();
					}
				} else if (!this._synthStopping) {
					Logger.debug("AlphaSynth", "Signaling synth to stop all voices (not all samples played)");
					this.synthesizer.noteOffAll(true);
					this._synthStopping = true;
				}
			}
		}
		_stopOneTimeMidi() {
			this.output.pause();
			this.output.resetSamples();
			this.synthesizer.noteOffAll(true);
			this.sequencer.resetOneTimeMidi();
			this.timePosition = this.sequencer.currentTime;
		}
		_createPositionChangedEventArgs(isSeek) {
			let currentTime = this._timePosition;
			let currentTick = this.sequencer.currentTimePositionToTickPosition(currentTime);
			const endTime = this.sequencer.currentEndTime;
			const endTick = this.sequencer.currentEndTick;
			if (currentTime > endTime) {
				currentTime = endTime;
				currentTick = endTick;
			}
			return new PositionChangedEventArgs(currentTime, endTime, currentTick, endTick, isSeek, this.sequencer.currentTempo, this.sequencer.modifiedTempo);
		}
		updateTimePosition(timePosition, isSeek) {
			this._timePosition = timePosition;
			const args = this._createPositionChangedEventArgs(isSeek);
			this._tickPosition = args.currentTick;
			const mode = this.sequencer.isPlayingMain ? "main" : this.sequencer.isPlayingCountIn ? "count-in" : "one-time";
			Logger.debug("AlphaSynth", `Position changed: (time: ${args.currentTime}/${args.endTime}, tick: ${args.currentTick}/${args.endTick}, Active Voices: ${this.synthesizer.activeVoiceCount} (${mode}), Tempo original: ${this.sequencer.currentTempo}, Tempo modified: ${this.sequencer.modifiedTempo})`);
			if (this.sequencer.isPlayingMain) {
				this._currentPosition = args;
				this.positionChanged.trigger(args);
			}
			if (isSeek) this.playedEventsQueue.clear();
			else {
				const playedEvents = [];
				while (!this.playedEventsQueue.isEmpty && this.playedEventsQueue.peek().time < args.currentTime) {
					const synthEvent = this.playedEventsQueue.dequeue();
					playedEvents.push(synthEvent.event);
				}
				if (playedEvents.length > 0) {
					playedEvents.reverse();
					this.midiEventsPlayed.trigger(new MidiEventsPlayedEventArgs(playedEvents));
				}
			}
		}
		/**
		* @lateinit
		*/
		ready;
		readyForPlayback = new EventEmitter();
		finished = new EventEmitter();
		soundFontLoaded = new EventEmitter();
		soundFontLoadFailed = new EventEmitterOfT();
		/**
		* @lateinit
		*/
		midiLoaded;
		midiLoadFailed = new EventEmitterOfT();
		/**
		* @lateinit
		*/
		stateChanged;
		/**
		* @lateinit
		*/
		positionChanged;
		midiEventsPlayed = new EventEmitterOfT();
		/**
		* @lateinit
		*/
		playbackRangeChanged;
		/**
		* @internal
		*/
		hasSamplesForProgram(program) {
			return this.synthesizer.hasSamplesForProgram(program);
		}
		/**
		* @internal
		*/
		hasSamplesForPercussion(key) {
			return this.synthesizer.hasSamplesForPercussion(key);
		}
		loadBackingTrack(_score) {}
		updateSyncPoints(_syncPoints) {}
	};
	/**
	* This is the main synthesizer component which can be used to
	* play a {@link MidiFile} via a {@link ISynthOutput}.
	* @public
	*/
	var AlphaSynth = class extends AlphaSynthBase {
		/**
		* Initializes a new instance of the {@link AlphaSynth} class.
		* @param output The output to use for playing the generated samples.
		*/
		constructor(output, bufferTimeInMilliseconds) {
			super(output, new TinySoundFont(output.sampleRate), bufferTimeInMilliseconds);
		}
		/**
		* Creates a new audio exporter, initialized with the given data.
		* @param options The export options to use.
		* The track volume and transposition pitches must lists must be filled with midi channels.
		* @param midi The midi file to use.
		* @param syncPoints The sync points to use
		* @param transpositionPitches The initial transposition pitches to apply.
		* @param transpositionPitches The initial transposition pitches to apply.
		*/
		exportAudio(options, midi, syncPoints, mainTranspositionPitches) {
			const exporter = new AlphaSynthAudioExporter(options);
			exporter.loadMidiFile(midi);
			if (options.useSyncPoints) exporter.updateSyncPoints(syncPoints);
			exporter.applyTranspositionPitches(mainTranspositionPitches);
			for (const [channel, semitones] of options.trackTranspositionPitches) exporter.setChannelTranspositionPitch(channel, semitones);
			for (const [channel, volume] of options.trackVolume) exporter.channelSetMixVolume(channel, volume);
			if (options.soundFonts) for (const f of options.soundFonts) exporter.loadSoundFont(f);
			else exporter.loadPresets(this.synthesizer.presets);
			if (options.playbackRange) exporter.limitExport(options.playbackRange);
			exporter.setup();
			return exporter;
		}
	};
	/**
	* A audio exporter allowing streaming synthesis of audio samples with a fixed configuration.
	* @public
	*/
	var AlphaSynthAudioExporter = class {
		_synth;
		_sequencer;
		constructor(options) {
			this._synth = new TinySoundFont(options.sampleRate);
			this._sequencer = new MidiFileSequencer(this._synth);
			this._synth.masterVolume = Math.max(options.masterVolume, SynthConstants.MinVolume);
			this._synth.metronomeVolume = Math.max(options.metronomeVolume, SynthConstants.MinVolume);
		}
		/**
		* Loads the specified sound font.
		* @param data The soundfont data.
		*/
		loadSoundFont(data) {
			const input = ByteBuffer.fromBuffer(data);
			const soundFont = new Hydra();
			soundFont.load(input);
			const programs = this._sequencer.instrumentPrograms;
			const percussionKeys = this._sequencer.percussionKeys;
			this._synth.loadPresets(soundFont, programs, percussionKeys, true);
		}
		/**
		* Loads the specified presets.
		* @param presets The presets to use.
		* @internal
		*/
		loadPresets(presets) {
			this._synth.presets = presets;
		}
		/**
		* Limits the time range for which the export is done.
		* @param range The time range
		*/
		limitExport(range) {
			this._sequencer.mainPlaybackRange = range;
			this._sequencer.mainSeek(this._sequencer.mainTickPositionToTimePosition(range.startTick));
		}
		/**
		* Sets the transposition pitch of a given channel. This pitch is additionally applied beside the
		* ones applied already via {@link applyTranspositionPitches}.
		* @param channel The channel number
		* @param semitones The number of semitones to apply as pitch offset.
		*/
		setChannelTranspositionPitch(channel, semitones) {
			this._synth.setChannelTranspositionPitch(channel, semitones);
		}
		/**
		* Applies the given transposition pitches used for general pitch changes that should be applied to the song.
		* Used for general transpositions applied to the file.
		* @param transpositionPitches A map defining for a given list of midi channels the number of semitones that should be adjusted.
		*/
		applyTranspositionPitches(mainTranspositionPitches) {
			this._synth.applyTranspositionPitches(mainTranspositionPitches);
		}
		/**
		* Loads the given midi file for synthesis.
		* @param midi The midi file.
		*/
		loadMidiFile(midi) {
			this._sequencer.loadMidi(midi);
		}
		/**
		* Updates the sync points used for time synchronization with a backing track.
		* @param syncPoints  The sync points.
		*/
		updateSyncPoints(syncPoints) {
			this._sequencer.mainUpdateSyncPoints(syncPoints);
		}
		/**
		* Sets the current and initial volume of the given channel.
		* @param channel The channel number.
		* @param volume The volume of of the channel (0.0-1.0)
		*/
		channelSetMixVolume(channel, volume) {
			volume = Math.max(volume, SynthConstants.MinVolume);
			this._synth.channelSetMixVolume(channel, volume);
		}
		_generatedAudioCurrentTime = 0;
		_generatedAudioEndTime = 0;
		setup() {
			this._synth.setupMetronomeChannel(this._sequencer.metronomeChannel, this._synth.metronomeVolume);
			const syncPoints = this._sequencer.currentSyncPoints;
			const alphaTabEndTime = this._sequencer.currentEndTime;
			if (syncPoints.length === 0) this._generatedAudioEndTime = alphaTabEndTime;
			else {
				const lastSyncPoint = syncPoints[syncPoints.length - 1];
				let endTime = lastSyncPoint.syncTime;
				const remainingTicks = this._sequencer.currentEndTick - lastSyncPoint.synthTick;
				if (remainingTicks > 0) endTime += MidiUtils.ticksToMillis(remainingTicks, lastSyncPoint.syncBpm);
				this._generatedAudioEndTime = endTime;
			}
		}
		render(milliseconds) {
			if (this._sequencer.isFinished) return;
			const oneMicroBufferMillis = SynthConstants.MicroBufferSize * 1e3 / this._synth.outSampleRate;
			const microBufferCount = Math.ceil(milliseconds / oneMicroBufferMillis);
			let samples = new Float32Array(SynthConstants.MicroBufferSize * microBufferCount * SynthConstants.AudioChannels);
			const syncPoints = this._sequencer.currentSyncPoints;
			let bufferPos = 0;
			let subBufferTime = this._generatedAudioCurrentTime;
			for (let i = 0; i < microBufferCount; i++) {
				if (syncPoints.length > 0) {
					this._sequencer.currentUpdateSyncPoints(subBufferTime);
					this._sequencer.currentUpdateCurrentTempo(this._sequencer.currentTime);
					const newSpeed = this._sequencer.syncPointTempo / this._sequencer.currentTempo;
					if (this._sequencer.playbackSpeed !== newSpeed) this._sequencer.playbackSpeed = newSpeed;
				}
				this._sequencer.fillMidiEventQueue();
				this._synth.synthesize(samples, bufferPos, SynthConstants.MicroBufferSize);
				bufferPos += SynthConstants.MicroBufferSize * SynthConstants.AudioChannels;
				subBufferTime += oneMicroBufferMillis;
				if (this._sequencer.isFinished) break;
			}
			if (bufferPos < samples.length) samples = samples.subarray(0, bufferPos);
			const chunk = new AudioExportChunk();
			chunk.currentTime = this._generatedAudioCurrentTime;
			chunk.endTime = this._generatedAudioEndTime;
			chunk.currentTick = this._sequencer.currentTimePositionToTickPosition(this._sequencer.currentTime);
			chunk.endTick = this._sequencer.currentEndTick;
			this._generatedAudioCurrentTime += milliseconds;
			chunk.samples = samples;
			if (this._sequencer.isFinished) this._synth.noteOffAll(true);
			return chunk;
		}
	};
	//#endregion
	//#region src/synth/BackingTrackPlayer.ts
	/**
	* @internal
	*/
	var BackingTrackAudioSynthesizer = class {
		_midiEventQueue = new Queue();
		masterVolume = 1;
		metronomeVolume = 0;
		outSampleRate = 44100;
		currentTempo = 120;
		timeSignatureNumerator = 4;
		timeSignatureDenominator = 4;
		activeVoiceCount = 0;
		output;
		noteOffAll(_immediate) {}
		resetSoft() {}
		resetPresets() {}
		loadPresets(_hydra, _instrumentPrograms, _percussionKeys, _append) {}
		setupMetronomeChannel(_metronomeChannel, _metronomeVolume) {}
		synthesizeSilent(_sampleCount) {
			this.fakeSynthesize();
		}
		_processMidiMessage(_e) {}
		dispatchEvent(synthEvent) {
			this._midiEventQueue.enqueue(synthEvent);
		}
		synthesize(_buffer, _bufferPos, _sampleCount) {
			return this.fakeSynthesize();
		}
		fakeSynthesize() {
			const processedEvents = [];
			while (!this._midiEventQueue.isEmpty) {
				const m = this._midiEventQueue.dequeue();
				if (m.isMetronome && this.metronomeVolume > 0) {} else if (m.event) this._processMidiMessage(m.event);
				processedEvents.push(m);
			}
			return processedEvents;
		}
		applyTranspositionPitches(_transpositionPitches) {}
		setChannelTranspositionPitch(_channel, _semitones) {}
		channelSetMute(_channel, _mute) {}
		channelSetSolo(_channel, _solo) {}
		resetChannelStates() {}
		channelSetMixVolume(_channel, _volume) {}
		hasSamplesForProgram(_program) {
			return true;
		}
		hasSamplesForPercussion(_key) {
			return true;
		}
	};
	/**
	* @internal
	*/
	var BackingTrackPlayer = class extends AlphaSynthBase {
		_backingTrackOutput;
		constructor(backingTrackOutput, bufferTimeInMilliseconds) {
			super(backingTrackOutput, new BackingTrackAudioSynthesizer(), bufferTimeInMilliseconds);
			this.synthesizer.output = backingTrackOutput;
			this._backingTrackOutput = backingTrackOutput;
			backingTrackOutput.timeUpdate.on((timePosition) => {
				const alphaTabTimePosition = this.sequencer.mainTimePositionFromBackingTrack(timePosition, backingTrackOutput.backingTrackDuration);
				this.sequencer.fillMidiEventQueueToEndTime(alphaTabTimePosition);
				this.synthesizer.fakeSynthesize();
				this.updateTimePosition(alphaTabTimePosition, false);
				this.checkForFinish();
			});
		}
		updateMasterVolume(value) {
			super.updateMasterVolume(value);
			this._backingTrackOutput.masterVolume = value;
		}
		updatePlaybackSpeed(value) {
			super.updatePlaybackSpeed(value);
			this._backingTrackOutput.playbackRate = value;
		}
		onSampleRequest() {}
		loadMidiFile(midi) {
			if (!this.isSoundFontLoaded) {
				this.isSoundFontLoaded = true;
				this.soundFontLoaded.trigger();
			}
			super.loadMidiFile(midi);
		}
		updateTimePosition(timePosition, isSeek) {
			super.updateTimePosition(timePosition, isSeek);
			if (isSeek) this._backingTrackOutput.seekTo(this.sequencer.mainTimePositionToBackingTrack(timePosition, this._backingTrackOutput.backingTrackDuration));
		}
		loadBackingTrack(score) {
			const backingTrackInfo = score.backingTrack;
			if (backingTrackInfo) {
				this._backingTrackOutput.loadBackingTrack(backingTrackInfo);
				this.timePosition = 0;
			}
		}
		updateSyncPoints(syncPoints) {
			this.sequencer.mainUpdateSyncPoints(syncPoints);
			this.tickPosition = this.tickPosition;
		}
	};
	//#endregion
	//#region src/platform/worker/AlphaSynthAudioExporterWorkerApi.ts
	/**
	* @internal
	*/
	var AlphaSynthAudioExporterWorkerApi = class AlphaSynthAudioExporterWorkerApi {
		static _nextExporterId = 1;
		_worker;
		_unsubscribe;
		_exporterId;
		_ownsWorker;
		_promise = null;
		constructor(synthWorker, ownsWorker) {
			this._exporterId = AlphaSynthAudioExporterWorkerApi._nextExporterId++;
			this._worker = synthWorker;
			this._ownsWorker = ownsWorker;
		}
		async initialize(options, midi, syncPoints, transpositionPitches) {
			const onmessage = (e) => this.handleWorkerMessage(e);
			this._worker.worker.addEventListener("message", onmessage);
			this._unsubscribe = () => {
				this._worker.worker.removeEventListener("message", onmessage);
			};
			this._promise = Promise.withResolvers();
			this._worker.worker.postMessage({
				cmd: "alphaSynth.exporter.initialize",
				exporterId: this._exporterId,
				options: Environment.prepareForPostMessage(options),
				midi: JsonConverter.midiFileToJsObject(Environment.prepareForPostMessage(midi)),
				syncPoints: Environment.prepareForPostMessage(syncPoints),
				transpositionPitches: Environment.prepareForPostMessage(transpositionPitches)
			});
			await this._promise.promise;
		}
		handleWorkerMessage(e) {
			const data = e.data;
			switch (data.cmd) {
				case "alphaSynth.exporter.initialized":
					if (data.exporterId !== this._exporterId) return;
					this._promise?.resolve(null);
					this._promise = null;
					break;
				case "alphaSynth.exporter.error":
					if (data.exporterId !== this._exporterId) return;
					this._promise?.reject(data.error);
					this._promise = null;
					break;
				case "alphaSynth.exporter.rendered":
					if (data.exporterId !== this._exporterId) return;
					this._promise?.resolve(data.chunk);
					this._promise = null;
					break;
				case "alphaSynth.destroyed":
					this._promise?.reject(new AlphaTabError(AlphaTabErrorType.General, "Worker was destroyed"));
					this._promise = null;
					break;
			}
		}
		async render(milliseconds) {
			if (this._promise) throw new AlphaTabError(AlphaTabErrorType.General, "There is already an ongoing operation, wait for initialize to complete before requesting render");
			this._promise = Promise.withResolvers();
			this._worker.worker.postMessage({
				cmd: "alphaSynth.exporter.render",
				exporterId: this._exporterId,
				milliseconds
			});
			return await this._promise.promise;
		}
		destroy() {
			this._worker.worker.postMessage({
				cmd: "alphaSynth.exporter.destroy",
				exporterId: this._exporterId
			});
			this._unsubscribe();
			if (this._ownsWorker) this._worker.destroy();
		}
		[Symbol.dispose]() {
			this.destroy();
		}
	};
	//#endregion
	//#region src/rendering/RenderFinishedEventArgs.ts
	/**
	* This eventargs define the details about the rendering and layouting process and are
	* provided whenever a part of of the music sheet is rendered.
	* @public
	*/
	var RenderFinishedEventArgs = class {
		/**
		* Gets or sets the unique id of this event args.
		*/
		id = ModelUtils.newGuid();
		/**
		* A value indicating whether the currently rendered viewport can be reused.
		* @remarks
		* If set to true, the viewport does NOT need to be cleared as a similar
		* content will be rendered.
		* If set to false, the viewport and any visual partials should be cleared
		* as it could lead to UI disturbances otherwise.
		*
		* The viewport can be typically used on resize renders or if the user supplied
		* a rendering hint that the new score is "similar" to the old one (e.g. in case of live-editing).
		*/
		reuseViewport = true;
		/**
		* Gets or sets the x position of the current rendering result.
		*/
		x = 0;
		/**
		* Gets or sets the y position of the current rendering result.
		*/
		y = 0;
		/**
		* Gets or sets the width of the current rendering result.
		*/
		width = 0;
		/**
		* Gets or sets the height of the current rendering result.
		*/
		height = 0;
		/**
		* Gets or sets the currently known total width of the final music sheet.
		*/
		totalWidth = 0;
		/**
		* Gets or sets the currently known total height of the final music sheet.
		*/
		totalHeight = 0;
		/**
		* Gets or sets the index of the first masterbar that was rendered in this result.
		*/
		firstMasterBarIndex = -1;
		/**
		* Gets or sets the index of the last masterbar that was rendered in this result.
		*/
		lastMasterBarIndex = -1;
		/**
		* Gets or sets the render engine specific result object which contains the rendered music sheet.
		*/
		renderResult = null;
	};
	//#endregion
	//#region src/rendering/ScoreRenderer.ts
	/**
	* This is the main wrapper of the rendering engine which
	* can render a single track of a score object into a notation sheet.
	* @public
	*/
	var ScoreRenderer = class {
		_currentLayoutMode = LayoutMode.Page;
		_currentRenderEngine = null;
		_renderedTracks = null;
		canvas = null;
		score = null;
		tracks = null;
		/**
		* @internal
		*/
		layout = null;
		settings;
		boundsLookup = null;
		width = 0;
		/**
		* Initializes a new instance of the {@link ScoreRenderer} class.
		* @param settings The settings to use for rendering.
		*/
		constructor(settings) {
			this.settings = settings;
			this._recreateCanvas();
			this._recreateLayout();
		}
		destroy() {
			this.score = null;
			this.canvas?.destroy();
			this.canvas = null;
			this.layout = null;
			this.boundsLookup = null;
			this.tracks = null;
		}
		_recreateCanvas() {
			if (this._currentRenderEngine !== this.settings.core.engine) {
				this.canvas?.destroy();
				this.canvas = Environment.getRenderEngineFactory(this.settings.core.engine).createCanvas();
				this._currentRenderEngine = this.settings.core.engine;
				return true;
			}
			return false;
		}
		_recreateLayout() {
			if (!this.layout || this._currentLayoutMode !== this.settings.display.layoutMode) {
				this.layout = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).createLayout(this);
				this._currentLayoutMode = this.settings.display.layoutMode;
				return true;
			}
			return false;
		}
		renderScore(score, trackIndexes, renderHints) {
			try {
				this.score = score;
				let tracks = null;
				if (score != null && trackIndexes != null) {
					if (!trackIndexes) tracks = score.tracks.slice(0);
					else {
						tracks = [];
						for (const track of trackIndexes) if (track >= 0 && track < score.tracks.length) tracks.push(score.tracks[track]);
					}
					if (tracks.length === 0 && score.tracks.length > 0) tracks.push(score.tracks[0]);
				}
				this.tracks = tracks;
				this.render(renderHints);
			} catch (e) {
				this.error.trigger(e);
			}
		}
		/**
		* Initiates rendering fof the given tracks.
		* @param tracks The tracks to render.
		*/
		renderTracks(tracks) {
			if (tracks.length === 0) this.score = null;
			else this.score = tracks[0].score;
			this.tracks = tracks;
			this.render();
		}
		updateSettings(settings) {
			this.settings = settings;
		}
		renderResult(resultId) {
			try {
				const layout = this.layout;
				if (layout) {
					Logger.debug("Rendering", `Request render of lazy partial ${resultId}`);
					layout.renderLazyPartial(resultId);
				} else Logger.warning("Rendering", `Request render of lazy partial ${resultId} ignored, no layout exists`);
			} catch (e) {
				this.error.trigger(e);
			}
		}
		render(renderHints) {
			if (this.width === 0) {
				Logger.warning("Rendering", "AlphaTab skipped rendering because of width=0 (element invisible)", null);
				return;
			}
			if (renderHints?.firstChangedMasterBar !== void 0 && this.boundsLookup) this.boundsLookup.resetForPartialUpdate();
			else this.boundsLookup = new BoundsLookup();
			this._recreateCanvas();
			this.canvas.lineWidth = 1;
			this.canvas.settings = this.settings;
			if (!this.tracks || this.tracks.length === 0 || !this.score) {
				Logger.debug("Rendering", "Clearing rendered tracks because no score or tracks are set");
				this.preRender.trigger(false);
				this._renderedTracks = null;
				this._onRenderFinished();
				this.postRenderFinished.trigger();
				Logger.debug("Rendering", "Clearing finished");
			} else {
				Logger.debug("Rendering", `Rendering ${this.tracks.length} tracks`);
				for (let i = 0; i < this.tracks.length; i++) {
					const track = this.tracks[i];
					Logger.debug("Rendering", `Track ${i}: ${track.name}`);
				}
				this.preRender.trigger(false);
				this._recreateLayout();
				this._layoutAndRender(renderHints);
				Logger.debug("Rendering", "Rendering finished");
			}
		}
		resizeRender() {
			if (this._recreateLayout() || this._recreateCanvas() || this._renderedTracks !== this.tracks || !this.tracks) {
				Logger.debug("Rendering", "Starting full rerendering due to layout or canvas change", null);
				this.render();
			} else if (this.layout.supportsResize) {
				Logger.debug("Rendering", "Starting optimized rerendering for resize");
				this.boundsLookup = new BoundsLookup();
				this.preRender.trigger(true);
				this.canvas.settings = this.settings;
				this.layout.resize();
				this._onRenderFinished();
				this.postRenderFinished.trigger();
			} else Logger.debug("Rendering", "Current layout does not support dynamic resizing, nothing was done", null);
			Logger.debug("Rendering", "Resize finished");
		}
		_layoutAndRender(renderHints) {
			Logger.debug("Rendering", `Rendering at scale ${this.settings.display.scale} with layout ${this.layout.name}`, null);
			this.layout.layoutAndRender(renderHints);
			this._renderedTracks = this.tracks;
			this._onRenderFinished();
			this.postRenderFinished.trigger();
		}
		preRender = new EventEmitterOfT();
		renderFinished = new EventEmitterOfT();
		partialRenderFinished = new EventEmitterOfT();
		partialLayoutFinished = new EventEmitterOfT();
		postRenderFinished = new EventEmitter();
		error = new EventEmitterOfT();
		_onRenderFinished() {
			this.boundsLookup?.finish(this.settings.display.scale);
			const e = new RenderFinishedEventArgs();
			e.totalHeight = this.layout.height;
			e.totalWidth = this.layout.width;
			e.renderResult = this.canvas.onRenderFinished();
			this.renderFinished.trigger(e);
		}
	};
	//#endregion
	//#region src/platform/javascript/BrowserUiFacade.ts
	/**
	* @target web
	* @internal
	*/
	var BrowserUiFacade = class BrowserUiFacade {
		_fontCheckers = /* @__PURE__ */ new Map();
		_api;
		_contents = null;
		_file = null;
		_totalResultCount = 0;
		_initialTrackIndexes = null;
		_intersectionObserver;
		_barToElementLookup = /* @__PURE__ */ new Map();
		_resultIdToElementLookup = /* @__PURE__ */ new Map();
		_webFont;
		rootContainerBecameVisible = new EventEmitter();
		canRenderChanged = new EventEmitter();
		get resizeThrottle() {
			return 10;
		}
		rootContainer;
		areWorkersSupported;
		get canRender() {
			return this._areAllFontsLoaded();
		}
		_areAllFontsLoaded() {
			let isAnyNotLoaded = false;
			for (const checker of this._fontCheckers.values()) if (!checker.isFontLoaded) isAnyNotLoaded = true;
			if (isAnyNotLoaded) return false;
			Logger.debug("Font", `All fonts loaded: ${this._fontCheckers.size}`);
			return true;
		}
		_onFontLoaded(family) {
			FontSizes.generateFontLookup(family);
			if (this._areAllFontsLoaded()) this.canRenderChanged.trigger();
		}
		constructor(rootElement) {
			if (Environment.webPlatform !== WebPlatform.Browser && Environment.webPlatform !== WebPlatform.BrowserModule) throw new AlphaTabError(AlphaTabErrorType.General, "Usage of AlphaTabApi is only possible in browser environments. For usage in node use the Low Level APIs");
			rootElement.classList.add("alphaTab");
			this.rootContainer = new HtmlElementContainer(rootElement);
			this.areWorkersSupported = "Worker" in window;
			this._intersectionObserver = new IntersectionObserver(this._onElementVisibilityChanged.bind(this), { threshold: [
				0,
				.01,
				1
			] });
			this._intersectionObserver.observe(rootElement);
		}
		_onElementVisibilityChanged(entries) {
			for (const e of entries) {
				const htmlElement = e.target;
				if (htmlElement === this.rootContainer.element) {
					if (e.isIntersecting) {
						this.rootContainerBecameVisible.trigger();
						this._intersectionObserver.unobserve(this.rootContainer.element);
					}
				} else if ("layoutResultId" in htmlElement && this._api.settings.core.enableLazyLoading) {
					const placeholder = htmlElement;
					if (e.isIntersecting) {
						if (placeholder.renderedResultId !== placeholder.layoutResultId) if (this._resultIdToElementLookup.has(placeholder.layoutResultId)) {
							if (placeholder.resultState !== 1) {
								placeholder.resultState = 1;
								this._api.renderer.renderResult(placeholder.layoutResultId);
							}
						} else htmlElement.replaceChildren();
						else if (placeholder.resultState === 3) {
							htmlElement.replaceChildren(...placeholder.renderedResult);
							placeholder.resultState = 2;
						}
					} else if (placeholder.resultState === 2) {
						placeholder.resultState = 3;
						placeholder.replaceChildren();
					}
				}
			}
		}
		createWorkerRenderer() {
			let worker;
			try {
				worker = BrowserUiFacade.createAlphaTabWebWorker(this._api.settings);
				return new AlphaTabWorkerScoreRenderer(this._api, worker);
			} catch (e) {
				Logger.error("Renderer", "Failed to create worker for background rendering, fallback to non-worker rendering", e);
				return new ScoreRenderer(this._api.settings);
			}
		}
		initialize(api, raw) {
			this._api = api;
			let settings;
			if (raw instanceof Settings) settings = raw;
			else settings = JsonConverter.jsObjectToSettings(raw);
			const dataAttributes = this._getDataAttributes();
			SettingsSerializer.fromJson(settings, dataAttributes);
			if (settings.notation.notationMode === NotationMode.SongBook) settings.setSongBookModeSettings();
			api.settings = settings;
			this._setupFontCheckers(settings);
			this._initialTrackIndexes = this.parseTracks(settings.core.tracks);
			this._contents = "";
			const element = api.container;
			if (settings.core.tex) {
				this._contents = element.element.textContent;
				element.element.innerText = "";
			}
			this._createStyleElements(settings);
			settings.display.resources.smuflFontFamilyName = this._webFont.familyName;
			this._file = settings.core.file;
		}
		_setupFontCheckers(settings) {
			for (const font of settings.display.resources.elementFonts.values()) this._registerFontChecker(font);
			this._registerFontChecker(settings.display.resources.graceFont);
			this._registerFontChecker(settings.display.resources.tablatureFont);
			this._registerFontChecker(settings.display.resources.numberedNotationFont);
			this._registerFontChecker(settings.display.resources.numberedNotationGraceFont);
		}
		_registerFontChecker(font) {
			if (!this._fontCheckers.has(font.families.join(", "))) {
				const checker = new FontLoadingChecker(font.families);
				this._fontCheckers.set(font.families.join(", "), checker);
				checker.fontLoaded.on(this._onFontLoaded.bind(this));
				checker.checkForFontAvailability();
			}
		}
		destroy() {
			const element = this.rootContainer.element;
			element.innerHTML = "";
			const webFont = this._webFont;
			const styleElement = webFont.elements.get(element.ownerDocument);
			if (styleElement) {
				styleElement.usages--;
				if (styleElement.usages <= 0) {
					styleElement.element.remove();
					webFont.elements.delete(element.ownerDocument);
				}
			}
			if (webFont.elements.size === 0) BrowserUiFacade._registeredWebFonts.delete(webFont.hash);
		}
		createCanvasElement() {
			const canvasElement = document.createElement("div");
			canvasElement.classList.add("at-surface", `at${this._webFont.fontSuffix}`);
			canvasElement.style.fontSize = "0";
			canvasElement.style.overflow = "hidden";
			canvasElement.style.lineHeight = "0";
			canvasElement.style.position = "relative";
			return new HtmlElementContainer(canvasElement);
		}
		setCanvasOverflow(canvasElement, overflow, isVertical) {
			const html = canvasElement.element;
			if (overflow === 0) {
				html.style.boxSizing = "";
				html.style.paddingRight = "";
				html.style.paddingBottom = "";
			} else if (isVertical) {
				html.style.boxSizing = "content-box";
				html.style.paddingBottom = `${overflow}px`;
			} else {
				html.style.boxSizing = "content-box";
				html.style.paddingRight = `${overflow}px`;
			}
		}
		triggerEvent(container, name, details = null, originalEvent) {
			const element = container.element;
			name = `alphaTab.${name}`;
			const e = document.createEvent("CustomEvent");
			const originalMouseEvent = originalEvent ? originalEvent.mouseEvent : null;
			e.initCustomEvent(name, false, false, details);
			if (originalMouseEvent) e.originalEvent = originalMouseEvent;
			element.dispatchEvent(e);
			if (window && "jQuery" in window) {
				const jquery = window.jQuery;
				const args = [];
				args.push(details);
				if (originalMouseEvent) args.push(originalMouseEvent);
				jquery(element).trigger(name, args);
			}
		}
		load(data, success, error) {
			if (data instanceof Score) {
				success(data);
				return true;
			}
			if (data instanceof ArrayBuffer) {
				const byteArray = new Uint8Array(data);
				success(ScoreLoader.loadScoreFromBytes(byteArray, this._api.settings));
				return true;
			}
			if (data instanceof Uint8Array) {
				success(ScoreLoader.loadScoreFromBytes(data, this._api.settings));
				return true;
			}
			if (typeof data === "string") {
				ScoreLoader.loadScoreAsync(data, success, error, this._api.settings);
				return true;
			}
			return false;
		}
		loadSoundFont(data, append) {
			if (!this._api.player) return false;
			if (data instanceof ArrayBuffer) {
				this._api.player.loadSoundFont(new Uint8Array(data), append);
				return true;
			}
			if (data instanceof Uint8Array) {
				this._api.player.loadSoundFont(data, append);
				return true;
			}
			if (typeof data === "string") {
				this._api.loadSoundFontFromUrl(data, append);
				return true;
			}
			return false;
		}
		initialRender() {
			this._api.renderer.preRender.on((_) => {
				this._totalResultCount = 0;
				this._resultIdToElementLookup.clear();
				this._barToElementLookup.clear();
			});
			const initialRender = () => {
				this._api.renderer.width = this.rootContainer.width | 0;
				this._api.renderer.updateSettings(this._api.settings);
				if (this._contents) {
					this._api.tex(this._contents, this._initialTrackIndexes ?? void 0);
					this._initialTrackIndexes = null;
				} else if (this._file) ScoreLoader.loadScoreAsync(this._file, (s) => {
					this._api.renderScore(s, this._initialTrackIndexes ?? void 0);
					this._initialTrackIndexes = null;
				}, (e) => {
					this._api.onError(e);
				}, this._api.settings);
			};
			if (!this.rootContainer.isVisible) this.rootContainerBecameVisible.on(initialRender);
			else initialRender();
		}
		_createStyleElements(settings) {
			const root = this._api.container.element.ownerDocument;
			BrowserUiFacade.createSharedStyleElement(root);
			const smuflFontSources = settings.core.smuflFontSources ?? CoreSettings.buildDefaultSmuflFontSources(settings.core.fontDirectory);
			const hash = BrowserUiFacade._cyrb53(smuflFontSources.values());
			const registeredWebFonts = BrowserUiFacade._registeredWebFonts;
			if (registeredWebFonts.has(hash)) {
				const webFont = registeredWebFonts.get(hash);
				webFont.checker.fontLoaded.on(this._onFontLoaded.bind(this));
				this._createStyleElement(webFont, root);
				this._webFont = webFont;
				return;
			}
			const fontSuffix = registeredWebFonts.size === 0 ? "" : String(registeredWebFonts.size);
			const familyName = `alphaTab${fontSuffix}`;
			const css = `
            @font-face {
                font-display: block;
                font-family: '${familyName}';
                src: ${Array.from(smuflFontSources.entries()).map((e) => `url(${JSON.stringify(e[1])}) format('${BrowserUiFacade._cssFormat(e[0])}')`).join(",")};
                font-weight: normal;
                font-style: normal;
            }
            .at-surface.at${fontSuffix} .at {
                font-family: '${familyName}';
                speak: none;
                font-style: normal;
                font-weight: normal;
                font-variant: normal;
                text-transform: none;
                line-height: 1;
                line-height: 1;
                -webkit-font-smoothing: antialiased;
                -moz-osx-font-smoothing: grayscale;
                font-size: ${settings.display.resources.engravingSettings.musicFontSize}px;
                overflow: visible !important;
            }`;
			const checker = new FontLoadingChecker([familyName]);
			checker.fontLoaded.on(this._onFontLoaded.bind(this));
			this._fontCheckers.set(familyName, checker);
			checker.checkForFontAvailability();
			const webFont = {
				hash,
				familyName,
				elements: /* @__PURE__ */ new Map(),
				fontSuffix,
				checker,
				cssSource: css
			};
			this._createStyleElement(webFont, root);
			registeredWebFonts.set(hash, webFont);
			this._webFont = webFont;
		}
		_createStyleElement(webFont, root) {
			if (webFont.elements.has(root)) {
				webFont.elements.get(root).usages++;
				return;
			}
			const styleElement = root.createElement("style");
			styleElement.id = `alphaTabStyle${webFont.fontSuffix}`;
			styleElement.innerHTML = webFont.cssSource;
			root.getElementsByTagName("head").item(0).appendChild(styleElement);
			webFont.elements.set(root, {
				element: styleElement,
				usages: 1
			});
		}
		static _cssFormat(format) {
			switch (format) {
				case FontFileFormat.EmbeddedOpenType: return "embedded-opentype";
				case FontFileFormat.Woff: return "woff";
				case FontFileFormat.Woff2: return "woff2";
				case FontFileFormat.OpenType: return "opentype";
				case FontFileFormat.TrueType: return "truetype";
				case FontFileFormat.Svg: return "svg";
			}
		}
		static _registeredWebFonts = /* @__PURE__ */ new Map();
		/**
		* cyrb53 (c) 2018 bryc (github.com/bryc)
		* License: Public domain (or MIT if needed). Attribution appreciated.
		* A fast and simple 53-bit string hash function with decent collision resistance.
		* Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity
		* @param str
		* @param seed
		* @returns
		*/
		static _cyrb53(strings, seed = 0) {
			let h1 = 3735928559 ^ seed;
			let h2 = 1103547991 ^ seed;
			for (const str of strings) for (let i = 0; i < str.length; i++) {
				const ch = str.charCodeAt(i);
				h1 = Math.imul(h1 ^ ch, 2654435761);
				h2 = Math.imul(h2 ^ ch, 1597334677);
			}
			h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507);
			h1 ^= Math.imul(h2 ^ h2 >>> 13, 3266489909);
			h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507);
			h2 ^= Math.imul(h1 ^ h1 >>> 13, 3266489909);
			return 4294967296 * (2097151 & h2) + (h1 >>> 0);
		}
		/**
		* Creates the default CSS styles used across all alphaTab instances.
		* @target web
		* @internal
		*/
		static createSharedStyleElement(root) {
			let styleElement = root.getElementById("alphaTabStyle");
			if (!styleElement) {
				styleElement = document.createElement("style");
				styleElement.id = "alphaTabStyleShared";
				styleElement.innerHTML = `
                .at-surface * {
                    cursor: default;
                    vertical-align: top;
                    overflow: visible;
                }
                .at-surface-svg text {
                    dominant-baseline: alphabetic;
                    white-space:pre;
                }`;
				document.getElementsByTagName("head").item(0).appendChild(styleElement);
			}
		}
		parseTracks(tracksData) {
			if (!tracksData) return [];
			const tracks = [];
			if (typeof tracksData === "string") try {
				if (tracksData === "all") return [-1];
				tracksData = JSON.parse(tracksData);
			} catch {
				tracksData = [0];
			}
			if (typeof tracksData === "number") tracks.push(tracksData);
			else if ("length" in tracksData) {
				const length = tracksData.length;
				const array = tracksData;
				for (let i = 0; i < length; i++) {
					const item = array[i];
					let value = 0;
					if (typeof item === "number") value = item;
					else if ("index" in item) value = item.index;
					else value = Number.parseInt(item.toString(), 10);
					if (value >= 0 || value === -1) tracks.push(value);
				}
			} else if ("index" in tracksData) tracks.push(tracksData.index);
			return tracks;
		}
		_getDataAttributes() {
			const dataAttributes = /* @__PURE__ */ new Map();
			const element = this._api.container.element;
			if (element.dataset) for (const key of Object.keys(element.dataset)) {
				let value = element.dataset[key];
				try {
					value = JSON.parse(value);
				} catch {
					if (value === "") value = null;
				}
				dataAttributes.set(key, value);
			}
			else for (let i = 0; i < element.attributes.length; i++) {
				const attr = element.attributes.item(i);
				const nodeName = attr.nodeName;
				if (nodeName.startsWith("data-")) {
					const keyParts = nodeName.substr(5).split("-");
					let key = keyParts[0];
					for (let j = 1; j < keyParts.length; j++) key += keyParts[j].substr(0, 1).toUpperCase() + keyParts[j].substr(1);
					let value = attr.nodeValue;
					try {
						value = JSON.parse(value);
					} catch {
						if (value === "") value = null;
					}
					dataAttributes.set(key, value);
				}
			}
			return dataAttributes;
		}
		beginUpdateRenderResults(renderResult) {
			if (!this._resultIdToElementLookup.has(renderResult.id)) return;
			const placeholder = this._resultIdToElementLookup.get(renderResult.id);
			const body = renderResult.renderResult;
			if (typeof body === "string") placeholder.innerHTML = body;
			else if ("nodeType" in body) placeholder.replaceChildren(body);
			placeholder.resultState = 2;
			placeholder.renderedResultId = renderResult.id;
			placeholder.renderedResult = Array.from(placeholder.children);
		}
		beginAppendRenderResults(renderResult) {
			const canvasElement = this._api.canvasElement.element;
			if (!renderResult) while (canvasElement.childElementCount > this._totalResultCount) {
				if (this._api.settings.core.enableLazyLoading) this._intersectionObserver.unobserve(canvasElement.lastChild);
				canvasElement.removeChild(canvasElement.lastElementChild);
			}
			else {
				let placeholder;
				if (this._totalResultCount < canvasElement.childElementCount) placeholder = canvasElement.childNodes.item(this._totalResultCount);
				else {
					placeholder = document.createElement("div");
					canvasElement.appendChild(placeholder);
				}
				placeholder.style.zIndex = "1";
				placeholder.style.position = "absolute";
				placeholder.style.left = `${renderResult.x}px`;
				placeholder.style.top = `${renderResult.y}px`;
				placeholder.style.width = `${renderResult.width}px`;
				placeholder.style.height = `${renderResult.height}px`;
				placeholder.style.display = "inline-block";
				placeholder.layoutResultId = renderResult.id;
				placeholder.resultState = 0;
				placeholder.renderedResultId = void 0;
				placeholder.renderedResult = void 0;
				if (!renderResult.reuseViewport) placeholder.textContent = "";
				this._resultIdToElementLookup.set(renderResult.id, placeholder);
				for (let i = renderResult.firstMasterBarIndex; i <= renderResult.lastMasterBarIndex; i++) if (i >= 0) this._barToElementLookup.set(i, placeholder);
				if (this._api.settings.core.enableLazyLoading) {
					this._intersectionObserver.unobserve(placeholder);
					this._intersectionObserver.observe(placeholder);
				}
				this._totalResultCount++;
			}
		}
		/**
		* This method creates the player. It detects browser compatibility and
		* initializes a alphaSynth version for the client.
		*/
		createWorkerPlayer() {
			let player = null;
			const supportsScriptProcessor = "ScriptProcessorNode" in window;
			if (window.isSecureContext && "AudioWorkletNode" in window && this._api.settings.player.outputMode === PlayerOutputMode.WebAudioAudioWorklets) {
				Logger.debug("Player", "Will use webworkers for synthesizing and web audio api with worklets for playback");
				let worker;
				try {
					worker = BrowserUiFacade.createAlphaSynthWebWorker(this._api.settings);
				} catch (e) {
					Logger.error("Player", "Failed to create worker for synthesizing audio", e);
					return null;
				}
				player = new AlphaSynthWebWorkerApi(new AlphaSynthAudioWorkletOutput(this._api.settings), this._api.settings, worker);
			} else if (supportsScriptProcessor) {
				Logger.debug("Player", "Will use webworkers for synthesizing and web audio api with ScriptProcessor for playback");
				let worker;
				try {
					worker = BrowserUiFacade.createAlphaSynthWebWorker(this._api.settings);
				} catch (e) {
					Logger.error("Player", "Failed to create worker for synthesizing audio", e);
					return null;
				}
				player = new AlphaSynthWebWorkerApi(new AlphaSynthScriptProcessorOutput(), this._api.settings, worker);
			}
			if (!player) Logger.error("Player", "Player requires webworkers and web audio api, browser unsupported", null);
			else player.ready.on(() => {
				if (this._api.settings.player.soundFont) this._api.loadSoundFontFromUrl(this._api.settings.player.soundFont, false);
			});
			return player;
		}
		createWorkerAudioExporter(synth) {
			const needNewWorker = synth === null || !(synth instanceof AlphaSynthWebWorkerApi);
			if (needNewWorker) synth = this.createWorkerPlayer();
			return new AlphaSynthAudioExporterWorkerApi(synth, needNewWorker);
		}
		beginInvoke(action) {
			window.requestAnimationFrame(() => {
				action();
			});
		}
		_highlightedElements = [];
		highlightElements(groupId, masterBarIndex) {
			const element = this._barToElementLookup.get(masterBarIndex);
			if (element) {
				const elementsToHighlight = element.getElementsByClassName(groupId);
				for (let i = 0; i < elementsToHighlight.length; i++) {
					elementsToHighlight.item(i).classList.add("at-highlight");
					this._highlightedElements.push(elementsToHighlight.item(i));
				}
			}
		}
		removeHighlights() {
			const highlightedElements = this._highlightedElements;
			if (!highlightedElements) return;
			for (const element of highlightedElements) element.classList.remove("at-highlight");
			this._highlightedElements = [];
		}
		destroyCursors() {
			const element = this._api.container.element;
			const cursorWrapper = element.querySelector(".at-cursors");
			element.removeChild(cursorWrapper);
		}
		createCursors() {
			const element = this._api.container.element;
			const cursorWrapper = document.createElement("div");
			cursorWrapper.classList.add("at-cursors");
			const selectionWrapper = document.createElement("div");
			selectionWrapper.classList.add("at-selection");
			const barCursorContainer = this.createScalingElement();
			const beatCursorContainer = this.createScalingElement();
			const barCursor = barCursorContainer.element;
			barCursor.classList.add("at-cursor-bar");
			const beatCursor = beatCursorContainer.element;
			beatCursor.classList.add("at-cursor-beat");
			element.style.position = "relative";
			element.style.textAlign = "left";
			cursorWrapper.style.position = "absolute";
			cursorWrapper.style.zIndex = "1000";
			cursorWrapper.style.display = "inline";
			cursorWrapper.style.pointerEvents = "none";
			selectionWrapper.style.position = "absolute";
			barCursor.style.position = "absolute";
			barCursor.style.left = "0";
			barCursor.style.top = "0";
			barCursor.style.willChange = "transform";
			barCursorContainer.width = 1;
			barCursorContainer.height = 1;
			barCursorContainer.setBounds(0, 0, 1, 1);
			beatCursor.style.position = "absolute";
			beatCursor.style.transition = "all 0s linear";
			beatCursor.style.left = "0";
			beatCursor.style.top = "0";
			beatCursor.style.willChange = "transform";
			beatCursorContainer.width = 3;
			beatCursorContainer.height = 1;
			beatCursorContainer.centerAtPosition = true;
			beatCursorContainer.setBounds(0, 0, 1, 1);
			element.insertBefore(cursorWrapper, element.firstChild);
			cursorWrapper.appendChild(selectionWrapper);
			cursorWrapper.appendChild(barCursor);
			cursorWrapper.appendChild(beatCursor);
			return new Cursors(new HtmlElementContainer(cursorWrapper), barCursorContainer, beatCursorContainer, new HtmlElementContainer(selectionWrapper));
		}
		getOffset(scrollContainer, container) {
			const element = container.element;
			const bounds = element.getBoundingClientRect();
			let top = bounds.top + element.ownerDocument.defaultView.pageYOffset;
			let left = bounds.left + element.ownerDocument.defaultView.pageXOffset;
			if (scrollContainer) {
				const scrollElement = scrollContainer.element;
				const nodeName = scrollElement.nodeName.toLowerCase();
				if (nodeName !== "html" && nodeName !== "body") {
					const scrollElementOffset = this.getOffset(null, scrollContainer);
					top = top + scrollElement.scrollTop - scrollElementOffset.y;
					left = left + scrollElement.scrollLeft - scrollElementOffset.x;
				}
			}
			const b = new Bounds();
			b.x = left;
			b.y = top;
			b.w = bounds.width;
			b.h = bounds.height;
			return b;
		}
		_scrollContainer = null;
		getScrollContainer() {
			if (this._scrollContainer) return this._scrollContainer;
			let scrollElement = typeof this._api.settings.player.scrollElement === "string" ? document.querySelector(this._api.settings.player.scrollElement) : this._api.settings.player.scrollElement;
			const nodeName = scrollElement.nodeName.toLowerCase();
			if (nodeName === "html" || nodeName === "body") if ("scrollingElement" in document) scrollElement = document.scrollingElement;
			else if (navigator.userAgent.indexOf("WebKit") !== -1) scrollElement = document.body;
			else scrollElement = document.documentElement;
			this._scrollContainer = new HtmlElementContainer(scrollElement);
			return this._scrollContainer;
		}
		createSelectionElement() {
			return this.createScalingElement();
		}
		createScalingElement() {
			const element = document.createElement("div");
			element.style.position = "absolute";
			const container = new ScalableHtmlElementContainer(element, 100, 100);
			container.width = 1;
			container.height = 1;
			container.setBounds(0, 0, 1, 1);
			return container;
		}
		scrollToY(element, scrollTargetY, speed) {
			this._internalScrollToY(element.element, scrollTargetY, speed);
		}
		scrollToX(element, scrollTargetY, speed) {
			this._internalScrollToX(element.element, scrollTargetY, speed);
		}
		stopScrolling(scrollElement) {
			const currentAnimation = this._scrollAnimationLookup.get(scrollElement.element);
			if (currentAnimation !== void 0) this._activeScrollAnimations.delete(currentAnimation);
		}
		get _nativeBrowserSmoothScroll() {
			const settings = this._api.settings.player;
			return settings.nativeBrowserSmoothScroll && settings.scrollMode !== ScrollMode.Smooth;
		}
		_scrollAnimationId = 0;
		_activeScrollAnimations = /* @__PURE__ */ new Set();
		_scrollAnimationLookup = /* @__PURE__ */ new Map();
		_internalScrollToY(element, scrollTargetY, speed) {
			if (this._nativeBrowserSmoothScroll) element.scrollTo({
				top: scrollTargetY,
				behavior: "smooth"
			});
			else this._internalScrollTo(element, element.scrollTop, scrollTargetY, speed, (scroll) => {
				element.scrollTop = scroll;
			});
		}
		_internalScrollTo(element, startScroll, endScroll, scrollDuration, setValue) {
			const currentAnimation = this._scrollAnimationLookup.get(element);
			if (currentAnimation !== void 0) this._activeScrollAnimations.delete(currentAnimation);
			if (scrollDuration === 0) {
				setValue(endScroll);
				return;
			}
			const animationId = this._scrollAnimationId++;
			this._scrollAnimationLookup.set(element, animationId);
			this._activeScrollAnimations.add(animationId);
			const diff = endScroll - startScroll;
			let start = 0;
			const step = (x) => {
				if (!this._activeScrollAnimations.has(animationId)) return;
				if (start === 0) start = x;
				const time = x - start;
				setValue(startScroll + diff * Math.min(time / scrollDuration, 1) | 0);
				if (time < scrollDuration) window.requestAnimationFrame(step);
				else this._activeScrollAnimations.delete(animationId);
			};
			window.requestAnimationFrame(step);
		}
		_internalScrollToX(element, scrollTargetX, speed) {
			if (this._nativeBrowserSmoothScroll) element.scrollTo({
				left: scrollTargetX,
				behavior: "smooth"
			});
			else this._internalScrollTo(element, element.scrollLeft, scrollTargetX, speed, (scroll) => {
				element.scrollLeft = scroll;
			});
		}
		createBackingTrackPlayer() {
			return new BackingTrackPlayer(new AudioElementBackingTrackSynthOutput(), this._api.settings.player.bufferTimeInMilliseconds);
		}
		throttle(action, delay) {
			let timeoutId = 0;
			return () => {
				Environment.globalThis.clearTimeout(timeoutId);
				timeoutId = Environment.globalThis.setTimeout(action, delay);
			};
		}
		/**
		* @internal
		*/
		static createAlphaTabWebWorker;
		/**
		* @internal
		*/
		static createAlphaSynthWebWorker;
		/**
		* @target web
		* @internal
		*/
		static createAlphaSynthAudioWorklet;
	};
	//#endregion
	//#region src/platform/javascript/AlphaSynthAudioWorkletOutput.ts
	/**
	* This class implements a HTML5 Web Audio API based audio output device
	* for alphaSynth using the modern Audio Worklets.
	* @target web
	* @internal
	*/
	var AlphaSynthWebWorklet = class AlphaSynthWebWorklet {
		static _isRegistered = false;
		static init() {
			if (AlphaSynthWebWorklet._isRegistered) return;
			AlphaSynthWebWorklet._isRegistered = true;
			registerProcessor("alphatab", class AlphaSynthWebWorkletProcessor extends AudioWorkletProcessor {
				static BufferSize = 4096;
				_outputBuffer = new Float32Array(0);
				_circularBuffer;
				_bufferCount = 0;
				_requestedBufferCount = 0;
				_isStopped = false;
				constructor(options) {
					super(options);
					Logger.debug("WebAudio", "creating processor");
					this._bufferCount = Math.floor(options.processorOptions.bufferTimeInMilliseconds * sampleRate / 1e3 / AlphaSynthWebWorkletProcessor.BufferSize);
					this._circularBuffer = new CircularSampleBuffer(AlphaSynthWebWorkletProcessor.BufferSize * this._bufferCount);
					this.port.addEventListener("message", (e) => this._handleMessage(e));
					this.port.start();
				}
				_handleMessage(e) {
					const data = e.data;
					switch (data.cmd) {
						case "alphaSynth.output.addSamples":
							const f = data.samples;
							this._circularBuffer.write(f, 0, f.length);
							this._requestedBufferCount--;
							break;
						case "alphaSynth.output.resetSamples":
							this._circularBuffer.clear();
							break;
						case "alphaSynth.output.stop":
							this._isStopped = true;
							break;
					}
				}
				process(_inputs, outputs, _parameters) {
					if (outputs.length !== 1 && outputs[0].length !== 2) return false;
					const left = outputs[0][0];
					const right = outputs[0][1];
					if (!left || !right) return true;
					const samples = left.length + right.length;
					let buffer = this._outputBuffer;
					if (buffer.length !== samples) {
						buffer = new Float32Array(samples);
						this._outputBuffer = buffer;
					}
					const samplesFromBuffer = this._circularBuffer.read(buffer, 0, Math.min(buffer.length, this._circularBuffer.count));
					let s = 0;
					const min = Math.min(left.length, samplesFromBuffer);
					for (let i = 0; i < min; i++) {
						left[i] = buffer[s++];
						right[i] = buffer[s++];
					}
					if (samplesFromBuffer < left.length) for (let i = samplesFromBuffer; i < left.length; i++) {
						left[i] = 0;
						right[i] = 0;
					}
					this.port.postMessage({
						cmd: "alphaSynth.output.samplesPlayed",
						samples: samplesFromBuffer / SynthConstants.AudioChannels
					});
					this._requestBuffers();
					return this._circularBuffer.count > 0 || !this._isStopped;
				}
				_requestBuffers() {
					const halfBufferCount = this._bufferCount / 2 | 0;
					const halfSamples = halfBufferCount * AlphaSynthWebWorkletProcessor.BufferSize;
					if (this._circularBuffer.count + this._requestedBufferCount * AlphaSynthWebWorkletProcessor.BufferSize < halfSamples) {
						for (let i = 0; i < halfBufferCount; i++) this.port.postMessage({ cmd: "alphaSynth.output.sampleRequest" });
						this._requestedBufferCount += halfBufferCount;
					}
				}
			});
		}
	};
	/**
	* This class implements a HTML5 Web Audio API based audio output device
	* for alphaSynth. It can be controlled via a JS API.
	* @target web
	* @internal
	*/
	var AlphaSynthAudioWorkletOutput = class extends AlphaSynthWebAudioOutputBase {
		_worklet = null;
		_bufferTimeInMilliseconds = 0;
		_settings;
		_boundHandleMessage;
		_pendingEvents;
		constructor(settings) {
			super();
			this._settings = settings;
			this._boundHandleMessage = (e) => this._handleMessage(e);
		}
		open(bufferTimeInMilliseconds) {
			super.open(bufferTimeInMilliseconds);
			this._bufferTimeInMilliseconds = bufferTimeInMilliseconds;
			this.onReady();
		}
		play() {
			super.play();
			const ctx = this.context;
			if (this._pendingEvents) this._pendingEvents = void 0;
			BrowserUiFacade.createAlphaSynthAudioWorklet(ctx, this._settings).then(() => {
				this._worklet = new AudioWorkletNode(ctx, "alphatab", {
					numberOfOutputs: 1,
					outputChannelCount: [2],
					processorOptions: { bufferTimeInMilliseconds: this._bufferTimeInMilliseconds }
				});
				this._worklet.port.addEventListener("message", this._boundHandleMessage);
				this._worklet.port.start();
				this.source.connect(this._worklet);
				this.source.start(0);
				this._worklet.connect(ctx.destination);
				const pending = this._pendingEvents;
				if (pending) {
					for (const e of pending) this._worklet.port.postMessage(e);
					this._pendingEvents = void 0;
				}
			}, (reason) => {
				Logger.error("WebAudio", `Audio Worklet creation failed: reason=${reason}`);
			});
		}
		_handleMessage(e) {
			const data = e.data;
			switch (data.cmd) {
				case "alphaSynth.output.samplesPlayed":
					this.onSamplesPlayed(data.samples);
					break;
				case "alphaSynth.output.sampleRequest":
					this.onSampleRequest();
					break;
			}
		}
		pause() {
			super.pause();
			if (this._worklet) {
				this._worklet.port.postMessage({ cmd: "alphaSynth.output.stop" });
				this._worklet.port.removeEventListener("message", this._boundHandleMessage);
				this._worklet.disconnect();
			}
			this._worklet = null;
			this._pendingEvents = void 0;
		}
		_postWorkerMessage(message) {
			const worklet = this._worklet;
			if (worklet) worklet.port.postMessage(message);
			else {
				this._pendingEvents ??= [];
				this._pendingEvents.push(message);
			}
		}
		addSamples(f) {
			this._postWorkerMessage({
				cmd: "alphaSynth.output.addSamples",
				samples: Environment.prepareForPostMessage(f)
			});
		}
		resetSamples() {
			this._postWorkerMessage({ cmd: "alphaSynth.output.resetSamples" });
		}
	};
	//#endregion
	//#region src/platform/javascript/Html5Canvas.ts
	/**
	* A canvas implementation for HTML5 canvas
	* @target web
	* @internal
	*/
	var Html5Canvas = class {
		_measureCanvas;
		_measureContext;
		_canvas = null;
		_context;
		_color = new Color(0, 0, 0, 255);
		_font = new Font("Arial", 10, FontStyle.Plain);
		_musicFont;
		_lineWidth = 0;
		settings;
		constructor() {
			this._measureCanvas = document.createElement("canvas");
			this._measureCanvas.width = 10;
			this._measureCanvas.height = 10;
			this._measureCanvas.style.width = "10px";
			this._measureCanvas.style.height = "10px";
			this._measureContext = this._measureCanvas.getContext("2d");
			this._measureContext.textBaseline = "hanging";
		}
		destroy() {}
		onRenderFinished() {
			return null;
		}
		beginRender(width, height) {
			this._musicFont = new Font(this.settings.display.resources.smuflFontFamilyName, this.settings.display.resources.engravingSettings.musicFontSize, FontStyle.Plain, FontWeight.Regular);
			const scale = this.settings.display.scale;
			this._canvas = document.createElement("canvas");
			this._canvas.width = width * Environment.highDpiFactor | 0;
			this._canvas.height = height * Environment.highDpiFactor | 0;
			this._canvas.style.width = `${width}px`;
			this._canvas.style.height = `${height}px`;
			this._context = this._canvas.getContext("2d");
			this._context.textBaseline = "hanging";
			this._context.scale(Environment.highDpiFactor * scale, Environment.highDpiFactor * scale);
			this._context.lineWidth = this._lineWidth;
		}
		endRender() {
			const result = this._canvas;
			this._canvas = null;
			return result;
		}
		get color() {
			return this._color;
		}
		set color(value) {
			if (this._color.rgba === value.rgba) return;
			this._color = value;
			this._context.strokeStyle = value.rgba;
			this._context.fillStyle = value.rgba;
		}
		get lineWidth() {
			return this._lineWidth;
		}
		set lineWidth(value) {
			this._lineWidth = value;
			if (this._context) this._context.lineWidth = value;
		}
		fillRect(x, y, w, h) {
			if (w > 0) this._context.fillRect(x, y, w, h);
		}
		strokeRect(x, y, w, h) {
			const blurOffset = this.lineWidth % 2 === 0 ? 0 : .5;
			this._context.strokeRect(x + blurOffset, y + blurOffset, w, h);
		}
		beginPath() {
			this._context.beginPath();
		}
		closePath() {
			this._context.closePath();
		}
		moveTo(x, y) {
			this._context.moveTo(x, y);
		}
		lineTo(x, y) {
			this._context.lineTo(x, y);
		}
		quadraticCurveTo(cpx, cpy, x, y) {
			this._context.quadraticCurveTo(cpx, cpy, x, y);
		}
		bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
			this._context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
		}
		fillCircle(x, y, radius) {
			this._context.beginPath();
			this._context.arc(x, y, radius, 0, Math.PI * 2, true);
			this.fill();
		}
		strokeCircle(x, y, radius) {
			this._context.beginPath();
			this._context.arc(x, y, radius, 0, Math.PI * 2, true);
			this.stroke();
		}
		fill() {
			this._context.fill();
			this._context.beginPath();
		}
		stroke() {
			this._context.stroke();
			this._context.beginPath();
		}
		get font() {
			return this._font;
		}
		set font(value) {
			this._font = value;
			if (this._context) this._context.font = value.toCssString(1);
			this._measureContext.font = value.toCssString(1);
		}
		get textAlign() {
			switch (this._context.textAlign) {
				case "left": return TextAlign.Left;
				case "center": return TextAlign.Center;
				case "right": return TextAlign.Right;
				default: return TextAlign.Left;
			}
		}
		set textAlign(value) {
			switch (value) {
				case TextAlign.Left:
					this._context.textAlign = "left";
					break;
				case TextAlign.Center:
					this._context.textAlign = "center";
					break;
				case TextAlign.Right:
					this._context.textAlign = "right";
					break;
			}
		}
		get textBaseline() {
			switch (this._context.textBaseline) {
				case "hanging": return TextBaseline.Top;
				case "middle": return TextBaseline.Middle;
				case "bottom": return TextBaseline.Bottom;
				case "alphabetic": return TextBaseline.Alphabetic;
				default: return TextBaseline.Top;
			}
		}
		set textBaseline(value) {
			switch (value) {
				case TextBaseline.Top:
					this._context.textBaseline = "hanging";
					break;
				case TextBaseline.Middle:
					this._context.textBaseline = "middle";
					break;
				case TextBaseline.Bottom:
					this._context.textBaseline = "bottom";
					break;
				case TextBaseline.Alphabetic:
					this._context.textBaseline = "alphabetic";
					break;
			}
		}
		beginGroup(_) {}
		endGroup() {}
		fillText(text, x, y) {
			this._context.fillText(text, x, y);
		}
		measureText(text) {
			const metrics = this._measureContext.measureText(text);
			return new MeasuredText(metrics.width, metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent);
		}
		fillMusicFontSymbol(x, y, relativeScale, symbol, centerAtPosition = false) {
			if (symbol === MusicFontSymbol.None) return;
			this._fillMusicFontSymbolText(x, y, relativeScale, String.fromCharCode(symbol), centerAtPosition);
		}
		fillMusicFontSymbols(x, y, relativeScale, symbols, centerAtPosition = false) {
			let s = "";
			for (const symbol of symbols) if (symbol !== MusicFontSymbol.None) s += String.fromCharCode(symbol);
			this._fillMusicFontSymbolText(x, y, relativeScale, s, centerAtPosition);
		}
		_fillMusicFontSymbolText(x, y, relativeScale, symbols, centerAtPosition) {
			const textAlign = this._context.textAlign;
			const baseLine = this._context.textBaseline;
			const font = this._context.font;
			this._context.font = this._musicFont.toCssString(relativeScale);
			this._context.textBaseline = "alphabetic";
			if (centerAtPosition) this._context.textAlign = "center";
			else this._context.textAlign = "left";
			this._context.fillText(symbols, x, y);
			this._context.textBaseline = baseLine;
			this._context.font = font;
			this._context.textAlign = textAlign;
		}
		beginRotate(centerX, centerY, angle) {
			this._context.save();
			this._context.translate(centerX, centerY);
			this._context.rotate(angle * Math.PI / 180);
		}
		endRotate() {
			this._context.restore();
		}
	};
	//#endregion
	//#region src/midi/AlphaSynthMidiFileHandler.ts
	/**
	* This implementation of the {@link IMidiFileHandler}
	* generates a {@link MidiFile} object which can be used in AlphaSynth for playback.
	* @public
	*/
	var AlphaSynthMidiFileHandler = class AlphaSynthMidiFileHandler {
		_midiFile;
		_smf1Mode;
		/**
		* An indicator by how many midi-ticks the song contents are shifted.
		* Grace beats at start might require a shift for the first beat to start at 0.
		* This information can be used to translate back the player time axis to the music notation.
		*/
		tickShift = 0;
		/**
		* Initializes a new instance of the {@link AlphaSynthMidiFileHandler} class.
		* @param midiFile The midi file.
		* @param smf1Mode Whether to generate a SMF1 compatible midi file. This might break multi note bends.
		*/
		constructor(midiFile, smf1Mode = false) {
			this._midiFile = midiFile;
			this._smf1Mode = smf1Mode;
		}
		addTickShift(tickShift) {
			this._midiFile.tickShift = tickShift;
			this.tickShift = tickShift;
		}
		addTimeSignature(tick, timeSignatureNumerator, timeSignatureDenominator) {
			tick += this.tickShift;
			let denominatorIndex = 0;
			let denominator = timeSignatureDenominator;
			while (true) {
				denominator = denominator >> 1;
				if (denominator > 0) denominatorIndex++;
				else break;
			}
			this._midiFile.addEvent(new TimeSignatureEvent(0, tick, timeSignatureNumerator, denominatorIndex, 48, 8));
		}
		addRest(track, tick, channel) {
			tick += this.tickShift;
			if (!this._smf1Mode) this._midiFile.addEvent(new AlphaTabRestEvent(track, tick, channel));
		}
		addNote(track, start, length, key, velocity, channel) {
			start += this.tickShift;
			this._midiFile.addEvent(new NoteOnEvent(track, start, channel, AlphaSynthMidiFileHandler._fixValue(key), AlphaSynthMidiFileHandler._fixValue(velocity)));
			this._midiFile.addEvent(new NoteOffEvent(track, start + length, channel, AlphaSynthMidiFileHandler._fixValue(key), AlphaSynthMidiFileHandler._fixValue(velocity)));
		}
		static _fixValue(value) {
			if (value > 127) return 127;
			if (value < 0) return 0;
			return value;
		}
		addControlChange(track, tick, channel, controller, value) {
			tick += this.tickShift;
			this._midiFile.addEvent(new ControlChangeEvent(track, tick, channel, controller, AlphaSynthMidiFileHandler._fixValue(value)));
		}
		addProgramChange(track, tick, channel, program) {
			tick += this.tickShift;
			this._midiFile.addEvent(new ProgramChangeEvent(track, tick, channel, program));
		}
		addTempo(tick, tempo) {
			tick += this.tickShift;
			const tempoEvent = new TempoChangeEvent(tick, 0);
			tempoEvent.beatsPerMinute = tempo;
			this._midiFile.addEvent(tempoEvent);
		}
		addBend(track, tick, channel, value) {
			tick += this.tickShift;
			if (value >= SynthConstants.MaxPitchWheel) value = SynthConstants.MaxPitchWheel;
			else value = Math.floor(value);
			this._midiFile.addEvent(new PitchBendEvent(track, tick, channel, value));
		}
		addNoteBend(track, tick, channel, key, value) {
			tick += this.tickShift;
			if (this._smf1Mode) this.addBend(track, tick, channel, value);
			else {
				value = value * SynthConstants.MaxPitchWheel20 / SynthConstants.MaxPitchWheel;
				this._midiFile.addEvent(new NoteBendEvent(track, tick, channel, key, value));
			}
		}
		finishTrack(track, tick) {
			tick += this.tickShift;
			if (this._midiFile.format === MidiFileFormat.MultiTrack || track === 0) this._midiFile.addEvent(new EndOfTrackEvent(track, tick));
		}
	};
	//#endregion
	//#region src/midi/MidiPlaybackController.ts
	/**
	* Helper container to handle repeats correctly
	* @internal
	*/
	var Repeat = class {
		group;
		opening;
		iterations;
		closingIndex = 0;
		constructor(group, opening) {
			this.group = group;
			this.opening = opening;
			group.closings = group.closings.sort((a, b) => a.index - b.index);
			this.iterations = group.closings.map((_) => 0);
		}
	};
	/**
	* @internal
	*/
	var MidiPlaybackController = class {
		_score;
		_repeatStack = [];
		_groupsOnStack = /* @__PURE__ */ new Set();
		_previousAlternateEndings = 0;
		_state = 0;
		shouldPlay = true;
		index = 0;
		currentTick = 0;
		get finished() {
			return this.index >= this._score.masterBars.length;
		}
		constructor(score) {
			this._score = score;
		}
		processCurrent() {
			const masterBar = this._score.masterBars[this.index];
			if (this._state === 0) {
				let masterBarAlternateEndings = masterBar.alternateEndings;
				if (masterBarAlternateEndings === 0) masterBarAlternateEndings = this._previousAlternateEndings;
				if (masterBar === masterBar.repeatGroup.opening && masterBar.repeatGroup.isClosed) {
					if (!this._groupsOnStack.has(masterBar.repeatGroup)) {
						const repeat = new Repeat(masterBar.repeatGroup, masterBar);
						this._repeatStack.push(repeat);
						this._groupsOnStack.add(masterBar.repeatGroup);
						this._previousAlternateEndings = 0;
						masterBarAlternateEndings = masterBar.alternateEndings;
					}
				}
				if (this._repeatStack.length === 0 || masterBarAlternateEndings === 0) this.shouldPlay = true;
				else {
					const repeat = this._repeatStack[this._repeatStack.length - 1];
					const iteration = repeat.iterations[repeat.closingIndex];
					this._previousAlternateEndings = masterBarAlternateEndings;
					if ((masterBarAlternateEndings & 1 << iteration) === 0) this.shouldPlay = false;
					else this.shouldPlay = true;
				}
			} else this.shouldPlay = true;
			if (this.shouldPlay) this.currentTick += masterBar.calculateDuration();
		}
		moveNext() {
			if (this._moveNextWithDirections()) return;
			this._moveNextWithNormalRepeats();
		}
		_resetRepeats() {
			this._groupsOnStack.clear();
			this._previousAlternateEndings = 0;
			this._repeatStack = [];
		}
		_handleDaCapo(directions, daCapo, newState) {
			if (directions.has(daCapo)) {
				this.index = 0;
				this._state = newState;
				this._resetRepeats();
				return true;
			}
			return false;
		}
		_handleDalSegno(directions, dalSegno, newState, jumpTarget) {
			if (directions.has(dalSegno)) {
				const segno = this._findJumpTarget(jumpTarget, this.index, true);
				if (segno === -1) return false;
				this.index = segno;
				this._state = newState;
				this._resetRepeats();
				return true;
			}
			return false;
		}
		_handleDaCoda(directions, daCoda, jumpTarget) {
			if (directions.has(daCoda)) {
				const coda = this._findJumpTarget(jumpTarget, this.index, false);
				if (coda === -1) {
					this.index++;
					return true;
				}
				this.index = coda;
				this._state = 0;
				return true;
			}
			return false;
		}
		_moveNextWithDirections() {
			const masterBar = this._score.masterBars[this.index];
			const hasDirections = masterBar.directions !== null && masterBar.directions.size > 0;
			if (this._state === 0 && !hasDirections) return false;
			if (!hasDirections) {
				this.index++;
				return true;
			}
			switch (this._state) {
				case 0:
					if (this._handleDaCapo(masterBar.directions, Direction.JumpDaCapo, 1) || this._handleDaCapo(masterBar.directions, Direction.JumpDaCapoAlCoda, 2) || this._handleDaCapo(masterBar.directions, Direction.JumpDaCapoAlDoubleCoda, 3) || this._handleDaCapo(masterBar.directions, Direction.JumpDaCapoAlFine, 4)) return true;
					if (this._handleDalSegno(masterBar.directions, Direction.JumpDalSegno, 1, Direction.TargetSegno) || this._handleDalSegno(masterBar.directions, Direction.JumpDalSegnoAlCoda, 2, Direction.TargetSegno) || this._handleDalSegno(masterBar.directions, Direction.JumpDalSegnoAlDoubleCoda, 3, Direction.TargetSegno) || this._handleDalSegno(masterBar.directions, Direction.JumpDalSegnoAlFine, 4, Direction.TargetSegno)) return true;
					if (this._handleDalSegno(masterBar.directions, Direction.JumpDalSegnoSegno, 1, Direction.TargetSegnoSegno) || this._handleDalSegno(masterBar.directions, Direction.JumpDalSegnoSegnoAlCoda, 2, Direction.TargetSegnoSegno) || this._handleDalSegno(masterBar.directions, Direction.JumpDalSegnoSegnoAlDoubleCoda, 3, Direction.TargetSegnoSegno) || this._handleDalSegno(masterBar.directions, Direction.JumpDalSegnoSegnoAlFine, 4, Direction.TargetSegnoSegno)) return true;
					return false;
				case 1:
					this.index++;
					return true;
				case 2:
					if (this._handleDaCoda(masterBar.directions, Direction.JumpDaCoda, Direction.TargetCoda)) return true;
					this.index++;
					return true;
				case 3:
					if (this._handleDaCoda(masterBar.directions, Direction.JumpDaDoubleCoda, Direction.TargetDoubleCoda)) return true;
					this.index++;
					return true;
				case 4:
					if (masterBar.directions.has(Direction.TargetFine)) {
						this.index = this._score.masterBars.length;
						return true;
					}
					this.index++;
					return true;
			}
			return true;
		}
		/**
		* Finds the index of the masterbar with the given direction applied which fits best
		* the given start index. In best case in one piece we only have single jump marks, but it could happen
		* that you have multiple Segno/Coda symbols placed at different sections.
		* @param toFind
		* @param searchIndex
		* @param backwardsFirst whether to first search backwards before looking forwards.
		* @returns the index of the masterbar found with the given direction or -1 if no masterbar with the given direction was found.
		*/
		_findJumpTarget(toFind, searchIndex, backwardsFirst) {
			let index;
			if (backwardsFirst) {
				index = this._findJumpTargetBackwards(toFind, searchIndex);
				if (index === -1) index = this._findJumpTargetForwards(toFind, searchIndex);
				return index;
			}
			index = this._findJumpTargetForwards(toFind, searchIndex);
			if (index === -1) index = this._findJumpTargetBackwards(toFind, searchIndex);
			return index;
		}
		_findJumpTargetForwards(toFind, searchIndex) {
			let index = searchIndex;
			while (index < this._score.masterBars.length) {
				const d = this._score.masterBars[index].directions;
				if (d && d.has(toFind)) return index;
				index++;
			}
			return -1;
		}
		_findJumpTargetBackwards(toFind, searchIndex) {
			let index = searchIndex;
			while (index >= 0) {
				const d = this._score.masterBars[index].directions;
				if (d && d.has(toFind)) return index;
				index--;
			}
			return -1;
		}
		_moveNextWithNormalRepeats() {
			const masterBarRepeatCount = this._score.masterBars[this.index].repeatCount - 1;
			if (this._repeatStack.length > 0 && masterBarRepeatCount > 0) {
				const repeat = this._repeatStack[this._repeatStack.length - 1];
				if (repeat.iterations[repeat.closingIndex] < masterBarRepeatCount) {
					this.index = repeat.opening.index;
					repeat.iterations[repeat.closingIndex]++;
					for (let i = 0; i < repeat.closingIndex; i++) repeat.iterations[i] = 0;
					repeat.closingIndex = 0;
					this._previousAlternateEndings = 0;
				} else if (repeat.closingIndex < repeat.group.closings.length - 1) {
					repeat.closingIndex++;
					this.index++;
				} else {
					this._repeatStack.pop();
					this._groupsOnStack.delete(repeat.group);
					this.index++;
				}
			} else this.index++;
		}
	};
	//#endregion
	//#region src/midi/BeatTickLookup.ts
	/**
	* Represents a beat and when it is actually played according to the generated audio.
	* @public
	*/
	var BeatTickLookupItem = class {
		/**
		* Gets the beat represented by this item.
		*/
		beat;
		/**
		* Gets the playback start of the beat according to the generated audio.
		*/
		playbackStart;
		constructor(beat, playbackStart) {
			this.beat = beat;
			this.playbackStart = playbackStart;
		}
	};
	/**
	* Represents the time period, for which one or multiple {@link Beat}s are played
	* @public
	*/
	var BeatTickLookup = class {
		_highlightedBeats = /* @__PURE__ */ new Map();
		/**
		* Gets or sets the start time in midi ticks at which the given beat is played.
		*/
		start;
		/**
		* Gets or sets the end time in midi ticks at which the given beat is played.
		*/
		end;
		/**
		* Gets or sets a list of all beats that should be highlighted when
		* the beat of this lookup starts playing. This might not mean
		* the beats start at this position.
		*/
		highlightedBeats = [];
		/**
		* Gets the next BeatTickLookup which comes after this one and is in the same
		* MasterBarTickLookup.
		*/
		nextBeat = null;
		/**
		* Gets the preivous BeatTickLookup which comes before this one and is in the same
		* MasterBarTickLookup.
		*/
		previousBeat = null;
		/**
		* Gets the tick duration of this lookup.
		*/
		get duration() {
			return this.end - this.start;
		}
		constructor(start, end) {
			this.start = start;
			this.end = end;
		}
		/**
		* Marks the given beat as highlighed as part of this lookup.
		* @param beat The beat to add.
		*/
		highlightBeat(beat, playbackStart) {
			if (!this._highlightedBeats.has(beat.id)) {
				this._highlightedBeats.set(beat.id, true);
				this.highlightedBeats.push(new BeatTickLookupItem(beat, playbackStart));
			}
		}
		/**
		* Looks for the first visible beat which starts at this lookup so it can be used for cursor placement.
		* @param visibleTracks The visible tracks.
		* @returns The first beat which is visible according to the given tracks or null.
		*/
		getVisibleBeatAtStart(visibleTracks) {
			for (const b of this.highlightedBeats) if (b.playbackStart === this.start && visibleTracks.has(b.beat.voice.bar.staff.track.index)) return b.beat;
			return null;
		}
		/**
		* Looks for the first visible beat which starts at this lookup so it can be used for cursor placement.
		* @param checker The custom checker to see if a beat is visible.
		* @returns The first beat which is visible according to the given tracks or null.
		*/
		getVisibleBeatAtStartWithChecker(checker) {
			for (const b of this.highlightedBeats) if (b.playbackStart === this.start && checker.isVisible(b.beat)) return b.beat;
			return null;
		}
	};
	//#endregion
	//#region src/midi/MasterBarTickLookup.ts
	/**
	* Represents a single point in time defining the tempo of a {@link MasterBarTickLookup}.
	* This is typically the initial tempo of a master bar or a tempo change.
	* @public
	*/
	var MasterBarTickLookupTempoChange = class {
		/**
		* Gets or sets the tick position within the {@link MasterBarTickLookup.start} and  {@link MasterBarTickLookup.end} range.
		*/
		tick;
		/**
		* Gets or sets the tempo at the tick position.
		*/
		tempo;
		constructor(tick, tempo) {
			this.tick = tick;
			this.tempo = tempo;
		}
	};
	/**
	* Represents the time period, for which all bars of a {@link MasterBar} are played.
	* @public
	*/
	var MasterBarTickLookup = class {
		/**
		* Gets or sets the start time in midi ticks at which the MasterBar is played.
		*/
		start = 0;
		/**
		* Gets or sets the end time in midi ticks at which the MasterBar is played.
		*/
		end = 0;
		/**
		* Gets or sets the current tempo when the MasterBar is played.
		* @deprecated use {@link tempoChanges}
		*/
		get tempo() {
			return this.tempoChanges[0].tempo;
		}
		/**
		* Gets the list of tempo changes within the tick lookup.
		*/
		tempoChanges = [];
		/**
		* Gets or sets the MasterBar which is played.
		*/
		masterBar;
		/**
		* The first beat in the bar. 
		*/
		firstBeat = null;
		/**
		* The last beat in the bar. 
		*/
		lastBeat = null;
		/**
		* Inserts `newNextBeat` after `currentBeat` in the linked list of items and updates.
		* the `firstBeat` and `lastBeat` respectively too.
		* @param currentBeat The item in which to insert the new item afterwards
		* @param newBeat The new item to insert
		*/
		_insertAfter(currentBeat, newBeat) {
			if (this.firstBeat == null || currentBeat == null || this.lastBeat == null) {
				this.firstBeat = newBeat;
				this.lastBeat = newBeat;
			} else {
				newBeat.nextBeat = currentBeat.nextBeat;
				newBeat.previousBeat = currentBeat;
				if (currentBeat.nextBeat) currentBeat.nextBeat.previousBeat = newBeat;
				currentBeat.nextBeat = newBeat;
				if (currentBeat === this.lastBeat) this.lastBeat = newBeat;
			}
		}
		/**
		* Inserts `newNextBeat` before `currentBeat` in the linked list of items and updates.
		* the `firstBeat` and `lastBeat` respectively too.
		* @param currentBeat The item in which to insert the new item afterwards
		* @param newBeat The new item to insert
		*/
		_insertBefore(currentBeat, newBeat) {
			if (this.firstBeat == null || currentBeat == null || this.lastBeat == null) {
				this.firstBeat = newBeat;
				this.lastBeat = newBeat;
			} else {
				newBeat.previousBeat = currentBeat.previousBeat;
				newBeat.nextBeat = currentBeat;
				if (currentBeat.previousBeat) currentBeat.previousBeat.nextBeat = newBeat;
				currentBeat.previousBeat = newBeat;
				if (currentBeat === this.firstBeat) this.firstBeat = newBeat;
			}
		}
		/**
		* Gets or sets the {@link MasterBarTickLookup} of the next masterbar in the {@link Score}
		*/
		nextMasterBar = null;
		/**
		* Gets or sets the {@link MasterBarTickLookup} of the previous masterbar in the {@link Score}
		*/
		previousMasterBar = null;
		/**
		* Adds a new beat to this masterbar following the slicing logic required by the MidiTickLookup.
		* @param beat The beat to add to this masterbat
		* @param beatPlaybackStart The original start of this beat. This time is relevant for highlighting.
		* @param sliceStart The slice start to which this beat should be added. This time is relevant for creating new slices.
		* @param sliceDuration The slice duration to which this beat should be added. This time is relevant for creating new slices.
		* @returns The first item of the chain which was affected.
		*/
		addBeat(beat, beatPlaybackStart, sliceStart, sliceDuration) {
			const end = sliceStart + sliceDuration;
			if (this.firstBeat == null) {
				const n1 = new BeatTickLookup(sliceStart, end);
				n1.highlightBeat(beat, beatPlaybackStart);
				this._insertAfter(this.firstBeat, n1);
			} else if (sliceStart >= this.lastBeat.end) {
				const n1 = new BeatTickLookup(this.lastBeat.end, end);
				n1.highlightBeat(beat, beatPlaybackStart);
				this._insertAfter(this.lastBeat, n1);
			} else {
				let l1 = null;
				if (sliceStart < this.firstBeat.start) l1 = this.firstBeat;
				else {
					let current = this.firstBeat;
					while (current != null) {
						if (sliceStart >= current.start && sliceStart < current.end) {
							l1 = current;
							break;
						}
						current = current.nextBeat;
					}
					if (l1 === null) throw new AlphaTabError(AlphaTabErrorType.General, "Error on building lookup, unknown variant");
				}
				if (sliceStart < l1.start) if (end === l1.start) {
					const n1 = new BeatTickLookup(sliceStart, l1.start);
					n1.highlightBeat(beat, beatPlaybackStart);
					this._insertBefore(this.firstBeat, n1);
				} else if (end < l1.end) {
					const n1 = new BeatTickLookup(sliceStart, l1.start);
					n1.highlightBeat(beat, beatPlaybackStart);
					this._insertBefore(l1, n1);
					const n2 = new BeatTickLookup(l1.start, end);
					for (const b of l1.highlightedBeats) n2.highlightBeat(b.beat, b.playbackStart);
					n2.highlightBeat(beat, beatPlaybackStart);
					this._insertBefore(l1, n2);
					l1.start = end;
				} else if (end === l1.end) {
					const n1 = new BeatTickLookup(sliceStart, l1.start);
					n1.highlightBeat(beat, beatPlaybackStart);
					l1.highlightBeat(beat, beatPlaybackStart);
					this._insertBefore(l1, n1);
				} else {
					const n1 = new BeatTickLookup(sliceStart, l1.start);
					n1.highlightBeat(beat, beatPlaybackStart);
					l1.highlightBeat(beat, beatPlaybackStart);
					this._insertBefore(l1, n1);
					this.addBeat(beat, beatPlaybackStart, l1.end, end - l1.end);
				}
				else if (sliceStart > l1.start) if (end === l1.end) {
					const n1 = new BeatTickLookup(l1.start, sliceStart);
					for (const b of l1.highlightedBeats) n1.highlightBeat(b.beat, b.playbackStart);
					l1.start = sliceStart;
					l1.highlightBeat(beat, beatPlaybackStart);
					this._insertBefore(l1, n1);
				} else if (end < l1.end) {
					const n1 = new BeatTickLookup(l1.start, sliceStart);
					this._insertBefore(l1, n1);
					const n2 = new BeatTickLookup(sliceStart, end);
					this._insertBefore(l1, n2);
					for (const b of l1.highlightedBeats) {
						n1.highlightBeat(b.beat, b.playbackStart);
						n2.highlightBeat(b.beat, b.playbackStart);
					}
					n2.highlightBeat(beat, beatPlaybackStart);
					l1.start = end;
				} else {
					const n1 = new BeatTickLookup(l1.start, sliceStart);
					for (const b of l1.highlightedBeats) n1.highlightBeat(b.beat, b.playbackStart);
					l1.start = sliceStart;
					l1.highlightBeat(beat, beatPlaybackStart);
					this._insertBefore(l1, n1);
					this.addBeat(beat, beatPlaybackStart, l1.end, end - l1.end);
				}
				else if (end === l1.end) l1.highlightBeat(beat, beatPlaybackStart);
				else if (end < l1.end) {
					const n1 = new BeatTickLookup(l1.start, end);
					for (const b of l1.highlightedBeats) n1.highlightBeat(b.beat, b.playbackStart);
					n1.highlightBeat(beat, beatPlaybackStart);
					l1.start = end;
					this._insertBefore(l1, n1);
				} else {
					l1.highlightBeat(beat, beatPlaybackStart);
					this.addBeat(beat, beatPlaybackStart, l1.end, end - l1.end);
				}
			}
		}
	};
	//#endregion
	//#region src/synth/PlaybackRange.ts
	/**
	* Represents a range of the song that should be played.
	* @public
	*/
	var PlaybackRange = class {
		/**
		* The position in midi ticks from where the song should start.
		*/
		startTick = 0;
		/**
		* The position in midi ticks to where the song should be played.
		*/
		endTick = 0;
	};
	//#endregion
	//#region src/midi/MidiTickLookup.ts
	/**
	* Describes how a cursor should be moving.
	* @public
	*/
	var MidiTickLookupFindBeatResultCursorMode = /* @__PURE__ */ function(MidiTickLookupFindBeatResultCursorMode) {
		/**
		* Unknown/Undetermined mode. Should not happen on user level.
		*/
		MidiTickLookupFindBeatResultCursorMode[MidiTickLookupFindBeatResultCursorMode["Unknown"] = 0] = "Unknown";
		/**
		* The cursor should animate to the next beat.
		*/
		MidiTickLookupFindBeatResultCursorMode[MidiTickLookupFindBeatResultCursorMode["ToNextBext"] = 1] = "ToNextBext";
		/**
		* @deprecated replaced by {@link ToEndOfBeat}
		*/
		MidiTickLookupFindBeatResultCursorMode[MidiTickLookupFindBeatResultCursorMode["ToEndOfBar"] = 2] = "ToEndOfBar";
		/**
		* The cursor should animate to the end of the **beat** (typically on repeats and jumps)
		* (this is named end of bar historically)
		*/
		MidiTickLookupFindBeatResultCursorMode[MidiTickLookupFindBeatResultCursorMode["ToEndOfBeat"] = 3] = "ToEndOfBeat";
		return MidiTickLookupFindBeatResultCursorMode;
	}({});
	/**
	* Represents the results of searching the currently played beat.
	* @see MidiTickLookup.findBeat
	* @public
	*/
	var MidiTickLookupFindBeatResult = class {
		/**
		* Gets or sets the beat that is currently played and used for the start
		* position of the cursor animation.
		*/
		beat;
		/**
		* Gets or sets the parent MasterBarTickLookup to which this beat lookup belongs to.
		*/
		masterBar;
		/**
		* Gets or sets the related beat tick lookup.
		*/
		beatLookup;
		/**
		* Gets or sets the beat that will be played next.
		*/
		nextBeat = null;
		/**
		* Gets or sets the duration in midi ticks how long this lookup is valid.
		*/
		tickDuration = 0;
		/**
		* Gets or sets the duration in milliseconds how long this lookup is valid.
		*/
		duration = 0;
		/**
		* The mode how the cursor should be handled.
		*/
		cursorMode = 0;
		get start() {
			return this.masterBar.start + this.beatLookup.start;
		}
		get end() {
			return this.start + this.tickDuration;
		}
		constructor(masterBar) {
			this.masterBar = masterBar;
		}
		calculateDuration() {
			if (this.masterBar.tempoChanges.length === 1) this.duration = MidiUtils.ticksToMillis(this.tickDuration, this.masterBar.tempoChanges[0].tempo);
			else {
				let millis = 0;
				let currentTick = this.start;
				let currentTempo = this.masterBar.tempoChanges[0].tempo;
				const endTick = this.end;
				for (const change of this.masterBar.tempoChanges) if (change.tick < currentTick) currentTempo = change.tempo;
				else if (change.tick > endTick) break;
				else {
					millis += MidiUtils.ticksToMillis(change.tick - currentTick, currentTempo);
					currentTempo = change.tempo;
					currentTick = change.tick;
				}
				if (endTick > currentTick) millis += MidiUtils.ticksToMillis(endTick - currentTick, currentTempo);
				this.duration = millis;
			}
		}
	};
	/**
	* @internal
	*/
	var TrackLookupBeatVisibilityChecker = class {
		_lookup;
		constructor(lookup) {
			this._lookup = lookup;
		}
		isVisible(beat) {
			return this._lookup.has(beat.voice.bar.staff.track.index);
		}
	};
	/**
	* This class holds all information about when {@link MasterBar}s and {@link Beat}s are played.
	*
	* On top level it is organized into {@link MasterBarTickLookup} objects indicating the
	* master bar start and end times. This information is used to highlight the currently played bars
	* and it gives access to the played beats in this masterbar and their times.
	*
	* The {@link BeatTickLookup} are then the slices into which the masterbar is separated by the voices and beats
	* of all tracks. An example how things are organized:
	*
	* Time (eighths):  | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
	*
	* Track 1:         |        B1         |        B2         |    B3   |    B4   |    B5   |    B6   |
	* Track 2:         |                  B7                   |         B7        | B9 | B10| B11| B12|
	* Track 3:         |                                      B13                                      |
	*
	* Lookup:          |        L1         |        L2         |    L3    |   L4   | L5 | L6 | L7 | L8 |
	* Active Beats:
	* - L1             B1,B7,B13
	* - L2                                 B2,B7,B13
	* - L3                                                      B3,B7,B13
	* - L4                                                                 B4,B7,B13
	* - L5                                                                          B5,B9,B13
	* - L6                                                                               B5,B10,B13
	* - L7                                                                                    B6,B11,B13
	* - L8                                                                                         B6,B12,B13
	*
	* Then during playback we build out of this list {@link MidiTickLookupFindBeatResult} objects which are sepcific
	* to the visible tracks displayed. This is required because if only Track 2 is displayed we cannot use the the
	* Lookup L1 alone to determine the start and end of the beat cursor. In this case we will derive a
	* MidiTickLookupFindBeatResult which holds for Time 01 the lookup L1 as start and L3 as end. This will be used
	* both for the cursor and beat highlighting.
	* @public
	*/
	var MidiTickLookup = class {
		_currentMasterBar = null;
		/**
		* A dictionary of all master bars played. The index is the index equals to {@link MasterBar.index}.
		* This lookup only contains the first time a MasterBar is played. For a whole sequence of the song refer to {@link MasterBars}.
		* @internal
		*/
		masterBarLookup = /* @__PURE__ */ new Map();
		/**
		* A dictionary of all beat played. The index is the id to {@link Beat.id}.
		* The value is the bar relative tick time at which the beat was registered during midi generation.
		* This lookup only contains the first time a Beat is played.
		* @internal
		*/
		beatLookup = /* @__PURE__ */ new Map();
		/**
		* A list of all {@link MasterBarTickLookup} sorted by time.
		*/
		masterBars = [];
		/**
		* The information about which bars are displayed via multi-bar rests.
		* The key is the start bar, and the value is the additional bars in sequential order.
		* This info allows building the correct "next" beat and duration.
		*/
		multiBarRestInfo = null;
		/**
		* An optional playback range to consider when performing lookups.
		* This will mainly influence the used {@link MidiTickLookupFindBeatResultCursorMode}
		*/
		playbackRange = null;
		/**
		* Finds the currently played beat given a list of tracks and the current time.
		* @param trackLookup The tracks indices in which to search the played beat for.
		* @param tick The current time in midi ticks.
		* @param currentBeatHint Used for optimized lookup during playback. By passing in a previous result lookup of the next one can be optimized using heuristics. (optional).
		* @returns The information about the current beat or null if no beat could be found.
		*/
		findBeat(trackLookup, tick, currentBeatHint = null) {
			return this.findBeatWithChecker(new TrackLookupBeatVisibilityChecker(trackLookup), tick, currentBeatHint);
		}
		/**
		* Finds the currently played beat given a list of tracks and the current time.
		* @param checker The checker to ask whether a beat is visible and should be considered for result.
		* @param tick The current time in midi ticks.
		* @param currentBeatHint Used for optimized lookup during playback. By passing in a previous result lookup of the next one can be optimized using heuristics. (optional).
		* @returns The information about the current beat or null if no beat could be found.
		*/
		findBeatWithChecker(checker, tick, currentBeatHint = null) {
			let result = null;
			if (currentBeatHint) result = this._findBeatFast(checker, currentBeatHint, tick);
			if (!result) result = this._findBeatSlow(checker, currentBeatHint, tick, false);
			if (result) {
				const playbackRange = this.playbackRange;
				if (playbackRange !== null && result.start >= playbackRange.endTick) return null;
			}
			return result;
		}
		_findBeatFast(checker, currentBeatHint, tick) {
			if (tick >= currentBeatHint.start && tick < currentBeatHint.end) return currentBeatHint;
			if (currentBeatHint.nextBeat && tick >= currentBeatHint.nextBeat.start && tick < currentBeatHint.nextBeat.end && (checker === void 0 || checker.isVisible(currentBeatHint.nextBeat.beat))) {
				const next = currentBeatHint.nextBeat;
				this._fillNextBeat(next, checker);
				return next;
			}
			return null;
		}
		_fillNextBeatMultiBarRest(current, checker) {
			const group = this.multiBarRestInfo.get(current.masterBar.masterBar.index);
			let endMasterBar = current.masterBar;
			for (let i = 0; i < group.length; i++) {
				if (!endMasterBar) break;
				endMasterBar = endMasterBar.nextMasterBar;
			}
			if (endMasterBar) if (endMasterBar.nextMasterBar) {
				current.nextBeat = this._firstBeatInMasterBar(checker, endMasterBar.nextMasterBar, endMasterBar.nextMasterBar.start, true);
				if (current.nextBeat) {
					current.tickDuration = current.nextBeat.start - current.start;
					current.cursorMode = 1;
					if (current.nextBeat.masterBar.masterBar.index !== endMasterBar.masterBar.index + 1 && (current.nextBeat.masterBar.masterBar.index !== endMasterBar.masterBar.index || current.nextBeat.beat.playbackStart <= current.beat.playbackStart)) current.cursorMode = 3;
					else if (this.playbackRange !== null && this.playbackRange.endTick <= current.nextBeat.start) current.cursorMode = 3;
				} else {
					current.tickDuration = endMasterBar.nextMasterBar.end - current.start;
					current.cursorMode = 3;
				}
			} else {
				current.tickDuration = endMasterBar.end - current.start;
				current.cursorMode = 3;
			}
			else {
				Logger.warning("Synth", "MultiBar Rest Info and the nextMasterBar are out of sync, this is an unexpected error. Please report it as bug.  (broken chain fill-next)");
				current.tickDuration = (current.masterBar.end - current.masterBar.start) * (group.length + 1);
				current.cursorMode = 3;
			}
			current.calculateDuration();
		}
		_fillNextBeat(current, checker) {
			if (this._isMultiBarRestResult(current)) this._fillNextBeatMultiBarRest(current, checker);
			else this._fillNextBeatDefault(current, checker);
		}
		_fillNextBeatDefault(current, checker) {
			current.nextBeat = this._findBeatInMasterBar(current.masterBar, current.beatLookup.nextBeat, current.end, checker, true);
			if (current.nextBeat == null) current.nextBeat = this._findBeatSlow(checker, current, current.end, true);
			if (current.nextBeat) {
				current.tickDuration = current.nextBeat.start - current.start;
				current.cursorMode = 1;
				current.calculateDuration();
			} else {
				current.tickDuration = current.masterBar.end - current.start;
				current.cursorMode = 3;
				current.calculateDuration();
			}
			if (current.nextBeat) {
				if (current.nextBeat.masterBar.masterBar.index !== current.masterBar.masterBar.index + 1 && (current.nextBeat.masterBar.masterBar.index !== current.masterBar.masterBar.index || current.nextBeat.beat.playbackStart <= current.beat.playbackStart)) current.cursorMode = 3;
				else if (this.playbackRange !== null && this.playbackRange.endTick <= current.nextBeat.start) current.cursorMode = 3;
			}
		}
		_isMultiBarRestResult(current) {
			return this._internalIsMultiBarRestResult(current.masterBar.masterBar.index, current.beat);
		}
		_internalIsMultiBarRestResult(masterBarIndex, beat) {
			return this.multiBarRestInfo && this.multiBarRestInfo.has(masterBarIndex) && beat.isRest && beat.voice.bar.isRestOnly;
		}
		_findBeatSlow(checker, currentBeatHint, tick, isNextSearch) {
			let masterBar = null;
			if (currentBeatHint != null) {
				if (currentBeatHint.masterBar.start <= tick && currentBeatHint.masterBar.end > tick) masterBar = currentBeatHint.masterBar;
				else if (currentBeatHint.masterBar.nextMasterBar && currentBeatHint.masterBar.nextMasterBar.start <= tick && currentBeatHint.masterBar.nextMasterBar.end > tick) masterBar = currentBeatHint.masterBar.nextMasterBar;
			}
			if (!masterBar) masterBar = this._findMasterBar(tick);
			if (!masterBar) return null;
			return this._firstBeatInMasterBar(checker, masterBar, tick, isNextSearch);
		}
		_firstBeatInMasterBar(checker, startMasterBar, tick, isNextSearch) {
			let masterBar = startMasterBar;
			while (masterBar) {
				if (masterBar.firstBeat) {
					const beat = this._findBeatInMasterBar(masterBar, masterBar.firstBeat, tick, checker, isNextSearch);
					if (beat) return beat;
				}
				masterBar = masterBar.nextMasterBar;
			}
			return null;
		}
		/**
		* Finds the beat at a given tick position within the known master bar.
		* @param masterBar
		* @param currentStartLookup
		* @param tick
		* @param visibleTracks
		* @param isNextSearch
		* @returns
		*/
		_findBeatInMasterBar(masterBar, currentStartLookup, tick, checker, isNextSearch) {
			if (!currentStartLookup) return null;
			let startBeatLookup = null;
			let startBeat = null;
			const relativeTick = tick - masterBar.start;
			while (currentStartLookup != null && startBeat == null) {
				if ((currentStartLookup.start <= relativeTick || isNextSearch && relativeTick < 0) && relativeTick < currentStartLookup.end) {
					startBeatLookup = currentStartLookup;
					startBeat = currentStartLookup.getVisibleBeatAtStartWithChecker(checker);
					if (!startBeat) if (isNextSearch) {
						let currentMasterBar = masterBar;
						while (currentMasterBar != null && startBeat == null) {
							while (currentStartLookup != null) {
								startBeat = currentStartLookup.getVisibleBeatAtStartWithChecker(checker);
								if (startBeat) {
									startBeatLookup = currentStartLookup;
									masterBar = currentMasterBar;
									break;
								}
								currentStartLookup = currentStartLookup.nextBeat;
							}
							if (!startBeat || !startBeatLookup) {
								currentMasterBar = currentMasterBar.nextMasterBar;
								currentStartLookup = currentMasterBar?.firstBeat ?? null;
							}
						}
					} else {
						let currentMasterBar = masterBar;
						while (currentMasterBar != null && startBeat == null) {
							while (currentStartLookup != null) {
								startBeat = currentStartLookup.getVisibleBeatAtStartWithChecker(checker);
								if (startBeat) {
									startBeatLookup = currentStartLookup;
									masterBar = currentMasterBar;
									break;
								}
								currentStartLookup = currentStartLookup.previousBeat;
							}
							if (!startBeat || !startBeatLookup) {
								currentMasterBar = currentMasterBar.previousMasterBar;
								currentStartLookup = currentMasterBar?.firstBeat ?? null;
							}
						}
					}
				} else if (currentStartLookup.end > relativeTick) break;
				currentStartLookup = currentStartLookup?.nextBeat ?? null;
			}
			if (startBeat == null) return null;
			return this._createResult(masterBar, startBeatLookup, startBeat, isNextSearch, checker);
		}
		_createResult(masterBar, beatLookup, beat, isNextSearch, checker) {
			const result = new MidiTickLookupFindBeatResult(masterBar);
			result.beat = beat;
			result.beatLookup = beatLookup;
			result.tickDuration = beatLookup.end - beatLookup.start;
			if (!isNextSearch) this._fillNextBeat(result, checker);
			else if (this._isMultiBarRestResult(result)) {
				const multiRest = this.multiBarRestInfo.get(masterBar.masterBar.index);
				let endMasterBar = masterBar;
				for (let i = 0; i < multiRest.length; i++) {
					if (!endMasterBar) break;
					endMasterBar = endMasterBar.nextMasterBar;
				}
				if (endMasterBar) if (endMasterBar.nextMasterBar) result.tickDuration = endMasterBar.nextMasterBar.start - beatLookup.start;
				else result.tickDuration = endMasterBar.end - beatLookup.start;
				else Logger.warning("Synth", "MultiBar Rest Info and the nextMasterBar are out of sync, this is an unexpected error. Please report it as bug.  (broken chain stretch-result)");
			}
			result.calculateDuration();
			return result;
		}
		_findMasterBar(tick) {
			if (tick <= 0 && this.masterBars.length > 0) return this.masterBars[0];
			const bars = this.masterBars;
			let bottom = 0;
			let top = bars.length - 1;
			while (bottom <= top) {
				const middle = (top + bottom) / 2 | 0;
				const bar = bars[middle];
				if (tick >= bar.start && tick < bar.end) return bar;
				if (tick < bar.start) top = middle - 1;
				else bottom = middle + 1;
			}
			return null;
		}
		/**
		* Gets the {@link MasterBarTickLookup} for a given masterbar at which the masterbar is played the first time.
		* @param bar The masterbar to find the time period for.
		* @returns A {@link MasterBarTickLookup} containing the details about the first time the {@link MasterBar} is played.
		*/
		getMasterBar(bar) {
			if (!this.masterBarLookup.has(bar.index)) {
				const fallback = new MasterBarTickLookup();
				fallback.masterBar = bar;
				return fallback;
			}
			return this.masterBarLookup.get(bar.index);
		}
		/**
		* Gets the start time in midi ticks for a given masterbar at which the masterbar is played the first time.
		* @param bar The masterbar to find the time period for.
		* @returns The time in midi ticks at which the masterbar is played the first time or 0 if the masterbar is not contained
		*/
		getMasterBarStart(bar) {
			if (!this.masterBarLookup.has(bar.index)) return 0;
			return this.masterBarLookup.get(bar.index).start;
		}
		/**
		* Gets the start time in midi ticks for a given beat at which the masterbar is played the first time.
		* @param beat The beat to find the time period for.
		* @returns The time in midi ticks at which the beat is played the first time or 0 if the beat is not contained
		*/
		getBeatStart(beat) {
			if (!this.masterBarLookup.has(beat.voice.bar.index) || !this.beatLookup.has(beat.id)) return 0;
			return this.masterBarLookup.get(beat.voice.bar.index).start + this.beatLookup.get(beat.id).startTick;
		}
		/**
		* Gets the playback range in midi ticks for a given beat.
		* @param beat The beat to find the time period for.
		* @returns The relative playback range within the parent masterbar at which the beat start and ends playing 
		*/
		getRelativeBeatPlaybackRange(beat) {
			if (!this.beatLookup.has(beat.id)) return;
			return this.beatLookup.get(beat.id);
		}
		/**
		* Adds a new {@link MasterBarTickLookup} to the lookup table.
		* @param masterBar The item to add.
		*/
		addMasterBar(masterBar) {
			this.masterBars.push(masterBar);
			if (this._currentMasterBar) {
				masterBar.previousMasterBar = this._currentMasterBar;
				this._currentMasterBar.nextMasterBar = masterBar;
			}
			this._currentMasterBar = masterBar;
			if (!this.masterBarLookup.has(masterBar.masterBar.index)) this.masterBarLookup.set(masterBar.masterBar.index, masterBar);
		}
		addBeat(beat, start, duration) {
			if (!this.beatLookup.has(beat.id)) {
				const playbackRange = new PlaybackRange();
				playbackRange.startTick = start;
				playbackRange.endTick = start + duration;
				this.beatLookup.set(beat.id, playbackRange);
			}
			const currentMasterBar = this._currentMasterBar;
			if (currentMasterBar) if (start < 0 && currentMasterBar.previousMasterBar) {
				const relativeMasterBarEnd = currentMasterBar.previousMasterBar.end - currentMasterBar.previousMasterBar.start;
				const previousStart = relativeMasterBarEnd + start;
				const previousEnd = previousStart + duration;
				currentMasterBar.previousMasterBar.addBeat(beat, previousStart, previousStart, duration);
				if (previousEnd > relativeMasterBarEnd) {
					const overlapDuration = duration + start;
					currentMasterBar.addBeat(beat, start, 0, overlapDuration);
				}
			} else currentMasterBar.addBeat(beat, start, start, duration);
		}
	};
	//#endregion
	//#region src/midi/MidiFileGenerator.ts
	/**
	* @internal
	*/
	var MidiNoteDuration = class {
		noteOnly = 0;
		untilTieOrSlideEnd = 0;
		letRingEnd = 0;
		/**
		* A factor indicating how much longer/shorter the beat is in its playback respecting
		* effects like tuplets, triplet feels, dots, grace beats stealing parts etc.
		*
		* This factor can be used to relatively adjust durations in effects like trills or tremolos.
		*/
		beatDurationFactor = 1;
	};
	/**
	* @internal
	*/
	var TripletFeelDurations = class {
		firstBeatDuration = 0;
		secondBeatStartOffset = 0;
		secondBeatDuration = 0;
	};
	/**
	* @internal
	*/
	var RasgueadoInfo = class {
		durations = [];
		brushInfos = [];
	};
	/**
	* @internal
	*/
	var PlayThroughContext = class {
		synthTick = 0;
		synthTime = 0;
		currentTempo = 0;
		automationToSyncPoint = /* @__PURE__ */ new Map();
		syncPoints;
		createNewSyncPoints = false;
	};
	/**
	* This generator creates a midi file using a score.
	* @public
	*/
	var MidiFileGenerator = class MidiFileGenerator {
		static _defaultDurationDead = 30;
		static _defaultDurationPalmMute = 80;
		_score;
		_settings;
		_handler;
		_programsPerChannel = /* @__PURE__ */ new Map();
		_currentTime = 0;
		_calculatedBeatTimers = /* @__PURE__ */ new Set();
		/**
		* Gets a lookup object which can be used to quickly find beats and bars
		* at a given midi tick position.
		*/
		tickLookup = new MidiTickLookup();
		/**
		* Gets or sets whether transposition pitches should be applied to the individual midi events or not.
		*/
		applyTranspositionPitches = true;
		/**
		* The computed sync points for synchronizing the midi file with an external backing track.
		*/
		syncPoints = [];
		/**
		* Gets the transposition pitches for the individual midi channels.
		*/
		transpositionPitches = /* @__PURE__ */ new Map();
		/**
		* Initializes a new instance of the {@link MidiFileGenerator} class.
		* @param score The score for which the midi file should be generated.
		* @param settings The settings ot use for generation.
		* @param handler The handler that should be used for generating midi events.
		*/
		constructor(score, settings, handler) {
			this._score = score;
			this._settings = !settings ? new Settings() : settings;
			this._handler = handler;
		}
		/**
		* Starts the generation of the midi file.
		*/
		generate() {
			this.transpositionPitches.clear();
			this._calculatedBeatTimers.clear();
			this._currentTime = 0;
			for (const track of this._score.tracks) this._generateTrack(track);
			Logger.debug("Midi", "Begin midi generation");
			this.syncPoints = [];
			MidiFileGenerator._playThroughSong(this._score, this.syncPoints, false, (bar, previousMasterBar, currentTick, currentTempo, occurence) => {
				this._generateMasterBar(bar, previousMasterBar, currentTick, currentTempo, occurence);
				if (bar.index === 0 && occurence === 0) this._detectTickShift();
			}, (index, currentTick, currentTempo) => {
				for (const track of this._score.tracks) for (const staff of track.staves) if (index < staff.bars.length) this._generateBar(staff.bars[index], currentTick, currentTempo);
			}, (endTick) => {
				for (const track of this._score.tracks) this._handler.finishTrack(track.index, endTick);
			});
			Logger.debug("Midi", "Midi generation done");
		}
		_detectTickShift() {
			let tickShift = 0;
			for (const track of this._score.tracks) for (const staff of track.staves) for (const voice of staff.bars[0].voices) if (!voice.isEmpty) {
				const beat = voice.beats[0];
				if (beat.playbackStart < tickShift) tickShift = beat.playbackStart;
			}
			tickShift = Math.abs(tickShift);
			this._handler.addTickShift(tickShift);
		}
		_generateTrack(track) {
			this._generateChannel(track, track.playbackInfo.primaryChannel, track.playbackInfo);
			if (track.playbackInfo.primaryChannel !== track.playbackInfo.secondaryChannel) this._generateChannel(track, track.playbackInfo.secondaryChannel, track.playbackInfo);
		}
		_addProgramChange(track, tick, channel, program) {
			if (!this._programsPerChannel.has(channel) || this._programsPerChannel.get(channel) !== program) {
				this._handler.addProgramChange(track.index, tick, channel, program);
				this._programsPerChannel.set(channel, program);
			}
		}
		_addBankChange(track, tick, channel, bank) {
			const lsbMsb = GeneralMidi.bankToLsbMsb(bank);
			this._handler.addControlChange(track.index, tick, channel, ControllerType.BankSelectCoarse, lsbMsb[1]);
			this._handler.addControlChange(track.index, tick, channel, ControllerType.BankSelectFine, lsbMsb[0]);
		}
		static buildTranspositionPitches(score, settings) {
			const transpositionPitches = /* @__PURE__ */ new Map();
			for (const track of score.tracks) {
				const transpositionPitch = track.index < settings.notation.transpositionPitches.length ? settings.notation.transpositionPitches[track.index] : -track.staves[0].transpositionPitch;
				transpositionPitches.set(track.playbackInfo.primaryChannel, transpositionPitch);
				transpositionPitches.set(track.playbackInfo.secondaryChannel, transpositionPitch);
			}
			return transpositionPitches;
		}
		_generateChannel(track, channel, playbackInfo) {
			const transpositionPitch = track.index < this._settings.notation.transpositionPitches.length ? this._settings.notation.transpositionPitches[track.index] : -track.staves[0].transpositionPitch;
			this.transpositionPitches.set(channel, transpositionPitch);
			const volume = MidiFileGenerator._toChannelShort(playbackInfo.volume);
			const balance = MidiFileGenerator._toChannelShort(playbackInfo.balance);
			this._handler.addControlChange(track.index, 0, channel, ControllerType.VolumeCoarse, volume);
			this._handler.addControlChange(track.index, 0, channel, ControllerType.PanCoarse, balance);
			this._handler.addControlChange(track.index, 0, channel, ControllerType.ExpressionControllerCoarse, 127);
			this._handler.addControlChange(track.index, 0, channel, ControllerType.RegisteredParameterFine, 0);
			this._handler.addControlChange(track.index, 0, channel, ControllerType.RegisteredParameterCourse, 0);
			this._handler.addControlChange(track.index, 0, channel, ControllerType.DataEntryFine, 0);
			this._handler.addControlChange(track.index, 0, channel, ControllerType.DataEntryCoarse, MidiFileGenerator._pitchBendRangeInSemitones);
			this._addBankChange(track, 0, channel, playbackInfo.bank);
			this._addProgramChange(track, 0, channel, playbackInfo.program);
		}
		/**
		* Generates the sync points for the given score without re-generating the midi itself.
		* @remarks
		* Use this method if a re-generation of the sync points after modification is required.
		* It correctly handles repeats and places sync points accoridng to their absolute midi tick when they
		* need to be considered for synchronization.
		* @param score The song for which to regenerate the sync points.
		* @param createNew Whether a new set of sync points should be generated for the sync (start, stop and tempo changes).
		* @returns The generated sync points for usage in the backing track playback.
		*/
		static generateSyncPoints(score, createNew = false) {
			const syncPoints = [];
			MidiFileGenerator._playThroughSong(score, syncPoints, createNew, (_masterBar, _previousMasterBar, _currentTick, _currentTempo, _barOccurence) => {}, (_barIndex, _currentTick, _currentTempo) => {}, (_endTick) => {});
			return syncPoints;
		}
		/**
		* @internal
		*/
		static buildModifiedTempoLookup(score) {
			return MidiFileGenerator._playThroughSong(score, [], false, (_masterBar, _previousMasterBar, _currentTick, _currentTempo, _barOccurence) => {}, (_barIndex, _currentTick, _currentTempo) => {}, (_endTick) => {}).automationToSyncPoint;
		}
		static _playThroughSong(score, syncPoints, createNewSyncPoints, generateMasterBar, generateTracks, finish) {
			const controller = new MidiPlaybackController(score);
			const playContext = new PlayThroughContext();
			playContext.currentTempo = score.tempo;
			playContext.syncPoints = syncPoints;
			playContext.createNewSyncPoints = createNewSyncPoints;
			let previousMasterBar = null;
			const barOccurence = /* @__PURE__ */ new Map();
			while (!controller.finished) {
				const index = controller.index;
				const bar = score.masterBars[index];
				const currentTick = controller.currentTick;
				controller.processCurrent();
				if (controller.shouldPlay) {
					let occurence = barOccurence.has(index) ? barOccurence.get(index) : -1;
					occurence++;
					barOccurence.set(index, occurence);
					generateMasterBar(bar, previousMasterBar, currentTick, playContext.currentTempo, occurence);
					generateTracks(index, currentTick, bar.tempoAutomations.length > 0 ? bar.tempoAutomations[0].value : playContext.currentTempo);
					playContext.synthTick = currentTick;
					MidiFileGenerator._processBarTime(bar, occurence, playContext);
				}
				controller.moveNext();
				previousMasterBar = bar;
			}
			if (syncPoints.length > 0) {
				const lastSyncPoint = syncPoints[syncPoints.length - 1];
				const remainingTicks = controller.currentTick - lastSyncPoint.synthTick;
				if (remainingTicks > 0) {
					const backingTrackSyncPoint = new BackingTrackSyncPoint();
					backingTrackSyncPoint.masterBarIndex = previousMasterBar.index;
					backingTrackSyncPoint.masterBarOccurence = barOccurence.get(previousMasterBar.index) - 1;
					backingTrackSyncPoint.synthTick = controller.currentTick;
					backingTrackSyncPoint.synthBpm = playContext.currentTempo;
					if (playContext.createNewSyncPoints) {
						backingTrackSyncPoint.syncBpm = lastSyncPoint.synthBpm;
						backingTrackSyncPoint.synthBpm = lastSyncPoint.synthBpm;
					} else if (syncPoints.length === 1) backingTrackSyncPoint.syncBpm = lastSyncPoint.synthBpm;
					else backingTrackSyncPoint.syncBpm = syncPoints[syncPoints.length - 2].syncBpm;
					backingTrackSyncPoint.synthTime = lastSyncPoint.synthTime + MidiUtils.ticksToMillis(remainingTicks, lastSyncPoint.synthBpm);
					backingTrackSyncPoint.syncTime = lastSyncPoint.syncTime + MidiUtils.ticksToMillis(remainingTicks, backingTrackSyncPoint.syncBpm);
					if (!playContext.createNewSyncPoints) lastSyncPoint.updateSyncBpm(backingTrackSyncPoint.synthTime, backingTrackSyncPoint.syncTime);
					syncPoints.push(backingTrackSyncPoint);
				}
			}
			finish(controller.currentTick);
			return playContext;
		}
		static _processBarTime(bar, occurence, context) {
			const duration = bar.calculateDuration();
			const barSyncPoints = bar.syncPoints;
			const barStartTick = context.synthTick;
			if (context.createNewSyncPoints) MidiFileGenerator._processBarTimeWithNewSyncPoints(bar, occurence, context);
			else if (barSyncPoints) MidiFileGenerator._processBarTimeWithSyncPoints(bar, occurence, context);
			else MidiFileGenerator._processBarTimeNoSyncPoints(bar, context);
			const endTick = barStartTick + duration;
			const tickOffset = endTick - context.synthTick;
			if (tickOffset > 0) {
				context.synthTime += MidiUtils.ticksToMillis(tickOffset, context.currentTempo);
				context.synthTick = endTick;
			}
		}
		static _processBarTimeWithNewSyncPoints(bar, occurence, context) {
			const barStartTick = context.synthTick;
			if (bar.index === 0 && occurence === 0) {
				context.currentTempo = bar.score.tempo;
				const backingTrackSyncPoint = new BackingTrackSyncPoint();
				backingTrackSyncPoint.masterBarIndex = bar.index;
				backingTrackSyncPoint.masterBarOccurence = occurence;
				backingTrackSyncPoint.synthTick = barStartTick;
				backingTrackSyncPoint.synthBpm = context.currentTempo;
				backingTrackSyncPoint.synthTime = context.synthTime;
				backingTrackSyncPoint.syncBpm = context.currentTempo;
				backingTrackSyncPoint.syncTime = context.synthTime;
				context.syncPoints.push(backingTrackSyncPoint);
			}
			const duration = bar.calculateDuration();
			for (const change of bar.tempoAutomations) {
				const absoluteTick = barStartTick + change.ratioPosition * duration;
				const tickOffset = absoluteTick - context.synthTick;
				if (tickOffset > 0) {
					context.synthTick = absoluteTick;
					context.synthTime += MidiUtils.ticksToMillis(tickOffset, context.currentTempo);
				}
				if (change.value !== context.currentTempo) {
					context.currentTempo = change.value;
					const backingTrackSyncPoint = new BackingTrackSyncPoint();
					backingTrackSyncPoint.masterBarIndex = bar.index;
					backingTrackSyncPoint.masterBarOccurence = occurence;
					backingTrackSyncPoint.synthTick = absoluteTick;
					backingTrackSyncPoint.synthBpm = context.currentTempo;
					backingTrackSyncPoint.synthTime = context.synthTime;
					backingTrackSyncPoint.syncBpm = context.currentTempo;
					backingTrackSyncPoint.syncTime = context.synthTime;
					context.syncPoints.push(backingTrackSyncPoint);
				}
			}
		}
		static _processBarTimeWithSyncPoints(bar, occurence, context) {
			const barStartTick = context.synthTick;
			const duration = bar.calculateDuration();
			let tempoChangeIndex = 0;
			let tickOffset;
			for (const syncPoint of bar.syncPoints) {
				if (syncPoint.syncPointValue.barOccurence !== occurence) continue;
				const syncPointTick = barStartTick + syncPoint.ratioPosition * duration;
				while (tempoChangeIndex < bar.tempoAutomations.length && bar.tempoAutomations[tempoChangeIndex].ratioPosition <= syncPoint.ratioPosition) {
					const tempoChange = bar.tempoAutomations[tempoChangeIndex];
					const absoluteTick = barStartTick + tempoChange.ratioPosition * duration;
					tickOffset = absoluteTick - context.synthTick;
					if (tickOffset > 0) {
						context.synthTick = absoluteTick;
						context.synthTime += MidiUtils.ticksToMillis(tickOffset, context.currentTempo);
					}
					context.currentTempo = tempoChange.value;
					tempoChangeIndex++;
				}
				tickOffset = syncPointTick - context.synthTick;
				if (tickOffset > 0) {
					context.synthTick = syncPointTick;
					context.synthTime += MidiUtils.ticksToMillis(tickOffset, context.currentTempo);
				}
				if (context.syncPoints.length > 0) context.syncPoints[context.syncPoints.length - 1].updateSyncBpm(context.synthTime, syncPoint.syncPointValue.millisecondOffset);
				const backingTrackSyncPoint = new BackingTrackSyncPoint();
				backingTrackSyncPoint.masterBarIndex = bar.index;
				backingTrackSyncPoint.masterBarOccurence = occurence;
				backingTrackSyncPoint.synthTick = syncPointTick;
				backingTrackSyncPoint.synthBpm = context.currentTempo;
				backingTrackSyncPoint.synthTime = context.synthTime;
				backingTrackSyncPoint.syncTime = syncPoint.syncPointValue.millisecondOffset;
				backingTrackSyncPoint.syncBpm = 0;
				context.syncPoints.push(backingTrackSyncPoint);
				context.automationToSyncPoint.set(syncPoint, backingTrackSyncPoint);
			}
			while (tempoChangeIndex < bar.tempoAutomations.length) {
				const tempoChange = bar.tempoAutomations[tempoChangeIndex];
				const absoluteTick = barStartTick + tempoChange.ratioPosition * duration;
				tickOffset = absoluteTick - context.synthTick;
				if (tickOffset > 0) {
					context.synthTick = absoluteTick;
					context.synthTime += MidiUtils.ticksToMillis(tickOffset, context.currentTempo);
				}
				context.currentTempo = tempoChange.value;
				tempoChangeIndex++;
			}
		}
		static _processBarTimeNoSyncPoints(bar, context) {
			const barStartTick = context.synthTick;
			const duration = bar.calculateDuration();
			for (const changes of bar.tempoAutomations) {
				const absoluteTick = barStartTick + changes.ratioPosition * duration;
				const tickOffset = absoluteTick - context.synthTick;
				if (tickOffset > 0) {
					context.synthTick = absoluteTick;
					context.synthTime += MidiUtils.ticksToMillis(tickOffset, context.currentTempo);
				}
				context.currentTempo = changes.value;
			}
		}
		static _toChannelShort(data) {
			const value = Math.max(-32768, Math.min(32767, data * 8 - 1));
			return Math.max(value, -1) + 1;
		}
		_generateMasterBar(masterBar, previousMasterBar, currentTick, currentTempo, _barOccurence) {
			if (!previousMasterBar || previousMasterBar.timeSignatureDenominator !== masterBar.timeSignatureDenominator || previousMasterBar.timeSignatureNumerator !== masterBar.timeSignatureNumerator) this._handler.addTimeSignature(currentTick, masterBar.timeSignatureNumerator, masterBar.timeSignatureDenominator);
			const masterBarDuration = masterBar.calculateDuration();
			const masterBarLookup = new MasterBarTickLookup();
			if (masterBar.tempoAutomations.length > 0) {
				if (masterBar.tempoAutomations[0].ratioPosition > 0) masterBarLookup.tempoChanges.push(new MasterBarTickLookupTempoChange(currentTick, currentTempo));
				for (const automation of masterBar.tempoAutomations) {
					const tick = currentTick + masterBarDuration * automation.ratioPosition;
					this._handler.addTempo(tick, automation.value);
					masterBarLookup.tempoChanges.push(new MasterBarTickLookupTempoChange(tick, automation.value));
				}
			} else if (!previousMasterBar) {
				this._handler.addTempo(currentTick, masterBar.score.tempo);
				masterBarLookup.tempoChanges.push(new MasterBarTickLookupTempoChange(currentTick, masterBar.score.tempo));
			} else masterBarLookup.tempoChanges.push(new MasterBarTickLookupTempoChange(currentTick, currentTempo));
			masterBarLookup.masterBar = masterBar;
			masterBarLookup.start = currentTick;
			masterBarLookup.end = masterBarLookup.start + masterBarDuration;
			this.tickLookup.addMasterBar(masterBarLookup);
		}
		_generateBar(bar, barStartTick, tempoOnBarStart) {
			const playbackBar = this._getPlaybackBar(bar);
			const barStartTime = this._currentTime;
			for (const v of playbackBar.voices) {
				this._currentTime = barStartTime;
				this._generateVoice(v, barStartTick, bar, tempoOnBarStart);
			}
			const masterBar = playbackBar.masterBar;
			const tickDuration = masterBar.calculateDuration();
			const tempoAutomations = masterBar.tempoAutomations.slice();
			if (tempoAutomations.length === 0) this._currentTime = barStartTime + MidiUtils.ticksToMillis(tickDuration, tempoOnBarStart);
			else {
				this._currentTime = barStartTime;
				let currentTick = barStartTick;
				let currentTempo = tempoOnBarStart;
				const endTick = barStartTick + tickDuration;
				for (const automation of tempoAutomations) {
					const diff = tickDuration * automation.ratioPosition - currentTick;
					if (diff > 0) this._currentTime += MidiUtils.ticksToMillis(diff, currentTempo);
					currentTempo = automation.value;
					currentTick += diff;
				}
				const remainingTick = endTick - currentTick;
				if (remainingTick > 0) this._currentTime += MidiUtils.ticksToMillis(remainingTick, currentTempo);
			}
			if (playbackBar.id !== bar.id) this.tickLookup.addBeat(bar.voices[0].beats[0], 0, tickDuration);
		}
		_getPlaybackBar(bar) {
			switch (bar.simileMark) {
				case SimileMark.Simple:
					if (bar.previousBar) bar = this._getPlaybackBar(bar.previousBar);
					break;
				case SimileMark.FirstOfDouble:
					if (bar.previousBar && bar.previousBar.previousBar) bar = this._getPlaybackBar(bar.previousBar.previousBar);
					break;
				case SimileMark.SecondOfDouble:
					if (bar.previousBar && bar.previousBar.previousBar) bar = this._getPlaybackBar(bar.previousBar.previousBar);
					break;
			}
			return bar;
		}
		_generateVoice(voice, barStartTick, realBar, tempoOnVoiceStart) {
			if (voice.isEmpty && (!voice.bar.isEmpty || voice.index !== 0)) return;
			const remainingBarTempoAutomations = realBar.masterBar.tempoAutomations.slice();
			let tempoOnBeatStart = tempoOnVoiceStart;
			const barDuration = realBar.masterBar.calculateDuration();
			for (const b of voice.beats) {
				const ratio = b.playbackStart / barDuration;
				while (remainingBarTempoAutomations.length > 0 && remainingBarTempoAutomations[0].ratioPosition <= ratio) tempoOnBeatStart = remainingBarTempoAutomations.shift().value;
				this._generateBeat(b, barStartTick, realBar, tempoOnBeatStart);
			}
		}
		_currentTripletFeel = null;
		_generateBeat(beat, barStartTick, realBar, tempoOnBeatStart) {
			let beatStart = beat.playbackStart;
			let audioDuration = beat.playbackDuration;
			const masterBarDuration = beat.voice.bar.masterBar.calculateDuration();
			if (beat.voice.bar.isEmpty && beat.voice.beats.length === 1) audioDuration = masterBarDuration;
			else if (beat.voice.bar.masterBar.tripletFeel !== TripletFeel.NoTripletFeel && this._settings.player.playTripletFeel) if (this._currentTripletFeel) {
				beatStart -= this._currentTripletFeel.secondBeatStartOffset;
				audioDuration = this._currentTripletFeel.secondBeatDuration;
				this._currentTripletFeel = null;
			} else {
				this._currentTripletFeel = MidiFileGenerator._calculateTripletFeelInfo(beatStart, audioDuration, beat);
				if (this._currentTripletFeel) audioDuration = this._currentTripletFeel.firstBeatDuration;
			}
			if (beat.showTimer && !this._calculatedBeatTimers.has(beat.id)) {
				beat.timer = this._currentTime;
				this._calculatedBeatTimers.add(beat.id);
			}
			this._currentTime += MidiUtils.ticksToMillis(audioDuration, tempoOnBeatStart);
			if (realBar === beat.voice.bar) this.tickLookup.addBeat(beat, beatStart, audioDuration);
			const track = beat.voice.bar.staff.track;
			for (const automation of beat.automations) this._generateNonTempoAutomation(beat, automation, barStartTick);
			if (beat.isRest) this._handler.addRest(track.index, barStartTick + beatStart, track.playbackInfo.primaryChannel);
			else if (beat.deadSlapped) this._generateDeadSlap(beat, barStartTick + beatStart);
			else {
				const brushInfo = this._getBrushInfo(beat);
				const rasgueadoInfo = this._getRasgueadoInfo(beat, audioDuration);
				for (const n of beat.notes) this._generateNote(n, barStartTick + beatStart, audioDuration, tempoOnBeatStart, brushInfo, rasgueadoInfo);
			}
			if (beat.fade !== FadeType.None) this._generateFade(beat, barStartTick + beatStart, audioDuration);
			if (beat.vibrato !== VibratoType.None) {
				let phaseLength = 240;
				let bendAmplitude = 3;
				switch (beat.vibrato) {
					case VibratoType.Slight:
						phaseLength = this._settings.player.vibrato.beatSlightLength;
						bendAmplitude = this._settings.player.vibrato.beatSlightAmplitude;
						break;
					case VibratoType.Wide:
						phaseLength = this._settings.player.vibrato.beatWideLength;
						bendAmplitude = this._settings.player.vibrato.beatWideAmplitude;
						break;
				}
				this._generateVibratorWithParams(barStartTick + beatStart, beat.playbackDuration, phaseLength, 0, bendAmplitude, (tick, value) => {
					this._handler.addBend(beat.voice.bar.staff.track.index, tick, track.playbackInfo.secondaryChannel, value);
				});
			}
		}
		static _calculateTripletFeelInfo(beatStart, audioDuration, beat) {
			let initialDuration;
			switch (beat.voice.bar.masterBar.tripletFeel) {
				case TripletFeel.Triplet8th:
				case TripletFeel.Dotted8th:
				case TripletFeel.Scottish8th:
					initialDuration = Duration.Eighth;
					break;
				case TripletFeel.Triplet16th:
				case TripletFeel.Dotted16th:
				case TripletFeel.Scottish16th:
					initialDuration = Duration.Sixteenth;
					break;
				default: return null;
			}
			const interval = MidiUtils.toTicks(initialDuration);
			if (audioDuration !== interval) return null;
			if (beatStart % (interval * 2) !== 0) return null;
			if (!beat.nextBeat || beat.nextBeat.voice !== beat.voice || beat.nextBeat.playbackDuration !== interval || beat.nextBeat.playbackStart !== beatStart + interval) return null;
			const durations = new TripletFeelDurations();
			switch (beat.voice.bar.masterBar.tripletFeel) {
				case TripletFeel.Triplet8th:
					durations.firstBeatDuration = MidiUtils.applyTuplet(MidiUtils.toTicks(Duration.Quarter), 3, 2);
					durations.secondBeatDuration = MidiUtils.applyTuplet(MidiUtils.toTicks(Duration.Eighth), 3, 2);
					break;
				case TripletFeel.Dotted8th:
					durations.firstBeatDuration = MidiUtils.applyDot(MidiUtils.toTicks(Duration.Eighth), false);
					durations.secondBeatDuration = MidiUtils.toTicks(Duration.Sixteenth);
					break;
				case TripletFeel.Scottish8th:
					durations.firstBeatDuration = MidiUtils.toTicks(Duration.Sixteenth);
					durations.secondBeatDuration = MidiUtils.applyDot(MidiUtils.toTicks(Duration.Eighth), false);
					break;
				case TripletFeel.Triplet16th:
					durations.firstBeatDuration = MidiUtils.applyTuplet(MidiUtils.toTicks(Duration.Eighth), 3, 2);
					durations.secondBeatDuration = MidiUtils.applyTuplet(MidiUtils.toTicks(Duration.Sixteenth), 3, 2);
					break;
				case TripletFeel.Dotted16th:
					durations.firstBeatDuration = MidiUtils.applyDot(MidiUtils.toTicks(Duration.Sixteenth), false);
					durations.secondBeatDuration = MidiUtils.toTicks(Duration.ThirtySecond);
					break;
				case TripletFeel.Scottish16th:
					durations.firstBeatDuration = MidiUtils.toTicks(Duration.ThirtySecond);
					durations.secondBeatDuration = MidiUtils.applyDot(MidiUtils.toTicks(Duration.Sixteenth), false);
					break;
			}
			durations.secondBeatStartOffset = audioDuration - durations.firstBeatDuration;
			return durations;
		}
		_generateDeadSlap(beat, beatStart) {
			const deadSlapDuration = MidiUtils.toTicks(Duration.SixtyFourth);
			const staff = beat.voice.bar.staff;
			if (staff.tuning.length > 0) for (const t of staff.tuning) this._handler.addNote(staff.track.index, beatStart, deadSlapDuration, t, MidiUtils.dynamicToVelocity(DynamicValue.F), staff.track.playbackInfo.primaryChannel);
		}
		_needsSecondaryChannel(note) {
			return note.hasBend || note.beat.hasWhammyBar || note.beat.vibrato !== VibratoType.None;
		}
		_determineChannel(track, note) {
			if (this._needsSecondaryChannel(note)) return track.playbackInfo.secondaryChannel;
			let currentNote = note;
			while (currentNote.isTieDestination) {
				currentNote = currentNote.tieOrigin;
				if (this._needsSecondaryChannel(currentNote)) return track.playbackInfo.secondaryChannel;
			}
			currentNote = note;
			while (currentNote.isTieOrigin) {
				currentNote = currentNote.tieDestination;
				if (this._needsSecondaryChannel(currentNote)) return track.playbackInfo.secondaryChannel;
			}
			return track.playbackInfo.primaryChannel;
		}
		_generateNote(note, beatStart, beatDuration, tempoOnBeatStart, brushInfo, rasgueadoInfo) {
			const track = note.beat.voice.bar.staff.track;
			const staff = note.beat.voice.bar.staff;
			let noteKey = note.calculateRealValue(this.applyTranspositionPitches, true);
			if (note.isPercussion) {
				const articulation = PercussionMapper.getArticulation(note);
				if (articulation) noteKey = articulation.outputMidiNumber;
			}
			const brushOffset = rasgueadoInfo == null && note.isStringed && note.string <= brushInfo.length ? brushInfo[note.string - 1] : 0;
			const noteStart = beatStart + brushOffset;
			const noteDuration = this._getNoteDuration(note, beatDuration, tempoOnBeatStart);
			noteDuration.untilTieOrSlideEnd -= brushOffset;
			noteDuration.noteOnly -= brushOffset;
			noteDuration.letRingEnd -= brushOffset;
			const velocity = MidiFileGenerator._getNoteVelocity(note);
			const channel = this._determineChannel(track, note);
			let initialBend = 0;
			const noteSoundDuration = Math.max(noteDuration.untilTieOrSlideEnd, noteDuration.letRingEnd);
			if (note.hasBend) initialBend = MidiFileGenerator.getPitchWheel(note.bendPoints[0].value);
			else if (note.beat.hasWhammyBar) initialBend = MidiFileGenerator.getPitchWheel(note.beat.whammyBarPoints[0].value);
			else if (note.isTieDestination || note.slideOrigin && note.slideOrigin.slideOutType === SlideOutType.Legato) initialBend = -1;
			else initialBend = MidiFileGenerator.getPitchWheel(0);
			if (initialBend >= 0) this._handler.addNoteBend(track.index, noteStart, channel, noteKey, initialBend);
			if (note.beat.hasRasgueado) {
				this._generateRasgueado(track, note, noteStart, noteKey, velocity, channel, rasgueadoInfo);
				return;
			}
			if (note.ornament !== NoteOrnament.None) {
				this._generateOrnament(track, note, noteStart, noteSoundDuration, noteKey, velocity, channel);
				return;
			}
			if (note.isTrill && !staff.isPercussion) {
				this._generateTrill(note, noteStart, noteDuration, noteKey, velocity, channel);
				return;
			}
			if (note.beat.isTremolo) {
				this._generateTremoloPicking(note, noteStart, noteDuration, noteKey, velocity, channel);
				return;
			}
			if (note.hasBend) this._generateBend(note, noteStart, noteDuration, noteKey, channel, tempoOnBeatStart);
			else if (note.beat.hasWhammyBar && note.index === 0) this._generateWhammy(note.beat, noteStart, noteDuration, channel, tempoOnBeatStart);
			else if (note.slideInType !== SlideInType.None || note.slideOutType !== SlideOutType.None) this._generateSlide(note, noteStart, noteDuration, noteKey, channel, tempoOnBeatStart);
			else if (note.vibrato !== VibratoType.None || note.isTieDestination && note.tieOrigin.vibrato !== VibratoType.None) this._generateVibrato(note, noteStart, noteDuration, noteKey, channel);
			if (!note.isTieDestination && (!note.slideOrigin || note.slideOrigin.slideOutType !== SlideOutType.Legato)) this._handler.addNote(track.index, noteStart, noteSoundDuration, noteKey, velocity, channel);
		}
		/**
		* For every note within the octave, the number of keys to go up when playing ornaments.
		* For white keys this is the next white key,
		* For black keys it is either the next black or white key depending on the distance.
		*
		* Ornaments are not really a strictly defined element, alphaTab is using shipping some default.
		*/
		static _ornamentKeysUp = [
			2,
			2,
			2,
			1,
			1,
			2,
			2,
			2,
			2,
			2,
			1,
			1
		];
		/**
		* For every note within the octave, the number of keys to go down when playing ornaments.
		* This is typically only a key down.
		*
		* Ornaments are not really a strictly defined element, alphaTab is using shipping some default.
		*/
		static ornamentKeysDown = [
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1,
			-1
		];
		_generateOrnament(track, note, noteStart, noteDuration, noteKey, velocity, channel) {
			let ornamentNoteKeys;
			let ornamentNoteDurations;
			const index = noteKey % 12;
			const triplet = 1 / 3;
			switch (note.ornament) {
				case NoteOrnament.Turn:
					ornamentNoteKeys = [
						noteKey + MidiFileGenerator._ornamentKeysUp[index],
						noteKey,
						noteKey + MidiFileGenerator.ornamentKeysDown[index]
					];
					ornamentNoteDurations = [
						MidiUtils.toTicks(Duration.Sixteenth) * triplet,
						MidiUtils.toTicks(Duration.Sixteenth) * triplet,
						MidiUtils.toTicks(Duration.Sixteenth) * triplet
					];
					break;
				case NoteOrnament.InvertedTurn:
					ornamentNoteKeys = [
						noteKey + MidiFileGenerator.ornamentKeysDown[index],
						noteKey,
						noteKey + MidiFileGenerator._ornamentKeysUp[index]
					];
					ornamentNoteDurations = [
						MidiUtils.toTicks(Duration.Sixteenth) * triplet,
						MidiUtils.toTicks(Duration.Sixteenth) * triplet,
						MidiUtils.toTicks(Duration.Sixteenth) * triplet
					];
					break;
				case NoteOrnament.UpperMordent:
					ornamentNoteKeys = [noteKey, noteKey + MidiFileGenerator._ornamentKeysUp[index]];
					ornamentNoteDurations = [MidiUtils.toTicks(Duration.ThirtySecond), MidiUtils.toTicks(Duration.ThirtySecond)];
					break;
				case NoteOrnament.LowerMordent:
					ornamentNoteKeys = [noteKey, noteKey + MidiFileGenerator.ornamentKeysDown[index]];
					ornamentNoteDurations = [MidiUtils.toTicks(Duration.ThirtySecond), MidiUtils.toTicks(Duration.ThirtySecond)];
					break;
				default: return;
			}
			let ornamentDurationFactor = 1;
			if (noteDuration < MidiUtils.QuarterTime) ornamentDurationFactor = noteDuration / MidiUtils.QuarterTime;
			velocity -= MidiUtils.VelocityIncrement;
			let totalOrnamentDuration = 0;
			for (let i = 0; i < ornamentNoteKeys.length; i++) {
				const realDuration = ornamentNoteDurations[i] * ornamentDurationFactor;
				this._handler.addNote(track.index, noteStart, realDuration, ornamentNoteKeys[i], velocity, channel);
				noteStart += realDuration;
				totalOrnamentDuration += realDuration;
			}
			const remaining = noteDuration - totalOrnamentDuration;
			this._handler.addNote(track.index, noteStart, remaining, noteKey, velocity, channel);
		}
		_getNoteDuration(note, beatPlayDuration, tempoOnBeatStart) {
			const durationWithEffects = new MidiNoteDuration();
			durationWithEffects.beatDurationFactor = beatPlayDuration / MidiUtils.toTicks(note.beat.duration);
			durationWithEffects.noteOnly = beatPlayDuration;
			durationWithEffects.untilTieOrSlideEnd = beatPlayDuration;
			durationWithEffects.letRingEnd = beatPlayDuration;
			if (note.isDead) {
				durationWithEffects.noteOnly = this._applyStaticDuration(MidiFileGenerator._defaultDurationDead, beatPlayDuration, tempoOnBeatStart);
				durationWithEffects.untilTieOrSlideEnd = durationWithEffects.noteOnly;
				durationWithEffects.letRingEnd = durationWithEffects.noteOnly;
				return durationWithEffects;
			}
			if (note.isPalmMute) {
				durationWithEffects.noteOnly = this._applyStaticDuration(MidiFileGenerator._defaultDurationPalmMute, beatPlayDuration, tempoOnBeatStart);
				durationWithEffects.untilTieOrSlideEnd = durationWithEffects.noteOnly;
				durationWithEffects.letRingEnd = durationWithEffects.noteOnly;
				return durationWithEffects;
			}
			if (note.isStaccato) {
				durationWithEffects.noteOnly = beatPlayDuration / 2 | 0;
				durationWithEffects.untilTieOrSlideEnd = durationWithEffects.noteOnly;
				durationWithEffects.letRingEnd = durationWithEffects.noteOnly;
				return durationWithEffects;
			}
			if (note.isTieOrigin) {
				const endNote = note.tieDestination;
				if (endNote) if (!note.isTieDestination) {
					const startTick = note.beat.absolutePlaybackStart;
					const tieDestinationDuration = this._getNoteDuration(endNote, endNote.beat.playbackDuration, tempoOnBeatStart);
					durationWithEffects.untilTieOrSlideEnd = endNote.beat.absolutePlaybackStart + tieDestinationDuration.untilTieOrSlideEnd - startTick;
				} else durationWithEffects.untilTieOrSlideEnd = beatPlayDuration + this._getNoteDuration(endNote, endNote.beat.playbackDuration, tempoOnBeatStart).untilTieOrSlideEnd;
			} else if (note.slideOutType === SlideOutType.Legato) {
				const endNote = note.slideTarget;
				if (endNote) {
					const startTick = note.beat.absolutePlaybackStart;
					const slideTargetDuration = this._getNoteDuration(endNote, endNote.beat.playbackDuration, tempoOnBeatStart);
					durationWithEffects.untilTieOrSlideEnd = endNote.beat.absolutePlaybackStart + slideTargetDuration.untilTieOrSlideEnd - startTick;
				}
			}
			if (note.isLetRing && this._settings.notation.notationMode === NotationMode.GuitarPro) {
				let lastLetRingBeat = note.beat;
				let letRingEnd = 0;
				const maxDuration = note.beat.voice.bar.masterBar.calculateDuration();
				while (lastLetRingBeat.nextBeat) {
					const next = lastLetRingBeat.nextBeat;
					if (next.isRest) break;
					if (note.isStringed && next.hasNoteOnString(note.string)) break;
					lastLetRingBeat = lastLetRingBeat.nextBeat;
					letRingEnd = lastLetRingBeat.absolutePlaybackStart - note.beat.absolutePlaybackStart + lastLetRingBeat.playbackDuration;
					if (letRingEnd > maxDuration) {
						letRingEnd = maxDuration;
						break;
					}
				}
				if (lastLetRingBeat === note.beat) durationWithEffects.letRingEnd = beatPlayDuration;
				else durationWithEffects.letRingEnd = letRingEnd;
			} else durationWithEffects.letRingEnd = durationWithEffects.untilTieOrSlideEnd;
			return durationWithEffects;
		}
		_applyStaticDuration(duration, maximum, tempo) {
			const value = tempo * duration / BendPoint.MaxPosition | 0;
			return Math.min(value, maximum);
		}
		static _getNoteVelocity(note) {
			let adjustment = 0;
			if (!note.beat.voice.bar.staff.isPercussion && note.hammerPullOrigin) adjustment--;
			if (note.isGhost) adjustment--;
			switch (note.accentuated) {
				case AccentuationType.Normal:
					adjustment++;
					break;
				case AccentuationType.Heavy:
					adjustment += 2;
					break;
			}
			return MidiUtils.dynamicToVelocity(note.dynamics, adjustment);
		}
		_generateFade(beat, beatStart, beatDuration) {
			const track = beat.voice.bar.staff.track;
			switch (beat.fade) {
				case FadeType.FadeIn:
					this._generateFadeSteps(track, beatStart, beatDuration, 0, MidiFileGenerator._toChannelShort(track.playbackInfo.volume));
					break;
				case FadeType.FadeOut:
					this._generateFadeSteps(track, beatStart, beatDuration, MidiFileGenerator._toChannelShort(track.playbackInfo.volume), 0);
					break;
				case FadeType.VolumeSwell:
					const half = beatDuration / 2 | 0;
					this._generateFadeSteps(track, beatStart, half, 0, MidiFileGenerator._toChannelShort(track.playbackInfo.volume));
					this._generateFadeSteps(track, beatStart + half, half, MidiFileGenerator._toChannelShort(track.playbackInfo.volume), 0);
					break;
			}
		}
		_generateFadeSteps(track, start, duration, startVolume, endVolume) {
			const tickStep = 120;
			duration = duration * .8 | 0;
			const volumeFactor = (endVolume - startVolume) / duration;
			const steps = duration / tickStep + 1 | 0;
			const endTick = start + duration;
			for (let i = 0; i < steps; i++) {
				const isLast = i === steps - 1;
				const tick = isLast ? endTick : start + i * tickStep;
				const volume = isLast ? endVolume : Math.round(startVolume + (tick - start) * volumeFactor);
				this._handler.addControlChange(track.index, tick, track.playbackInfo.primaryChannel, ControllerType.VolumeCoarse, volume);
				this._handler.addControlChange(track.index, tick, track.playbackInfo.secondaryChannel, ControllerType.VolumeCoarse, volume);
			}
		}
		_generateVibrato(note, noteStart, noteDuration, noteKey, channel) {
			let phaseLength = 0;
			let bendAmplitude = 0;
			switch (note.vibrato !== VibratoType.None ? note.vibrato : note.isTieDestination ? note.tieOrigin.vibrato : VibratoType.Slight) {
				case VibratoType.Slight:
					phaseLength = this._settings.player.vibrato.noteSlightLength;
					bendAmplitude = this._settings.player.vibrato.noteSlightAmplitude;
					break;
				case VibratoType.Wide:
					phaseLength = this._settings.player.vibrato.noteWideLength;
					bendAmplitude = this._settings.player.vibrato.noteWideAmplitude;
					break;
				default: return;
			}
			const track = note.beat.voice.bar.staff.track;
			let bendBase = 0;
			if (note.isTieDestination && note.tieOrigin.hasBend) {
				const bendPoints = note.tieOrigin.bendPoints;
				bendBase = bendPoints[bendPoints.length - 1].value;
			}
			this._generateVibratorWithParams(noteStart, noteDuration.noteOnly, phaseLength, bendBase, bendAmplitude, (tick, value) => {
				this._handler.addNoteBend(track.index, tick, channel, noteKey, value);
			});
		}
		vibratoResolution = 16;
		_generateVibratorWithParams(noteStart, noteDuration, phaseLength, bendBase, bendAmplitude, addBend) {
			const resolution = this.vibratoResolution;
			const phaseHalf = phaseLength / 2 | 0;
			const noteEnd = noteStart + noteDuration;
			while (noteStart < noteEnd) {
				let phase = 0;
				const phaseDuration = noteStart + phaseLength < noteEnd ? phaseLength : noteEnd - noteStart;
				while (phase < phaseDuration) {
					const bend = bendBase + bendAmplitude * Math.sin(phase * Math.PI / phaseHalf);
					addBend(noteStart + phase | 0, MidiFileGenerator.getPitchWheel(bend));
					phase += resolution;
				}
				noteStart += phaseLength;
			}
			addBend(noteEnd | 0, MidiFileGenerator.getPitchWheel(bendBase));
		}
		/**
		* Maximum semitones that are supported in bends in one direction (up or down)
		* GP has 8 full tones on whammys.
		*/
		static _pitchBendRangeInSemitones = 16;
		/**
		* The value on how many pitch-values are used for one semitone
		*/
		static _pitchValuePerSemitone = SynthConstants.DefaultPitchWheel / MidiFileGenerator._pitchBendRangeInSemitones;
		/**
		* The minimum number of breakpoints generated per semitone bend.
		*/
		static _minBreakpointsPerSemitone = 6;
		/**
		* How long until a new breakpoint is generated for a bend.
		*/
		static _millisecondsPerBreakpoint = 150;
		/**
		* Calculates the midi pitch wheel value for the give bend value.
		*/
		static getPitchWheel(bendValue) {
			return SynthConstants.DefaultPitchWheel + bendValue / 2 * MidiFileGenerator._pitchValuePerSemitone;
		}
		_generateSlide(note, noteStart, noteDuration, noteKey, channel, tempoOnBeatStart) {
			const duration = note.slideOutType === SlideOutType.Legato ? noteDuration.noteOnly : noteDuration.untilTieOrSlideEnd;
			const playedBendPoints = [];
			const track = note.beat.voice.bar.staff.track;
			const simpleSlidePitchOffset = this._settings.player.slide.simpleSlidePitchOffset;
			const simpleSlideDurationOffset = Math.floor(BendPoint.MaxPosition * this._settings.player.slide.simpleSlideDurationRatio);
			const shiftSlideDurationOffset = Math.floor(BendPoint.MaxPosition * this._settings.player.slide.shiftSlideDurationRatio);
			switch (note.slideInType) {
				case SlideInType.IntoFromAbove:
					playedBendPoints.push(new BendPoint(0, simpleSlidePitchOffset));
					playedBendPoints.push(new BendPoint(simpleSlideDurationOffset, 0));
					break;
				case SlideInType.IntoFromBelow:
					playedBendPoints.push(new BendPoint(0, -simpleSlidePitchOffset));
					playedBendPoints.push(new BendPoint(simpleSlideDurationOffset, 0));
					break;
			}
			switch (note.slideOutType) {
				case SlideOutType.Legato:
				case SlideOutType.Shift:
					playedBendPoints.push(new BendPoint(shiftSlideDurationOffset, 0));
					const dy = (note.slideTarget.calculateRealValue(this.applyTranspositionPitches, true) - note.calculateRealValue(this.applyTranspositionPitches, true)) * 2;
					playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, dy));
					break;
				case SlideOutType.OutDown:
					playedBendPoints.push(new BendPoint(BendPoint.MaxPosition - simpleSlideDurationOffset, 0));
					playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, -simpleSlidePitchOffset));
					break;
				case SlideOutType.OutUp:
					playedBendPoints.push(new BendPoint(BendPoint.MaxPosition - simpleSlideDurationOffset, 0));
					playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, simpleSlidePitchOffset));
					break;
			}
			this._generateWhammyOrBend(noteStart, duration, playedBendPoints, tempoOnBeatStart, (tick, value) => {
				this._handler.addNoteBend(track.index, tick, channel, noteKey, value);
			});
		}
		_generateBend(note, noteStart, noteDuration, noteKey, channel, tempoOnBeatStart) {
			const bendPoints = note.bendPoints;
			const track = note.beat.voice.bar.staff.track;
			const addBend = (tick, value) => {
				this._handler.addNoteBend(track.index, tick, channel, noteKey, value);
			};
			let finalBendValue = null;
			let duration;
			if (note.isTieOrigin && this._settings.notation.extendBendArrowsOnTiedNotes) {
				let endNote = note;
				while (endNote.isTieOrigin && !endNote.tieDestination.hasBend && endNote.tieDestination.vibrato === VibratoType.None) endNote = endNote.tieDestination;
				duration = endNote.beat.absolutePlaybackStart - note.beat.absolutePlaybackStart + this._getNoteDuration(endNote, endNote.beat.playbackDuration, tempoOnBeatStart).noteOnly;
			} else if (note.isTieOrigin && note.beat.graceType !== GraceType.None) {
				switch (note.tieDestination.bendType) {
					case BendType.Bend:
					case BendType.BendRelease:
					case BendType.PrebendBend:
						finalBendValue = note.tieDestination.bendPoints[1].value;
						break;
					case BendType.Prebend:
					case BendType.PrebendRelease:
						finalBendValue = note.tieDestination.bendPoints[0].value;
						break;
				}
				duration = Math.max(noteDuration.noteOnly, MidiUtils.millisToTicks(this._settings.player.songBookBendDuration, tempoOnBeatStart));
			} else duration = noteDuration.noteOnly;
			if (bendPoints[0].value > 0 && !note.isContinuedBend && noteStart > 0) noteStart--;
			const bendDuration = Math.min(duration, MidiUtils.millisToTicks(this._settings.player.songBookBendDuration, tempoOnBeatStart));
			let playedBendPoints = [];
			switch (note.bendType) {
				case BendType.Custom:
					playedBendPoints = bendPoints;
					break;
				case BendType.Bend:
				case BendType.Release:
					switch (note.bendStyle) {
						case BendStyle.Default:
							playedBendPoints = bendPoints;
							break;
						case BendStyle.Gradual:
							playedBendPoints.push(new BendPoint(0, note.bendPoints[0].value));
							if (!finalBendValue || finalBendValue < note.bendPoints[1].value) finalBendValue = note.bendPoints[1].value;
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, finalBendValue));
							break;
						case BendStyle.Fast:
							if (!finalBendValue || finalBendValue < note.bendPoints[1].value) finalBendValue = note.bendPoints[1].value;
							if (note.beat.graceType === GraceType.BendGrace) this._generateSongBookWhammyOrBend(noteStart, duration, true, [note.bendPoints[0].value, finalBendValue], bendDuration, tempoOnBeatStart, addBend);
							else this._generateSongBookWhammyOrBend(noteStart, duration, false, [note.bendPoints[0].value, finalBendValue], bendDuration, tempoOnBeatStart, addBend);
							return;
					}
					break;
				case BendType.BendRelease:
					switch (note.bendStyle) {
						case BendStyle.Default:
							playedBendPoints = bendPoints;
							break;
						case BendStyle.Gradual:
							playedBendPoints.push(new BendPoint(0, note.bendPoints[0].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition / 2 | 0, note.bendPoints[1].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, note.bendPoints[2].value));
							break;
						case BendStyle.Fast:
							this._generateSongBookWhammyOrBend(noteStart, duration, false, [
								note.bendPoints[0].value,
								note.bendPoints[1].value,
								note.bendPoints[2].value
							], bendDuration, tempoOnBeatStart, addBend);
							return;
					}
					break;
				case BendType.Hold:
					playedBendPoints = bendPoints;
					break;
				case BendType.Prebend:
					playedBendPoints = bendPoints;
					break;
				case BendType.PrebendBend:
					switch (note.bendStyle) {
						case BendStyle.Default:
							playedBendPoints = bendPoints;
							break;
						case BendStyle.Gradual:
							playedBendPoints.push(new BendPoint(0, note.bendPoints[0].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, note.bendPoints[1].value));
							break;
						case BendStyle.Fast:
							const preBendValue = MidiFileGenerator.getPitchWheel(note.bendPoints[0].value);
							addBend(noteStart, preBendValue | 0);
							if (!finalBendValue || finalBendValue < note.bendPoints[1].value) finalBendValue = note.bendPoints[1].value;
							this._generateSongBookWhammyOrBend(noteStart, duration, false, [note.bendPoints[0].value, finalBendValue], bendDuration, tempoOnBeatStart, addBend);
							return;
					}
					break;
				case BendType.PrebendRelease:
					switch (note.bendStyle) {
						case BendStyle.Default:
							playedBendPoints = bendPoints;
							break;
						case BendStyle.Gradual:
							playedBendPoints.push(new BendPoint(0, note.bendPoints[0].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, note.bendPoints[1].value));
							break;
						case BendStyle.Fast:
							const preBendValue = MidiFileGenerator.getPitchWheel(note.bendPoints[0].value);
							addBend(noteStart, preBendValue | 0);
							this._generateSongBookWhammyOrBend(noteStart, duration, false, [note.bendPoints[0].value, note.bendPoints[1].value], bendDuration, tempoOnBeatStart, addBend);
							return;
					}
					break;
			}
			this._generateWhammyOrBend(noteStart, duration, playedBendPoints, tempoOnBeatStart, addBend);
		}
		_generateSongBookWhammyOrBend(noteStart, duration, bendAtBeginning, bendValues, bendDuration, tempoOnBeatStart, addBend) {
			const startTick = bendAtBeginning ? noteStart : noteStart + duration - bendDuration;
			const ticksBetweenPoints = bendDuration / (bendValues.length - 1);
			for (let i = 0; i < bendValues.length - 1; i++) {
				const currentBendValue = MidiFileGenerator.getPitchWheel(bendValues[i]);
				const nextBendValue = MidiFileGenerator.getPitchWheel(bendValues[i + 1]);
				const tick = startTick + ticksBetweenPoints * i;
				this._generateBendValues(tick, ticksBetweenPoints, currentBendValue, nextBendValue, tempoOnBeatStart, addBend);
			}
		}
		_generateWhammy(beat, noteStart, noteDuration, channel, tempoOnBeatStart) {
			const bendPoints = beat.whammyBarPoints;
			const track = beat.voice.bar.staff.track;
			const duration = noteDuration.noteOnly;
			if (bendPoints[0].value > 0 && !beat.isContinuedWhammy) noteStart--;
			const addBend = (tick, value) => {
				this._handler.addBend(track.index, tick, channel, value);
			};
			let playedBendPoints = [];
			switch (beat.whammyBarType) {
				case WhammyType.Custom:
					playedBendPoints = bendPoints;
					break;
				case WhammyType.Dive:
					switch (beat.whammyStyle) {
						case BendStyle.Default:
							playedBendPoints = bendPoints;
							break;
						case BendStyle.Gradual:
							playedBendPoints.push(new BendPoint(0, bendPoints[0].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, bendPoints[1].value));
							break;
						case BendStyle.Fast:
							const whammyDuration = Math.min(duration, MidiUtils.millisToTicks(this._settings.player.songBookBendDuration, tempoOnBeatStart));
							this._generateSongBookWhammyOrBend(noteStart, duration, false, [bendPoints[0].value, bendPoints[1].value], whammyDuration, tempoOnBeatStart, addBend);
							return;
					}
					break;
				case WhammyType.Dip:
					switch (beat.whammyStyle) {
						case BendStyle.Default:
							playedBendPoints = bendPoints;
							break;
						case BendStyle.Gradual:
							playedBendPoints.push(new BendPoint(0, bendPoints[0].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition / 2 | 0, bendPoints[1].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, bendPoints[2].value));
							break;
						case BendStyle.Fast:
							const whammyDuration = Math.min(duration, MidiUtils.millisToTicks(this._settings.player.songBookDipDuration, tempoOnBeatStart));
							this._generateSongBookWhammyOrBend(noteStart, duration, true, [
								bendPoints[0].value,
								bendPoints[1].value,
								bendPoints[2].value
							], whammyDuration, tempoOnBeatStart, addBend);
							return;
					}
					break;
				case WhammyType.Hold:
					playedBendPoints = bendPoints;
					break;
				case WhammyType.Predive:
					playedBendPoints = bendPoints;
					break;
				case WhammyType.PrediveDive:
					switch (beat.whammyStyle) {
						case BendStyle.Default:
							playedBendPoints = bendPoints;
							break;
						case BendStyle.Gradual:
							playedBendPoints.push(new BendPoint(0, bendPoints[0].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition / 2 | 0, bendPoints[0].value));
							playedBendPoints.push(new BendPoint(BendPoint.MaxPosition, bendPoints[1].value));
							break;
						case BendStyle.Fast:
							const preDiveValue = MidiFileGenerator.getPitchWheel(bendPoints[0].value);
							this._handler.addBend(track.index, noteStart, channel, preDiveValue | 0);
							const whammyDuration = Math.min(duration, MidiUtils.millisToTicks(this._settings.player.songBookBendDuration, tempoOnBeatStart));
							this._generateSongBookWhammyOrBend(noteStart, duration, false, [bendPoints[0].value, bendPoints[1].value], whammyDuration, tempoOnBeatStart, addBend);
							return;
					}
					break;
			}
			this._generateWhammyOrBend(noteStart, duration, playedBendPoints, tempoOnBeatStart, addBend);
		}
		_generateWhammyOrBend(noteStart, duration, playedBendPoints, tempoOnBeatStart, addBend) {
			const ticksPerPosition = duration / BendPoint.MaxPosition;
			for (let i = 0; i < playedBendPoints.length - 1; i++) {
				const currentPoint = playedBendPoints[i];
				const nextPoint = playedBendPoints[i + 1];
				const currentBendValue = MidiFileGenerator.getPitchWheel(currentPoint.value);
				const nextBendValue = MidiFileGenerator.getPitchWheel(nextPoint.value);
				const ticksBetweenPoints = ticksPerPosition * (nextPoint.offset - currentPoint.offset);
				const tick = noteStart + ticksPerPosition * currentPoint.offset;
				this._generateBendValues(tick, ticksBetweenPoints, currentBendValue, nextBendValue, tempoOnBeatStart, addBend);
			}
		}
		_generateBendValues(currentTick, ticksBetweenPoints, currentBendValue, nextBendValue, tempoOnBeatStart, addBend) {
			const millisBetweenPoints = MidiUtils.ticksToMillis(ticksBetweenPoints, tempoOnBeatStart);
			const numberOfSemitones = Math.abs(nextBendValue - currentBendValue) / MidiFileGenerator._pitchValuePerSemitone;
			const numberOfSteps = Math.max(MidiFileGenerator._minBreakpointsPerSemitone * numberOfSemitones, millisBetweenPoints / MidiFileGenerator._millisecondsPerBreakpoint);
			const ticksPerBreakpoint = ticksBetweenPoints / numberOfSteps;
			const pitchPerBreakpoint = (nextBendValue - currentBendValue) / numberOfSteps;
			const endTick = currentTick + ticksBetweenPoints;
			for (let i = 0; i < numberOfSteps; i++) {
				addBend(currentTick | 0, Math.round(currentBendValue));
				currentBendValue += pitchPerBreakpoint;
				currentTick += ticksPerBreakpoint;
			}
			addBend(endTick | 0, nextBendValue);
		}
		_generateRasgueado(track, note, noteStart, noteKey, velocity, channel, rasgueadoInfo) {
			let tick = noteStart;
			for (let i = 0; i < rasgueadoInfo.durations.length; i++) {
				const brushInfo = rasgueadoInfo.brushInfos[i];
				const brushOffset = note.isStringed && note.string <= brushInfo.length ? brushInfo[note.string - 1] : 0;
				const duration = rasgueadoInfo.durations[i];
				this._handler.addNote(track.index, tick + brushOffset, duration - brushOffset, noteKey, velocity, channel);
				tick += duration;
			}
		}
		_generateTrill(note, noteStart, noteDuration, noteKey, dynamicValue, channel) {
			const track = note.beat.voice.bar.staff.track;
			const trillKey = note.stringTuning + note.trillFret;
			let trillLength = MidiUtils.toTicks(note.trillSpeed);
			let realKey = true;
			let tick = noteStart;
			const end = noteStart + noteDuration.untilTieOrSlideEnd;
			while (tick + 10 < end) {
				if (tick + trillLength >= end) trillLength = end - tick;
				this._handler.addNote(track.index, tick, trillLength, realKey ? noteKey : trillKey, dynamicValue, channel);
				realKey = !realKey;
				tick += trillLength;
			}
		}
		_generateTremoloPicking(note, noteStart, noteDuration, noteKey, dynamicValue, channel) {
			const track = note.beat.voice.bar.staff.track;
			if (note.beat.tremoloPicking.marks === 0) return;
			let tpLength = note.beat.tremoloPicking.getDurationAsTicks(note.beat.duration) * noteDuration.beatDurationFactor;
			let tick = noteStart;
			const end = noteStart + noteDuration.untilTieOrSlideEnd;
			while (tick + 10 < end) {
				if (tick + tpLength >= end) tpLength = end - tick;
				this._handler.addNote(track.index, tick, tpLength, noteKey, dynamicValue, channel);
				tick += tpLength;
			}
		}
		static _rasgueadoDirections = new Map([
			[Rasgueado.Ii, [BrushType.BrushDown, BrushType.BrushUp]],
			[Rasgueado.Mi, [BrushType.BrushDown, BrushType.BrushDown]],
			[Rasgueado.MiiTriplet, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushUp
			]],
			[Rasgueado.MiiAnapaest, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushUp
			]],
			[Rasgueado.PmpTriplet, [
				BrushType.BrushUp,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.PmpAnapaest, [
				BrushType.BrushUp,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.PeiTriplet, [
				BrushType.BrushUp,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.PeiAnapaest, [
				BrushType.BrushUp,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.PaiTriplet, [
				BrushType.BrushUp,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.PaiAnapaest, [
				BrushType.BrushUp,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.AmiTriplet, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.AmiAnapaest, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.Ppp, [
				BrushType.None,
				BrushType.BrushDown,
				BrushType.BrushUp
			]],
			[Rasgueado.Amii, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushUp
			]],
			[Rasgueado.Amip, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushUp
			]],
			[Rasgueado.Eami, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown
			]],
			[Rasgueado.Eamii, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushUp
			]],
			[Rasgueado.Peami, [
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushDown,
				BrushType.BrushUp
			]]
		]);
		static _rasgueadoDurations = new Map([
			[Rasgueado.Ii, [MidiUtils.toTicks(Duration.Eighth), MidiUtils.toTicks(Duration.Eighth)]],
			[Rasgueado.Mi, [MidiUtils.toTicks(Duration.Eighth), MidiUtils.toTicks(Duration.Eighth)]],
			[Rasgueado.MiiTriplet, [
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.MiiAnapaest, [
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Eighth)
			]],
			[Rasgueado.PmpTriplet, [
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.PmpAnapaest, [
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.PeiTriplet, [
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.PeiAnapaest, [
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Eighth)
			]],
			[Rasgueado.PaiTriplet, [
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.PaiAnapaest, [
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Eighth)
			]],
			[Rasgueado.AmiTriplet, [
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.AmiAnapaest, [
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.Ppp, [
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Eighth) / 3
			]],
			[Rasgueado.Amii, [
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Eighth)
			]],
			[Rasgueado.Amip, [
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Sixteenth) / 3,
				MidiUtils.toTicks(Duration.Eighth)
			]],
			[Rasgueado.Eami, [
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Sixteenth),
				MidiUtils.toTicks(Duration.Sixteenth)
			]],
			[Rasgueado.Eamii, [
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5
			]],
			[Rasgueado.Peami, [
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5,
				MidiUtils.toTicks(Duration.Sixteenth) / 5
			]]
		]);
		_getRasgueadoInfo(beat, beatDuration) {
			if (!beat.hasRasgueado) return null;
			const info = new RasgueadoInfo();
			const patternDuration = MidiFileGenerator._rasgueadoDurations.get(beat.rasgueado).reduce((p, v) => p + v, 0);
			info.durations = MidiFileGenerator._rasgueadoDurations.get(beat.rasgueado).map((v) => beatDuration * v / patternDuration);
			info.brushInfos = new Array(info.durations.length);
			const sixteenthBrush = MidiUtils.toTicks(Duration.Sixteenth);
			let stringUsed = 0;
			let stringCount = 0;
			for (const n of beat.notes) {
				if (n.isTieDestination) continue;
				stringUsed |= 1 << n.string - 1;
				stringCount++;
			}
			const rasgueadoDirections = MidiFileGenerator._rasgueadoDirections.get(beat.rasgueado);
			for (let i = 0; i < info.durations.length; i++) {
				const brushDuration = info.durations[i] * sixteenthBrush / MidiUtils.QuarterTime;
				const brushInfo = new Int32Array(beat.voice.bar.staff.tuning.length);
				info.brushInfos[i] = brushInfo;
				const brushType = rasgueadoDirections[i];
				if (brushType !== BrushType.None) this._fillBrushInfo(beat, brushInfo, brushType === BrushType.ArpeggioDown || brushType === BrushType.BrushDown, stringUsed, stringCount, brushDuration);
			}
			return info;
		}
		_getBrushInfo(beat) {
			const brushInfo = new Int32Array(beat.voice.bar.staff.tuning.length);
			if (beat.brushType) {
				let stringUsed = 0;
				let stringCount = 0;
				for (const n of beat.notes) {
					if (n.isTieDestination) continue;
					stringUsed |= 1 << n.string - 1;
					stringCount++;
				}
				this._fillBrushInfo(beat, brushInfo, beat.brushType === BrushType.ArpeggioDown || beat.brushType === BrushType.BrushDown, stringUsed, stringCount, beat.brushDuration);
			}
			return brushInfo;
		}
		_fillBrushInfo(beat, brushInfo, down, stringUsed, stringCount, brushDuration) {
			if (beat.notes.length > 0) {
				let brushMove = 0;
				const brushIncrement = brushDuration / (stringCount - 1) | 0;
				for (let i = 0; i < beat.voice.bar.staff.tuning.length; i++) {
					const index = down ? i : brushInfo.length - 1 - i;
					if ((stringUsed & 1 << index) !== 0) {
						brushInfo[index] = brushMove;
						brushMove += brushIncrement;
					}
				}
			}
			return brushInfo;
		}
		_generateNonTempoAutomation(beat, automation, startMove) {
			switch (automation.type) {
				case AutomationType.Instrument:
					this._addProgramChange(beat.voice.bar.staff.track, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.primaryChannel, (automation.value | 0) & 255);
					this._addProgramChange(beat.voice.bar.staff.track, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.secondaryChannel, (automation.value | 0) & 255);
					break;
				case AutomationType.Bank:
					this._addBankChange(beat.voice.bar.staff.track, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.primaryChannel, automation.value);
					this._addBankChange(beat.voice.bar.staff.track, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.secondaryChannel, automation.value);
					break;
				case AutomationType.Balance:
					const balance = MidiFileGenerator._toChannelShort(automation.value);
					this._handler.addControlChange(beat.voice.bar.staff.track.index, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.primaryChannel, ControllerType.PanCoarse, balance);
					this._handler.addControlChange(beat.voice.bar.staff.track.index, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.secondaryChannel, ControllerType.PanCoarse, balance);
					break;
				case AutomationType.Volume:
					const volume = MidiFileGenerator._toChannelShort(automation.value);
					this._handler.addControlChange(beat.voice.bar.staff.track.index, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.primaryChannel, ControllerType.VolumeCoarse, volume);
					this._handler.addControlChange(beat.voice.bar.staff.track.index, beat.playbackStart + startMove, beat.voice.bar.staff.track.playbackInfo.secondaryChannel, ControllerType.VolumeCoarse, volume);
					break;
			}
		}
		prepareSingleBeat(beat) {
			let tempo = -1;
			let program = -1;
			let currentBeat = beat;
			while (currentBeat && (tempo === -1 || program === -1)) {
				for (const automation of beat.automations) switch (automation.type) {
					case AutomationType.Instrument:
						program = automation.value;
						break;
					case AutomationType.Tempo:
						tempo = automation.value;
						break;
				}
				currentBeat = currentBeat.previousBeat;
			}
			const track = beat.voice.bar.staff.track;
			const masterBar = beat.voice.bar.masterBar;
			if (tempo === -1) tempo = masterBar.score.tempo;
			const positionRatio = beat.playbackStart / masterBar.calculateDuration();
			for (const automation of masterBar.tempoAutomations) if (automation.ratioPosition <= positionRatio) tempo = automation.value;
			else break;
			if (program === -1) program = track.playbackInfo.program;
			const volume = track.playbackInfo.volume;
			this._generateTrack(track);
			this._handler.addTimeSignature(0, masterBar.timeSignatureNumerator, masterBar.timeSignatureDenominator);
			this._handler.addTempo(0, tempo);
			const volumeCoarse = MidiFileGenerator._toChannelShort(volume);
			this._handler.addControlChange(0, 0, track.playbackInfo.primaryChannel, ControllerType.VolumeCoarse, volumeCoarse);
			this._handler.addControlChange(0, 0, track.playbackInfo.secondaryChannel, ControllerType.VolumeCoarse, volumeCoarse);
			return tempo;
		}
		generateSingleBeat(beat) {
			const tempo = this.prepareSingleBeat(beat);
			this._generateBeat(beat, -beat.playbackStart, beat.voice.bar, tempo);
		}
		generateSingleNote(note) {
			const tempo = this.prepareSingleBeat(note.beat);
			this._generateNote(note, 0, note.beat.playbackDuration, tempo, new Int32Array(note.beat.voice.bar.staff.tuning.length), null);
		}
	};
	//#endregion
	//#region src/CursorHandler.ts
	/**
	* A cursor handler which animates the beat cursor to the next beat or end of the beat bounds
	* depending on the cursor mode.
	* @internal
	*/
	var ToNextBeatAnimatingCursorHandler = class {
		onAttach(_cursors) {}
		onDetach(_cursors) {}
		placeBeatCursor(beatCursor, beatBounds, startBeatX) {
			const barBounds = beatBounds.barBounds.masterBarBounds.visualBounds;
			beatCursor.transitionToX(0, startBeatX);
			beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
		}
		placeBarCursor(barCursor, beatBounds) {
			const barBounds = beatBounds.barBounds.masterBarBounds.visualBounds;
			barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
		}
		transitionBeatCursor(beatCursor, _beatBounds, startBeatX, nextBeatX, duration, cursorMode) {
			const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
			nextBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
			duration = duration * factor;
			beatCursor.transitionToX(duration, nextBeatX);
		}
	};
	/**
	* A cursor handler which just places the bar and beat cursor without any animations applied.
	* @internal
	*/
	var NonAnimatingCursorHandler = class {
		onAttach(_cursors) {}
		onDetach(_cursors) {}
		placeBeatCursor(beatCursor, beatBounds, _startBeatX) {
			const barBounds = beatBounds.barBounds.masterBarBounds.visualBounds;
			beatCursor.transitionToX(0, beatBounds.onNotesX);
			beatCursor.setBounds(beatBounds.onNotesX, barBounds.y, 1, barBounds.h);
		}
		placeBarCursor(barCursor, beatBounds) {
			const barBounds = beatBounds.barBounds.masterBarBounds.visualBounds;
			barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
		}
		transitionBeatCursor(beatCursor, beatBounds, startBeatX, _nextBeatX, _duration, _cursorMode) {
			this.placeBeatCursor(beatCursor, beatBounds, startBeatX);
		}
	};
	//#endregion
	//#region src/rendering/BeatXPosition.ts
	/**
	* Lists the different position modes for {@link BarRendererBase.getBeatX}
	* @internal
	*/
	var BeatXPosition = /* @__PURE__ */ function(BeatXPosition) {
		/**
		* Gets the pre-notes position which is located before the accidentals
		*/
		BeatXPosition[BeatXPosition["PreNotes"] = 0] = "PreNotes";
		/**
		* Gets the on-notes position which is located after the accidentals but before the note heads.
		*/
		BeatXPosition[BeatXPosition["OnNotes"] = 1] = "OnNotes";
		/**
		* Gets the middle-notes position which is located after in the exact center of the note heads.
		*/
		BeatXPosition[BeatXPosition["MiddleNotes"] = 2] = "MiddleNotes";
		/**
		* Gets position of the stem for this beat
		*/
		BeatXPosition[BeatXPosition["Stem"] = 3] = "Stem";
		/**
		* Get the post-notes position which is located at after the note heads.
		*/
		BeatXPosition[BeatXPosition["PostNotes"] = 4] = "PostNotes";
		/**
		* Get the end-beat position which is located at the end of the beat. This position is almost
		* equal to the pre-notes position of the next beat.
		*/
		BeatXPosition[BeatXPosition["EndBeat"] = 5] = "EndBeat";
		return BeatXPosition;
	}({});
	//#endregion
	//#region src/rendering/glyphs/Glyph.ts
	/**
	* A glyph is a single symbol which can be added to a GlyphBarRenderer for automated
	* layouting and drawing of stacked symbols.
	* @internal
	*/
	var Glyph = class {
		x;
		y;
		width = 0;
		height = 0;
		renderer;
		constructor(x, y) {
			this.x = x;
			this.y = y;
		}
		getBoundingBoxTop() {
			return this.y;
		}
		getBoundingBoxBottom() {
			return this.getBoundingBoxTop() + this.height;
		}
		doLayout() {}
		paint(_cx, _cy, _canvas) {}
	};
	//#endregion
	//#region src/rendering/glyphs/BeatContainerGlyph.ts
	/**
	* @internal
	*/
	var BeatContainerGlyphBase = class extends Glyph {
		scaleToWidth(beatWidth) {
			this.width = beatWidth;
		}
	};
	/**
	* @internal
	*/
	var BeatContainerGlyph = class BeatContainerGlyph extends BeatContainerGlyphBase {
		_ties = [];
		_tieWidth = 0;
		beat;
		preNotes;
		onNotes;
		getLowestNoteY(requestedPosition) {
			return this.onNotes.getLowestNoteY(requestedPosition);
		}
		getHighestNoteY(requestedPosition) {
			return this.onNotes.getHighestNoteY(requestedPosition);
		}
		get beatId() {
			return this.beat.id;
		}
		get isLastOfVoice() {
			return this.beat.isLastOfVoice;
		}
		get displayDuration() {
			return this.beat.displayDuration;
		}
		get graceIndex() {
			return this.beat.graceIndex;
		}
		get graceType() {
			return this.beat.graceType;
		}
		get absoluteDisplayStart() {
			return this.beat.absoluteDisplayStart;
		}
		get graceGroup() {
			return this.beat.graceGroup;
		}
		get voiceIndex() {
			return this.beat.voice.index;
		}
		get isFirstOfTupletGroup() {
			return this.beat.hasTuplet && this.beat.tupletGroup.beats[0].id === this.beat.id;
		}
		get tupletGroup() {
			return this.beat.tupletGroup;
		}
		get onTimeX() {
			return this.onNotes.x + this.onNotes.onTimeX;
		}
		constructor(beat) {
			super(0, 0);
			this.beat = beat;
			this._ties = [];
		}
		getNoteY(note, requestedPosition) {
			return this.onNotes.y + this.onNotes.getNoteY(note, requestedPosition);
		}
		getRestY(requestedPosition) {
			return this.onNotes.y + this.onNotes.getRestY(requestedPosition);
		}
		getNoteX(note, requestedPosition) {
			return this.onNotes.x + this.onNotes.getNoteX(note, requestedPosition);
		}
		addTie(tie) {
			const tg = tie;
			tg.renderer = this.renderer;
			this._ties.push(tie);
			this.renderer.registerTie(tie);
		}
		getBoundingBoxTop() {
			let top = ModelUtils.minBoundingBox(this.preNotes.getBoundingBoxTop(), this.onNotes.getBoundingBoxTop());
			if (Number.isNaN(top)) top = this.renderer.middleYPosition;
			return top;
		}
		getBoundingBoxBottom() {
			let bottom = ModelUtils.maxBoundingBox(this.preNotes.getBoundingBoxBottom(), this.onNotes.getBoundingBoxBottom());
			if (Number.isNaN(bottom)) bottom = this.renderer.middleYPosition;
			return bottom;
		}
		drawBeamHelperAsFlags(helper) {
			return helper.hasFlag(false, void 0);
		}
		get postBeatStretch() {
			return this.onNotes.computedWidth + this._tieWidth - this.onNotes.onTimeX;
		}
		registerLayoutingInfo(layoutings) {
			const preBeatStretch = this.preNotes.computedWidth + this.onNotes.onTimeX;
			let postBeatStretch = this.postBeatStretch;
			for (const tie of this._ties) postBeatStretch += tie.width;
			layoutings.addBeatSpring(this, preBeatStretch, postBeatStretch);
			layoutings.setBeatSizes(this, {
				preBeatSize: this.preNotes.width,
				onBeatSize: this.onNotes.width
			});
		}
		applyLayoutingInfo(_info) {
			this.updateWidth();
		}
		doLayout() {
			this.preNotes.x = 0;
			this.preNotes.renderer = this.renderer;
			this.preNotes.container = this;
			this.preNotes.doLayout();
			this.onNotes.x = this.preNotes.x + this.preNotes.width;
			this.onNotes.renderer = this.renderer;
			this.onNotes.container = this;
			this.onNotes.doLayout();
			this.createBeatTies();
			this.updateWidth();
		}
		createBeatTies() {
			let i = this.beat.notes.length - 1;
			while (i >= 0) this.createTies(this.beat.notes[i--]);
		}
		doMultiVoiceLayout() {}
		updateWidth() {
			let width = this.preNotes.width + this.onNotes.width;
			let tieWidth = 0;
			for (const tie of this._ties) {
				const tg = tie;
				if (tg.width > tieWidth) tieWidth = tg.width;
			}
			this._tieWidth = tieWidth;
			width += tieWidth;
			this.width = width;
		}
		createTies(_n) {}
		static getGroupId(beat) {
			return `b${beat.id}`;
		}
		paint(cx, cy, canvas) {
			if (this.preNotes.isEmpty && this.onNotes.isEmpty && this._ties.length === 0) return;
			canvas.beginGroup(BeatContainerGlyph.getGroupId(this.beat));
			this.preNotes.paint(cx + this.x, cy + this.y, canvas);
			this.onNotes.paint(cx + this.x, cy + this.y, canvas);
			const staffX = cx - this.renderer.beatGlyphsStart - this.renderer.x;
			const staffY = cy - this.renderer.y;
			for (let i = 0, j = this._ties.length; i < j; i++) {
				const t = this._ties[i];
				t.renderer = this.renderer;
				t.paint(staffX, staffY, canvas);
			}
			canvas.endGroup();
		}
		buildBoundingsLookup(barBounds, cx, cy) {
			const beatBoundings = new BeatBounds();
			beatBoundings.beat = this.beat;
			if (this.beat.isEmpty) {
				beatBoundings.visualBounds = new Bounds();
				beatBoundings.visualBounds.x = cx + this.x;
				beatBoundings.visualBounds.y = barBounds.visualBounds.y;
				beatBoundings.visualBounds.w = this.width;
				beatBoundings.visualBounds.h = barBounds.visualBounds.h;
				beatBoundings.realBounds = new Bounds();
				beatBoundings.realBounds.x = cx + this.x;
				beatBoundings.realBounds.y = barBounds.realBounds.y;
				beatBoundings.realBounds.w = this.width;
				beatBoundings.realBounds.h = barBounds.realBounds.h;
				beatBoundings.onNotesX = cx + this.x + this.onNotes.x + this.onNotes.onTimeX;
			} else {
				beatBoundings.visualBounds = new Bounds();
				beatBoundings.visualBounds.x = cx + this.x;
				if (!this.preNotes.isEmpty) beatBoundings.visualBounds.x = cx + this.x + this.preNotes.x;
				else if (!this.onNotes.isEmpty) beatBoundings.visualBounds.x = cx + this.x + this.onNotes.x;
				else beatBoundings.visualBounds.x = cx + this.x;
				let visualEndX = 0;
				if (!this.onNotes.isEmpty) visualEndX = cx + this.x + this.onNotes.x + this.onNotes.onTimeX + this.postBeatStretch;
				else if (!this.preNotes.isEmpty) visualEndX = cx + this.x + this.preNotes.x + this.preNotes.width;
				else visualEndX = cx + this.x + this.width;
				beatBoundings.visualBounds.w = visualEndX - beatBoundings.visualBounds.x;
				beatBoundings.visualBounds.y = barBounds.visualBounds.y;
				beatBoundings.visualBounds.h = barBounds.visualBounds.h;
				beatBoundings.realBounds = new Bounds();
				beatBoundings.realBounds.x = cx + this.x;
				beatBoundings.realBounds.y = barBounds.realBounds.y;
				beatBoundings.realBounds.w = this.width;
				beatBoundings.realBounds.h = barBounds.realBounds.h;
				beatBoundings.onNotesX = cx + this.x + this.onNotes.x + this.onNotes.onTimeX;
			}
			barBounds.addBeat(beatBoundings);
			if (this.renderer.settings.core.includeNoteBounds) this.onNotes.buildBoundingsLookup(beatBoundings, cx + this.x, cy + this.y);
		}
		getBeatX(requestedPosition, useSharedSizes = false) {
			switch (requestedPosition) {
				case BeatXPosition.PreNotes: return this.preNotes.x;
				case BeatXPosition.OnNotes: return this.onNotes.x;
				case BeatXPosition.MiddleNotes: return this.onNotes.x + this.onNotes.middleX;
				case BeatXPosition.Stem: return this.onNotes.x + this.onNotes.stemX;
				case BeatXPosition.PostNotes:
					const onNoteSize = useSharedSizes ? this.renderer.layoutingInfo.getBeatSizes(this.beat)?.onBeatSize ?? this.onNotes.width : this.onNotes.width;
					return this.onNotes.x + onNoteSize;
				case BeatXPosition.EndBeat: return this.width;
			}
			return this.preNotes.x;
		}
	};
	//#endregion
	//#region src/rendering/ScoreRendererWrapper.ts
	/**
	* A {@link IScoreRenderer} implementation wrapping and underling other {@link IScoreRenderer}
	* allowing dynamic changing of the underlying instance without loosing aspects like the
	* event listeners.
	* @internal
	*/
	var ScoreRendererWrapper = class {
		_instance;
		_instanceEventUnregister;
		_settings;
		_width = 0;
		_score = null;
		_trackIndexes = null;
		get instance() {
			return this._instance;
		}
		set instance(value) {
			this._instance = value;
			const unregister = this._instanceEventUnregister;
			if (unregister) for (const e of unregister) e();
			if (value) {
				const newUnregister = [];
				newUnregister.push(value.preRender.on((v) => this.preRender.trigger(v)));
				newUnregister.push(value.renderFinished.on((v) => this.renderFinished.trigger(v)));
				newUnregister.push(value.partialRenderFinished.on((v) => this.partialRenderFinished.trigger(v)));
				newUnregister.push(value.partialLayoutFinished.on((v) => this.partialLayoutFinished.trigger(v)));
				newUnregister.push(value.postRenderFinished.on(() => this.postRenderFinished.trigger()));
				newUnregister.push(value.error.on((v) => this.error.trigger(v)));
				this._instanceEventUnregister = newUnregister;
				if (this._settings) value.updateSettings(this._settings);
				value.width = this._width;
				if (this._score !== null) value.renderScore(this._score, this._trackIndexes);
			} else this._instanceEventUnregister = void 0;
		}
		get boundsLookup() {
			return this._instance ? this._instance.boundsLookup : null;
		}
		get width() {
			return this._instance ? this._instance.width : 0;
		}
		set width(value) {
			this._width = value;
			if (this._instance) this._instance.width = value;
		}
		render(renderHints) {
			this._instance?.render(renderHints);
		}
		resizeRender() {
			this._instance?.resizeRender();
		}
		renderScore(score, trackIndexes, renderHints) {
			this._score = score;
			this._trackIndexes = trackIndexes;
			this._instance?.renderScore(score, trackIndexes, renderHints);
		}
		renderResult(resultId) {
			this._instance?.renderResult(resultId);
		}
		updateSettings(settings) {
			this._settings = settings;
			this._instance?.updateSettings(settings);
		}
		destroy() {
			this._instance?.destroy();
			this._instance = void 0;
		}
		preRender = new EventEmitterOfT();
		renderFinished = new EventEmitterOfT();
		partialRenderFinished = new EventEmitterOfT();
		partialLayoutFinished = new EventEmitterOfT();
		postRenderFinished = new EventEmitter();
		error = new EventEmitterOfT();
	};
	//#endregion
	//#region src/ResizeEventArgs.ts
	/**
	* Represents the information related to a resize event.
	* @public
	*/
	var ResizeEventArgs = class {
		/**
		* Gets the size before the resizing happened.
		*/
		oldWidth = 0;
		/**
		* Gets the size after the resize was complete.
		*/
		newWidth = 0;
		/**
		* Gets the settings currently used for rendering.
		*/
		settings = null;
	};
	//#endregion
	//#region src/ScrollHandlers.ts
	/**
	* Some basic scroll handler checking for changed offsets and scroll if changed.
	* @internal
	*/
	var BasicScrollHandler = class {
		api;
		lastScroll = -1;
		constructor(api) {
			this.api = api;
		}
		[Symbol.dispose]() {}
		forceScrollTo(currentBeatBounds) {
			this._scrollToBeat(currentBeatBounds, true);
			this.lastScroll = -1;
		}
		_scrollToBeat(currentBeatBounds, force) {
			const newLastScroll = this.calculateLastScroll(currentBeatBounds);
			if (newLastScroll === this.lastScroll && !force) return;
			this.lastScroll = newLastScroll;
			this.doScroll(currentBeatBounds);
		}
		onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, _actualBeatCursorTransitionDuration) {
			this._scrollToBeat(startBeat, false);
		}
	};
	/**
	* This is the default scroll handler for vertical layouts using {@link ScrollMode.Continuous}.
	* Whenever the system changes, we scroll to the new system position vertically.
	* @internal
	*/
	var VerticalContinuousScrollHandler = class extends BasicScrollHandler {
		calculateLastScroll(currentBeatBounds) {
			return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
		}
		doScroll(currentBeatBounds) {
			const ui = this.api.uiFacade;
			const settings = this.api.settings;
			const scroll = ui.getScrollContainer();
			const elementOffset = ui.getOffset(scroll, this.api.container);
			const y = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
			ui.scrollToY(scroll, elementOffset.y + y, this.api.settings.player.scrollSpeed);
		}
	};
	/**
	* This is the default scroll handler for vertical layouts using {@link ScrollMode.OffScreen}.
	* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
	* @internal
	*/
	var VerticalOffScreenScrollHandler = class extends BasicScrollHandler {
		calculateLastScroll(currentBeatBounds) {
			return currentBeatBounds.barBounds.masterBarBounds.realBounds.y;
		}
		doScroll(currentBeatBounds) {
			const ui = this.api.uiFacade;
			const settings = this.api.settings;
			const scroll = ui.getScrollContainer();
			const elementBottom = scroll.scrollTop + ui.getOffset(null, scroll).h;
			const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
			if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom || barBoundings.visualBounds.y < scroll.scrollTop) {
				const scrollTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
				ui.scrollToY(scroll, scrollTop, settings.player.scrollSpeed);
			}
		}
	};
	/**
	* This is the default scroll handler for vertical layouts using {@link ScrollMode.Smooth}.
	* vertical smooth scrolling aims to place the on-time position
	* at scrollOffsetY **at the time when a system starts**
	* this means when a system starts, it is at scrollOffsetY,
	* then gradually scrolls down the system height reaching the bottom
	* when the system completes.
	* @internal
	*/
	var VerticalSmoothScrollHandler = class {
		_api;
		_lastScroll = -1;
		_scrollContainerResizeUnregister;
		constructor(api) {
			this._api = api;
			this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
				const scrollContainer = api.uiFacade.getScrollContainer();
				const overflowNeeded = api.settings.player.scrollOffsetX;
				const overflowNeededAbsolute = scrollContainer.width + overflowNeeded;
				api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, true);
			});
		}
		[Symbol.dispose]() {
			this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, true);
			this._scrollContainerResizeUnregister();
		}
		forceScrollTo(currentBeatBounds) {
			const ui = this._api.uiFacade;
			const settings = this._api.settings;
			const scroll = ui.getScrollContainer();
			const systemTop = currentBeatBounds.barBounds.masterBarBounds.realBounds.y + settings.player.scrollOffsetY;
			ui.scrollToY(scroll, systemTop, 0);
			this._lastScroll = -1;
		}
		onBeatCursorUpdating(startBeat, _endBeat, _cursorMode, _actualBeatCursorStartX, _actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
			const ui = this._api.uiFacade;
			const settings = this._api.settings;
			const barBoundings = startBeat.barBounds.masterBarBounds;
			const systemTop = barBoundings.realBounds.y + settings.player.scrollOffsetY;
			if (systemTop === this._lastScroll && actualBeatCursorTransitionDuration > 0) return;
			const scroll = ui.getScrollContainer();
			ui.scrollToY(scroll, systemTop, 0);
			if (actualBeatCursorTransitionDuration === 0) {
				this._lastScroll = -1;
				return;
			}
			this._lastScroll = systemTop;
			const systemBottom = systemTop + barBoundings.realBounds.h;
			const systemDuration = this._calculateSystemDuration(barBoundings);
			ui.scrollToY(scroll, systemBottom, systemDuration);
		}
		_calculateSystemDuration(barBoundings) {
			const systemBars = barBoundings.staffSystemBounds.bars;
			const tickCache = this._api.tickCache;
			let duration = 0;
			const masterBars = this._api.score.masterBars;
			for (const bar of systemBars) {
				const mb = masterBars[bar.index];
				const mbInfo = tickCache.getMasterBar(mb);
				const tempoChanges = tickCache.getMasterBar(mb).tempoChanges;
				let tempo = tempoChanges[0].tempo;
				let tick = tempoChanges[0].tick;
				for (let i = 1; i < tempoChanges.length; i++) {
					const diff = tempoChanges[i].tick - tick;
					duration += MidiUtils.ticksToMillis(diff, tempo);
					tempo = tempoChanges[i].tempo;
					tick = tempoChanges[i].tick;
				}
				const toEnd = mbInfo.end - tick;
				duration += MidiUtils.ticksToMillis(toEnd, tempo);
			}
			return duration;
		}
	};
	/**
	* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Continuous}.
	* Whenever the master bar changes, we scroll to the position horizontally.
	* @internal
	*/
	var HorizontalContinuousScrollHandler = class extends BasicScrollHandler {
		calculateLastScroll(currentBeatBounds) {
			return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
		}
		doScroll(currentBeatBounds) {
			const ui = this.api.uiFacade;
			const settings = this.api.settings;
			const scroll = ui.getScrollContainer();
			const scrollLeftContinuous = currentBeatBounds.barBounds.masterBarBounds.realBounds.x + settings.player.scrollOffsetX;
			ui.scrollToX(scroll, scrollLeftContinuous, settings.player.scrollSpeed);
		}
	};
	/**
	* This is the default scroll handler for horizontal layouts using {@link ScrollMode.OffScreen}.
	* Whenever the system changes, we check if the new system bounds are out-of-screen and if yes, we scroll.
	* @internal
	*/
	var HorizontalOffScreenScrollHandler = class extends BasicScrollHandler {
		calculateLastScroll(currentBeatBounds) {
			return currentBeatBounds.barBounds.masterBarBounds.visualBounds.x;
		}
		doScroll(currentBeatBounds) {
			const ui = this.api.uiFacade;
			const settings = this.api.settings;
			const scroll = ui.getScrollContainer();
			const elementRight = scroll.scrollLeft + ui.getOffset(null, scroll).w;
			const barBoundings = currentBeatBounds.barBounds.masterBarBounds;
			if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight || barBoundings.visualBounds.x < scroll.scrollLeft) {
				const scrollLeftOffScreen = barBoundings.realBounds.x + settings.player.scrollOffsetX;
				ui.scrollToX(scroll, scrollLeftOffScreen, settings.player.scrollSpeed);
			}
		}
	};
	/**
	* This is the default scroll handler for horizontal layouts using {@link ScrollMode.Smooth}.
	* horiontal smooth scrolling aims to place the on-time position
	* at scrollOffsetX from a beat-to-beat perspective.
	* This achieves an steady cursor at the same position with rather the music sheet scrolling past it.
	* Due to some animation inconsistencies (e.g. CSS animation vs scrolling) there might be a slight
	* flickering of the cursor.
	*
	* To get a fully steady cursor the beat cursor can simply be visually hidden and a cursor can be placed at
	* `scrollOffsetX` by the integrator.
	* @internal
	*/
	var HorizontalSmoothScrollHandler = class {
		_api;
		_lastScroll = -1;
		_scrollContainerResizeUnregister;
		constructor(api) {
			this._api = api;
			this._scrollContainerResizeUnregister = api.uiFacade.getScrollContainer().resize.on(() => {
				const scrollContainer = api.uiFacade.getScrollContainer();
				const overflowNeeded = api.settings.player.scrollOffsetX;
				const overflowNeededAbsolute = scrollContainer.width + overflowNeeded;
				api.uiFacade.setCanvasOverflow(api.canvasElement, overflowNeededAbsolute, false);
			});
		}
		[Symbol.dispose]() {
			this._scrollContainerResizeUnregister();
			this._api.uiFacade.setCanvasOverflow(this._api.canvasElement, 0, false);
		}
		forceScrollTo(currentBeatBounds) {
			const ui = this._api.uiFacade;
			const settings = this._api.settings;
			const scroll = ui.getScrollContainer();
			const barStartX = currentBeatBounds.onNotesX + settings.player.scrollOffsetY;
			ui.scrollToY(scroll, barStartX, 0);
			this._lastScroll = -1;
		}
		onBeatCursorUpdating(_startBeat, _endBeat, _cursorMode, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
			const ui = this._api.uiFacade;
			if (actualBeatCursorEndX === this._lastScroll && actualBeatCursorTransitionDuration > 0) return;
			const settings = this._api.settings;
			const scroll = ui.getScrollContainer();
			ui.scrollToX(scroll, actualBeatCursorStartX + settings.player.scrollOffsetX, 0);
			if (actualBeatCursorTransitionDuration === 0) {
				this._lastScroll = -1;
				return;
			}
			this._lastScroll = actualBeatCursorEndX;
			const scrollX = actualBeatCursorEndX + settings.player.scrollOffsetX;
			ui.scrollToX(scroll, scrollX, actualBeatCursorTransitionDuration);
		}
	};
	//#endregion
	//#region src/synth/ActiveBeatsChangedEventArgs.ts
	/**
	* Represents the information related to the beats actively being played now.
	* @public
	*/
	var ActiveBeatsChangedEventArgs = class {
		/**
		* The currently active beats across all tracks and voices.
		*/
		activeBeats;
		constructor(activeBeats) {
			this.activeBeats = activeBeats;
		}
	};
	//#endregion
	//#region src/synth/AlphaSynthWrapper.ts
	/**
	* A {@link IAlphaSynth} implementation wrapping and underling other {@link IAlphaSynth}
	* allowing dynamic changing of the underlying instance without loosing aspects like the
	* main playback information and event listeners.
	*
	* @remarks
	* This wrapper is used when re-exposing the underlying player via {@link AlphaTabApiBase} to integrators.
	* Even with dynamic switching between synthesizer, backing tracks etc. aspects like volume, playbackspeed,
	* event listeners etc. should not be lost.
	*
	* @internal
	*/
	var AlphaSynthWrapper = class {
		_masterVolume = 1;
		_metronomeVolume = 0;
		_countInVolume = 0;
		_playbackSpeed = 1;
		_isLooping = false;
		_midiEventsPlayedFilter = [];
		_instance;
		_instanceEventUnregister;
		midiTickShift = 0;
		constructor() {
			this.ready = new EventEmitter(() => this.isReady);
			this.readyForPlayback = new EventEmitter(() => this.isReadyForPlayback);
			this.midiLoaded = new EventEmitterOfT(() => {
				return this._instance?.loadedMidiInfo ?? null;
			});
			this.stateChanged = new EventEmitterOfT(() => {
				return new PlayerStateChangedEventArgs(this.state, false);
			});
			this.positionChanged = new EventEmitterOfT(() => {
				return this.currentPosition;
			});
			this.playbackRangeChanged = new EventEmitterOfT(() => {
				const range = this.playbackRange;
				if (range) return new PlaybackRangeChangedEventArgs(range);
				return null;
			});
		}
		get instance() {
			return this._instance;
		}
		set instance(value) {
			this._instance = value;
			const unregister = this._instanceEventUnregister;
			if (unregister) for (const e of unregister) e();
			if (value) {
				const newUnregister = [];
				newUnregister.push(value.ready.on(() => this.ready.trigger()));
				newUnregister.push(value.readyForPlayback.on(() => this.readyForPlayback.trigger()));
				newUnregister.push(value.finished.on(() => this.finished.trigger()));
				newUnregister.push(value.soundFontLoaded.on(() => this.soundFontLoaded.trigger()));
				newUnregister.push(value.soundFontLoadFailed.on((e) => this.soundFontLoadFailed.trigger(e)));
				newUnregister.push(value.midiLoaded.on((e) => {
					this.midiLoaded.trigger(this._shiftPositionChangedEventArgsToApi(e));
				}));
				newUnregister.push(value.midiLoadFailed.on((e) => this.midiLoadFailed.trigger(e)));
				newUnregister.push(value.stateChanged.on((e) => this.stateChanged.trigger(e)));
				newUnregister.push(value.positionChanged.on((e) => {
					this.positionChanged.trigger(this._shiftPositionChangedEventArgsToApi(e));
				}));
				newUnregister.push(value.midiEventsPlayed.on((e) => this.midiEventsPlayed.trigger(e)));
				newUnregister.push(value.playbackRangeChanged.on((e) => this.playbackRangeChanged.trigger(this._shiftPlaybackRangeChangedEventArgsToApi(e))));
				this._instanceEventUnregister = newUnregister;
				if (this.isReady) {
					value.masterVolume = this._masterVolume;
					value.metronomeVolume = this._metronomeVolume;
					value.countInVolume = this._countInVolume;
					value.playbackSpeed = this._playbackSpeed;
					value.isLooping = this._isLooping;
					value.midiEventsPlayedFilter = this._midiEventsPlayedFilter;
					this.ready.trigger();
				} else newUnregister.push(value.ready.on(() => {
					value.masterVolume = this._masterVolume;
					value.metronomeVolume = this._metronomeVolume;
					value.countInVolume = this._countInVolume;
					value.playbackSpeed = this._playbackSpeed;
					value.isLooping = this._isLooping;
					value.midiEventsPlayedFilter = this._midiEventsPlayedFilter;
				}));
			} else this._instanceEventUnregister = void 0;
		}
		get output() {
			return this._instance.output;
		}
		get isReady() {
			return this._instance ? this._instance.isReady : false;
		}
		get isReadyForPlayback() {
			return this._instance ? this._instance.isReadyForPlayback : false;
		}
		get state() {
			return this._instance ? this._instance.state : PlayerState.Paused;
		}
		get logLevel() {
			return Logger.logLevel;
		}
		set logLevel(value) {
			Logger.logLevel = value;
			if (this._instance) this._instance.logLevel = value;
		}
		get masterVolume() {
			return this._masterVolume;
		}
		set masterVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this._masterVolume = value;
			if (this._instance) this._instance.masterVolume = value;
		}
		get metronomeVolume() {
			return this._metronomeVolume;
		}
		set metronomeVolume(value) {
			value = Math.max(value, SynthConstants.MinVolume);
			this._metronomeVolume = value;
			if (this._instance) this._instance.metronomeVolume = value;
		}
		get playbackSpeed() {
			return this._playbackSpeed;
		}
		set playbackSpeed(value) {
			this._playbackSpeed = value;
			if (this._instance) this._instance.playbackSpeed = value;
		}
		get loadedMidiInfo() {
			return this._instance ? this._shiftPositionChangedEventArgsToApi(this._instance.loadedMidiInfo) : void 0;
		}
		get currentPosition() {
			return this._instance ? this._shiftPositionChangedEventArgsToApi(this._instance.currentPosition) : new PositionChangedEventArgs(0, 0, 0, 0, false, 120, 120);
		}
		get tickPosition() {
			return this._instance ? this._shiftTickToApi(this._instance.tickPosition) : 0;
		}
		set tickPosition(value) {
			if (this._instance) this._instance.tickPosition = this._shiftTickToPlayer(value);
		}
		get timePosition() {
			return this._instance ? this._instance.timePosition : 0;
		}
		set timePosition(value) {
			if (this._instance) this._instance.timePosition = value;
		}
		get playbackRange() {
			return this._instance ? this._shiftPlaybackRangeToApi(this._instance.playbackRange) : null;
		}
		set playbackRange(value) {
			if (this._instance) this._instance.playbackRange = this._shiftPlaybackRangeToPlayer(value);
		}
		get isLooping() {
			return this._isLooping;
		}
		set isLooping(value) {
			this._isLooping = value;
			if (this._instance) this._instance.isLooping = value;
		}
		get countInVolume() {
			return this._countInVolume;
		}
		set countInVolume(value) {
			this._countInVolume = value;
			if (this._instance) this._instance.countInVolume = value;
		}
		get midiEventsPlayedFilter() {
			return this._midiEventsPlayedFilter;
		}
		set midiEventsPlayedFilter(value) {
			this._midiEventsPlayedFilter = value;
			if (this._instance) this._instance.midiEventsPlayedFilter = value;
		}
		destroy() {
			if (this._instance) {
				this._instance.destroy();
				this._instance = void 0;
			}
		}
		play() {
			return this._instance ? this._instance.play() : false;
		}
		pause() {
			if (this._instance) this._instance.pause();
		}
		playPause() {
			if (this._instance) this._instance.playPause();
		}
		stop() {
			if (this._instance) this._instance.stop();
		}
		playOneTimeMidiFile(midi) {
			if (this._instance) this._instance.playOneTimeMidiFile(midi);
		}
		loadSoundFont(data, append) {
			if (this._instance) this._instance.loadSoundFont(data, append);
		}
		resetSoundFonts() {
			if (this._instance) this._instance.resetSoundFonts();
		}
		loadMidiFile(midi) {
			if (this._instance) this._instance.loadMidiFile(midi);
		}
		loadBackingTrack(score) {
			if (this._instance) this._instance.loadBackingTrack(score);
		}
		updateSyncPoints(syncPoints) {
			if (this._instance) this._instance.updateSyncPoints(syncPoints);
		}
		applyTranspositionPitches(transpositionPitches) {
			if (this._instance) this._instance.applyTranspositionPitches(transpositionPitches);
		}
		setChannelTranspositionPitch(channel, semitones) {
			if (this._instance) this._instance.setChannelTranspositionPitch(channel, semitones);
		}
		setChannelMute(channel, mute) {
			if (this._instance) this._instance.setChannelMute(channel, mute);
		}
		resetChannelStates() {
			if (this._instance) this._instance.resetChannelStates();
		}
		setChannelSolo(channel, solo) {
			if (this._instance) this._instance.setChannelSolo(channel, solo);
		}
		setChannelVolume(channel, volume) {
			if (this._instance) this._instance.setChannelVolume(channel, volume);
		}
		ready;
		readyForPlayback;
		finished = new EventEmitter();
		soundFontLoaded = new EventEmitter();
		soundFontLoadFailed = new EventEmitterOfT();
		midiLoaded;
		midiLoadFailed = new EventEmitterOfT();
		stateChanged;
		positionChanged;
		midiEventsPlayed = new EventEmitterOfT();
		playbackRangeChanged;
		_shiftPlaybackRangeChangedEventArgsToApi(e) {
			if (e.playbackRange == null) return e;
			if (this.midiTickShift > 0) return new PlaybackRangeChangedEventArgs(this._shiftPlaybackRangeToApi(e.playbackRange));
			else return e;
		}
		_shiftPlaybackRangeToApi(e) {
			if (e == null) return e;
			const tickShift = this.midiTickShift;
			if (tickShift > 0) {
				const range = new PlaybackRange();
				range.startTick = e.startTick - tickShift;
				range.endTick = e.endTick - tickShift;
				return range;
			} else return e;
		}
		_shiftPlaybackRangeToPlayer(e) {
			if (e == null) return e;
			const tickShift = this.midiTickShift;
			if (tickShift > 0) {
				const range = new PlaybackRange();
				range.startTick = e.startTick + tickShift;
				range.endTick = e.endTick + tickShift;
				return range;
			} else return e;
		}
		_shiftPositionChangedEventArgsToApi(e) {
			if (!e) return e;
			const tickShift = this.midiTickShift;
			return tickShift > 0 ? new PositionChangedEventArgs(e.currentTime, e.endTime, e.currentTick - tickShift, e.endTick - tickShift, e.isSeek, e.originalTempo, e.modifiedTempo) : e;
		}
		_shiftTickToApi(tickPosition) {
			return tickPosition - this.midiTickShift;
		}
		_shiftTickToPlayer(tickPosition) {
			return tickPosition + this.midiTickShift;
		}
	};
	//#endregion
	//#region src/synth/ExternalMediaPlayer.ts
	/**
	* @internal
	*/
	var ExternalMediaSynthOutput = class {
		sampleRate = 44100;
		_seekPosition = 0;
		_handler;
		get handler() {
			return this._handler;
		}
		set handler(value) {
			if (value) {
				if (this._seekPosition !== 0) {
					value.seekTo(this._seekPosition);
					this._seekPosition = 0;
				}
			}
			this._handler = value;
		}
		get backingTrackDuration() {
			return this.handler?.backingTrackDuration ?? 0;
		}
		get playbackRate() {
			return this.handler?.playbackRate ?? 1;
		}
		set playbackRate(value) {
			const handler = this.handler;
			if (handler) handler.playbackRate = value;
		}
		get masterVolume() {
			return this.handler?.masterVolume ?? 1;
		}
		set masterVolume(value) {
			const handler = this.handler;
			if (handler) handler.masterVolume = value;
		}
		seekTo(time) {
			const handler = this.handler;
			if (handler) handler.seekTo(time);
			else this._seekPosition = time;
		}
		loadBackingTrack(_backingTrack) {}
		open(_bufferTimeInMilliseconds) {
			this.ready.trigger();
		}
		updatePosition(currentTime) {
			this.timeUpdate.trigger(currentTime);
		}
		play() {
			this.handler?.play();
		}
		destroy() {}
		pause() {
			this.handler?.pause();
		}
		addSamples(_samples) {}
		resetSamples() {}
		activate() {}
		ready = new EventEmitter();
		samplesPlayed = new EventEmitterOfT();
		timeUpdate = new EventEmitterOfT();
		sampleRequest = new EventEmitter();
		async enumerateOutputDevices() {
			return [];
		}
		async setOutputDevice(_device) {}
		async getOutputDevice() {
			return null;
		}
	};
	/**
	* @internal
	*/
	var ExternalMediaPlayer = class extends BackingTrackPlayer {
		get handler() {
			return this.output.handler;
		}
		set handler(value) {
			this.output.handler = value;
		}
		constructor(bufferTimeInMilliseconds) {
			super(new ExternalMediaSynthOutput(), bufferTimeInMilliseconds);
		}
	};
	//#endregion
	//#region src/AlphaTabApiBase.ts
	/**
	* @internal
	*/
	var BoundsLookupVisibilityChecker = class {
		bounds = null;
		isVisible(beat) {
			const bounds = this.bounds;
			if (!bounds) return false;
			return bounds.findBeat(beat) !== null;
		}
	};
	/**
	* This class represents the public API of alphaTab and provides all logic to display
	* a music sheet in any UI using the given {@link IUiFacade}
	* @param <TSettings> The UI object holding the settings.
	* @public
	*/
	var AlphaTabApiBase = class {
		_startTime = 0;
		_trackIndexes = null;
		_trackIndexLookup = null;
		_beatVisibilityChecker = new BoundsLookupVisibilityChecker();
		_isDestroyed = false;
		_score = null;
		_tracks = [];
		_actualPlayerMode = PlayerMode.Disabled;
		_player;
		_renderer;
		_defaultScrollHandler;
		_defaultCursorHandler;
		_customCursorHandler;
		/**
		* An indicator by how many midi-ticks the song contents are shifted.
		* Grace beats at start might require a shift for the first beat to start at 0.
		* This information can be used to translate back the player time axis to the music notation.
		*/
		get midiTickShift() {
			return this._player.midiTickShift;
		}
		/**
		* The actual player mode which is currently active.
		* @remarks
		* Allows determining whether a backing track or the synthesizer is active in case automatic detection is enabled.
		* @category Properties - Player
		* @since 1.6.0
		*/
		get actualPlayerMode() {
			return this._actualPlayerMode;
		}
		/**
		* The UI facade used for interacting with the user interface (like the browser).
		* @remarks
		* The implementation depends on the platform alphaTab is running in (e.g. the web version in the browser, WPF in .net etc.)
		* @category Properties - Core
		* @since 0.9.4
		*/
		uiFacade;
		/**
		* The UI container that holds the whole alphaTab control.
		* @remarks
		* Gets the UI container that represents the element on which alphaTab was initialized. Note that this is not the raw instance, but a UI framework specific wrapper for alphaTab.
		* @category Properties - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* const container = api.container;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* var container = api.Container;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* val container = api.container;
		* ```
		*/
		container;
		/**
		* The score renderer used for rendering the music sheet.
		* @remarks
		* This is the low-level API responsible for the actual rendering engine.
		* Gets access to the underling {@link IScoreRenderer} that is used for the rendering.
		*
		* @category Properties - Core
		* @since 0.9.4
		*/
		get renderer() {
			return this._renderer;
		}
		/**
		* The score holding all information about the song being rendered
		* @category Properties - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* updateScoreInfo(api.score);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* UpdateScoreInfo(api.Score);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* updateScoreInfo(api.score)
		* ```
		*/
		get score() {
			return this._score;
		}
		/**
		* The settings that are used for rendering the music notation.
		* @remarks
		* Gets access to the underling {@link Settings} object that is currently used by alphaTab.
		*
		* @category Properties - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* showSettingsModal(api.settings);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* ShowSettingsDialog(api.Settings);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* showSettingsDialog(api.settings)
		* ```
		*/
		settings;
		/**
		* The list of the tracks that are currently rendered.
		*
		* @category Properties - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* highlightCurrentTracksInTrackSelector(api.tracks);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* HighlightCurrentTracksInTrackSelector(api.Tracks);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* highlightCurrentTracksInTrackSelector(api.tracks)
		* ```
		*/
		get tracks() {
			return this._tracks;
		}
		/**
		* The UI container that will hold all rendered results.
		* @since 0.9.4
		* @category Properties - Core
		*/
		canvasElement;
		/**
		* Initializes a new instance of the {@link AlphaTabApiBase} class.
		* @param uiFacade The UI facade to use for interacting with the user interface.
		* @param settings The UI settings object to use for loading the settings.
		*/
		constructor(uiFacade, settings) {
			this.uiFacade = uiFacade;
			this.container = uiFacade.rootContainer;
			this.activeBeatsChanged = new EventEmitterOfT(() => {
				const currentBeat = this._currentBeat;
				if (this._player.state === PlayerState.Playing && currentBeat) return new ActiveBeatsChangedEventArgs(currentBeat.beatLookup.highlightedBeats.map((h) => h.beat));
				return null;
			});
			this.playedBeatChanged = new EventEmitterOfT(() => {
				const currentBeat = this._currentBeat;
				if (this._player.state === PlayerState.Playing && currentBeat) return currentBeat.beat;
				return null;
			});
			this.scoreLoaded = new EventEmitterOfT(() => {
				if (this._score) return this._score;
				return null;
			});
			this.midiLoaded = new EventEmitterOfT(() => {
				return this._player.loadedMidiInfo ?? null;
			});
			uiFacade.initialize(this, settings);
			Logger.logLevel = this.settings.core.logLevel;
			this.settings.handleBackwardsCompatibility();
			Environment.printEnvironmentInfo(false);
			this.canvasElement = uiFacade.createCanvasElement();
			this.container.appendChild(this.canvasElement);
			this._renderer = new ScoreRendererWrapper();
			if (this.settings.core.useWorkers && this.uiFacade.areWorkersSupported && Environment.getRenderEngineFactory(this.settings.core.engine).supportsWorkers) this._renderer.instance = this.uiFacade.createWorkerRenderer();
			else this._renderer.instance = new ScoreRenderer(this.settings);
			this.container.resize.on(this.uiFacade.throttle(() => {
				if (this._isDestroyed) return;
				if (this.container.width !== this._renderer.width) this.triggerResize();
			}, uiFacade.resizeThrottle));
			const initialResizeEventInfo = new ResizeEventArgs();
			initialResizeEventInfo.oldWidth = this._renderer.width;
			initialResizeEventInfo.newWidth = this.container.width | 0;
			initialResizeEventInfo.settings = this.settings;
			this._onResize(initialResizeEventInfo);
			this._renderer.preRender.on(this._onRenderStarted.bind(this));
			this._renderer.renderFinished.on((renderingResult) => {
				this._onRenderFinished(renderingResult);
			});
			this._renderer.postRenderFinished.on(() => {
				const duration = Date.now() - this._startTime;
				Logger.debug("rendering", `Rendering completed in ${duration}ms`);
				this._onPostRenderFinished();
			});
			this._renderer.preRender.on((_) => {
				this._startTime = Date.now();
			});
			this._renderer.partialLayoutFinished.on((r) => this._appendRenderResult(r, false));
			this._renderer.partialRenderFinished.on(this._updateRenderResult.bind(this));
			this._renderer.renderFinished.on((r) => {
				this._appendRenderResult(r, true);
			});
			this._renderer.error.on(this.onError.bind(this));
			this._setupPlayerWrapper();
			if (this.settings.player.playerMode !== PlayerMode.Disabled) this._setupOrDestroyPlayer();
			this._setupClickHandling();
			this.uiFacade.beginInvoke(() => {
				this.uiFacade.initialRender();
			});
		}
		_setupPlayerWrapper() {
			const player = new AlphaSynthWrapper();
			this._player = player;
			player.ready.on(() => {
				this.loadMidiForScore();
			});
			player.readyForPlayback.on(() => {
				this._onPlayerReady();
				if (this.tracks) for (const track of this.tracks) {
					const volume = track.playbackInfo.volume / 16;
					player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
					player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
				}
			});
			player.soundFontLoaded.on(this._onSoundFontLoaded.bind(this));
			player.soundFontLoadFailed.on((e) => {
				this.onError(e);
			});
			player.midiLoaded.on(this._onMidiLoaded.bind(this));
			player.midiLoadFailed.on((e) => {
				this.onError(e);
			});
			player.stateChanged.on(this._onPlayerStateChanged.bind(this));
			player.positionChanged.on(this._onPlayerPositionChanged.bind(this));
			player.midiEventsPlayed.on(this._onMidiEventsPlayed.bind(this));
			player.playbackRangeChanged.on(this._onPlaybackRangeChanged.bind(this));
			player.finished.on(this._onPlayerFinished.bind(this));
		}
		/**
		* Destroys the alphaTab control and restores the initial state of the UI.
		* @remarks
		* This function destroys the alphaTab control and tries to restore the initial state of the UI. This might be useful if
		* our website is quite dynamic and you need to uninitialize alphaTab from an element again. After destroying alphaTab
		* it cannot be used anymore. Any further usage leads to unexpected behavior.
		*
		* @category Methods - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.destroy();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Destroy();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.destroy()
		* ```
		*/
		destroy() {
			this._isDestroyed = true;
			this._player.destroy();
			this.uiFacade.destroy();
			this._renderer.destroy();
		}
		/**
		* Applies any changes that were done to the settings object.
		* @remarks
		* It also informs the {@link renderer} about any new values to consider.
		* By default alphaTab will not trigger any re-rendering or settings update just if the settings object itself was changed. This method must be called
		* to trigger an update of the settings in all components. Then a re-rendering can be initiated using the {@link render} method.
		*
		* @category Methods - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.settings.display.scale = 2.0;
		* api.updateSettings();
		* api.render();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		*
		* api.Settings.Display.Scale = 2.0;
		* api.UpdateSettings();
		* api.Render()
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		*
		* api.settings.display.scale = 2.0
		* api.updateSettings()
		* api.render()
		* ```
		*/
		updateSettings() {
			this.settings.handleBackwardsCompatibility();
			const score = this.score;
			if (score) ModelUtils.applyPitchOffsets(this.settings, score);
			this._updateRenderer();
			this._renderer.updateSettings(this.settings);
			this._setupOrDestroyPlayer();
			this._onSettingsUpdated();
		}
		_updateRenderer() {
			const renderer = this._renderer;
			if (this.settings.core.useWorkers && this.uiFacade.areWorkersSupported && Environment.getRenderEngineFactory(this.settings.core.engine).supportsWorkers) {
				if (renderer.instance instanceof ScoreRenderer) {
					renderer.destroy();
					renderer.instance = this.uiFacade.createWorkerRenderer();
				}
			} else if (!(renderer.instance instanceof ScoreRenderer)) {
				renderer.destroy();
				renderer.instance = new ScoreRenderer(this.settings);
			}
		}
		/**
		* Initiates a load of the score using the given data.
		* @returns true if the data object is supported and a load was initiated, otherwise false
		* @param scoreData The data container supported by {@link IUiFacade}.  The supported types is depending on the platform:
		*
		* * A `alphaTab.model.Score` instance (all platforms)
		* * A `ArrayBuffer` or `Uint8Array` containing one of the supported file formats (all platforms, native byte array or input streams on other platforms)
		* * A url from where to download the binary data of one of the supported file formats (browser only)
		*
		* @param trackIndexes The indexes of the tracks from the song that should be rendered. If not provided, the first track of the
		* song will be shown.
		* @category Methods - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.load('/assets/MyFile.gp');
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Load(System.IO.File.OpenRead("MyFile.gp"));
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* contentResolver.openInputStream(uri).use {
		*     api.load(it)
		* }
		* ```
		*/
		load(scoreData, trackIndexes) {
			try {
				return this.uiFacade.load(scoreData, (score) => {
					this.renderScore(score, trackIndexes);
				}, (error) => {
					this.onError(error);
				});
			} catch (e) {
				this.onError(e);
				return false;
			}
		}
		/**
		* Initiates a rendering of the given score.
		* @param score The score containing the tracks to be rendered.
		* @param trackIndexes The indexes of the tracks from the song that should be rendered. If not provided, the first track of the
		* song will be shown.
		* @param renderHints Additional hints to respect during layouting and rendering.
		*
		* @category Methods - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.RenderScore(generateScore(),[ 2, 3 ]);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.RenderScore(GenerateScore(), new double[] { 2, 3 });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.renderScore(generateScore(), alphaTab.collections.DoubleList(2, 3));
		* ```
		*/
		renderScore(score, trackIndexes, renderHints) {
			const tracks = [];
			if (!trackIndexes) {
				if (score.tracks.length > 0) tracks.push(score.tracks[0]);
			} else if (trackIndexes.length === 0) {
				if (score.tracks.length > 0) tracks.push(score.tracks[0]);
			} else if (trackIndexes.length === 1 && trackIndexes[0] === -1) for (const track of score.tracks) tracks.push(track);
			else for (const index of trackIndexes) if (index >= 0 && index <= score.tracks.length) tracks.push(score.tracks[index]);
			this._internalRenderTracks(score, tracks, renderHints);
		}
		/**
		* Renders the given list of tracks.
		* @param tracks The tracks to render. They must all belong to the same score.
		* @param renderHints Additional hints to respect during layouting and rendering.
		*
		* @category Methods - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.renderTracks([api.score.tracks[0], api.score.tracks[1]]);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.RenderTracks(new []{
		*     api.Score.Tracks[2],
		*     api.Score.Tracks[3]
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.renderTracks(alphaTab.collections.List(
		*     api.score.tracks[2],
		*     api.score.tracks[3]
		* }
		* ```
		*/
		renderTracks(tracks, renderHints) {
			if (tracks.length > 0) {
				const score = tracks[0].score;
				for (const track of tracks) if (track.score !== score) {
					this.onError(new AlphaTabError(AlphaTabErrorType.General, "All rendered tracks must belong to the same score."));
					return;
				}
				this._internalRenderTracks(score, tracks, renderHints);
			}
		}
		_internalRenderTracks(score, tracks, renderHints) {
			ModelUtils.applyPitchOffsets(this.settings, score);
			if (score !== this.score) {
				this._score = score;
				this._tracks = tracks;
				this._tickCache = null;
				this._trackIndexes = [];
				for (const track of tracks) this._trackIndexes.push(track.index);
				this._trackIndexLookup = new Set(this._trackIndexes);
				this._onScoreLoaded(score);
				this.loadMidiForScore();
				this.render(renderHints);
			} else {
				this._tracks = tracks;
				const startIndex = ModelUtils.computeFirstDisplayedBarIndex(score, this.settings);
				const endIndex = ModelUtils.computeLastDisplayedBarIndex(score, this.settings, startIndex);
				if (this._tickCache) this._tickCache.multiBarRestInfo = ModelUtils.buildMultiBarRestInfo(this.tracks, startIndex, endIndex);
				this._trackIndexes = [];
				for (const track of tracks) this._trackIndexes.push(track.index);
				this._trackIndexLookup = new Set(this._trackIndexes);
				this.render(renderHints);
			}
		}
		/**
		* @internal
		*/
		triggerResize() {
			if (!this.container.isVisible) {
				Logger.warning("Rendering", "AlphaTab container was invisible while autosizing, waiting for element to become visible", null);
				this.uiFacade.rootContainerBecameVisible.on(() => {
					Logger.debug("Rendering", "AlphaTab container became visible, doing autosizing", null);
					this.triggerResize();
				});
			} else {
				const resizeEventInfo = new ResizeEventArgs();
				resizeEventInfo.oldWidth = this._renderer.width;
				resizeEventInfo.newWidth = this.container.width;
				resizeEventInfo.settings = this.settings;
				this._onResize(resizeEventInfo);
				this._renderer.updateSettings(this.settings);
				this._renderer.width = this.container.width;
				this._renderer.resizeRender();
			}
		}
		_appendRenderResult(result, isLast) {
			if (isLast) {
				this.canvasElement.width = result.totalWidth;
				this.canvasElement.height = result.totalHeight;
				if (this._cursorWrapper) {
					this._cursorWrapper.width = result.totalWidth;
					this._cursorWrapper.height = result.totalHeight;
				}
			}
			if (result.width > 0 || result.height > 0) this.uiFacade.beginAppendRenderResults(result);
			if (isLast) this.uiFacade.beginAppendRenderResults(null);
		}
		_updateRenderResult(result) {
			if (result && result.renderResult) this.uiFacade.beginUpdateRenderResults(result);
		}
		/**
		* Tells alphaTab to render the given alphaTex.
		* @param tex The alphaTex code to render.
		* @param tracks If set, the given tracks will be rendered, otherwise the first track only will be rendered.
		* @category Methods - Core
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.tex("\\title 'Test' . 3.3.4");
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Tex("\\title 'Test' . 3.3.4");
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.tex("\\title 'Test' . 3.3.4");
		* ```
		*/
		tex(tex, tracks) {
			try {
				const parser = new AlphaTexImporter();
				parser.logErrors = true;
				parser.initFromString(tex, this.settings);
				const score = parser.readScore();
				this.renderScore(score, tracks);
			} catch (e) {
				this.onError(e);
			}
		}
		/**
		* Triggers a load of the soundfont from the given data.
		* @remarks
		* AlphaTab only supports SoundFont2 and SoundFont3 {@since 1.4.0} encoded soundfonts for loading. To load a soundfont the player must be enabled in advance.
		*
		* @param data The data object to decode. The supported data types is depending on the platform.
		*
		* * A `ArrayBuffer` or `Uint8Array` (all platforms, native byte array or input streams on other platforms)
		* * A url from where to download the binary data of one of the supported file formats (browser only)
		*
		* @param append Whether to fully replace or append the data from the given soundfont.
		* @returns `true` if the passed in object is a supported format and loading was initiated, otherwise `false`.
		*
		* @category Methods - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.loadSoundFont('/assets/MyFile.sf2');
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.LoadSoundFont(System.IO.File.OpenRead("MyFile.sf2"));
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* contentResolver.openInputStream(uri).use {
		*     api.loadSoundFont(it)
		* }
		* ```
		*/
		loadSoundFont(data, append = false) {
			return this.uiFacade.loadSoundFont(data, append);
		}
		/**
		* Unloads all presets from previously loaded SoundFonts.
		* @remarks
		* This function resets the player internally to not have any SoundFont loaded anymore. This allows you to reduce the memory usage of the page
		* if multiple partial SoundFonts are loaded via `loadSoundFont(..., true)`. Depending on the workflow you might also just want to use `loadSoundFont(..., false)` once
		* instead of unloading the previous SoundFonts.
		*
		* @category Methods - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.loadSoundFont('/assets/guitars.sf2', true);
		* api.loadSoundFont('/assets/pianos.sf2', true);
		* // ..
		* api.resetSoundFonts();
		* api.loadSoundFont('/assets/synths.sf2', true);
		* ```
		*
		* @example
		* C#
		* ```cs
		*var api = new AlphaTabApi<MyControl>(...);
		*api.LoadSoundFont(System.IO.File.OpenRead("guitars.sf2"), true);
		*api.LoadSoundFont(System.IO.File.OpenRead("pianos.sf2"), true);
		*...
		*api.ResetSoundFonts();
		*api.LoadSoundFont(System.IO.File.OpenRead("synths.sf2"), true);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.loadSoundFont(readResource("guitars.sf2"), true)
		* api.loadSoundFont(readResource("pianos.sf2"), true)
		* ...
		* api.resetSoundFonts()
		* api.loadSoundFont(readResource("synths.sf2"), true)
		* ```
		*/
		resetSoundFonts() {
			this._player.resetSoundFonts();
		}
		/**
		* Initiates a re-rendering of the current setup.
		* @param renderHints Additional hints to respect during layouting and rendering.
		* @remarks
		* If rendering is not yet possible, it will be deferred until the UI changes to be ready for rendering.
		*
		* @category Methods - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.render();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Render();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.render()
		* ```
		*/
		render(renderHints) {
			if (this.uiFacade.canRender) {
				this._renderer.width = this.container.width;
				this._renderer.renderScore(this.score, this._trackIndexes, renderHints);
			} else this.uiFacade.canRenderChanged.on(() => this.render(renderHints));
		}
		/**
		* A custom cursor handler which will be used to update the cursor positions during playback.
		*
		* @category Properties - Player
		* @since 1.8.1
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.customCursorHandler = {
		*   _customAdorner: undefined,
		*   onAttach(cursors) {
		*     this._customAdorner = document.createElement('div');
		*     this._customAdorner.classList.add('cursor-adorner');
		*     cursors.cursorWrapper.element.appendChild(this._customAdorner);
		*   },
		*   onDetach(cursors) { this._customAdorner.remove(); },
		*   placeBarCursor(barCursor, beatBounds) {
		*     const barBoundings = beatBounds.barBounds.masterBarBounds;
		*     const barBounds = barBoundings.visualBounds;
		*     barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
		*   },
		*   placeBeatCursor(beatCursor, beatBounds, startBeatX) {
		*     const barBoundings = beatBounds.barBounds.masterBarBounds;
		*     const barBounds = barBoundings.visualBounds;
		*     beatCursor.transitionToX(0, startBeatX);
		*     beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
		*     this._customAdorner.style.left = startBeatX + 'px';
		*     this._customAdorner.style.top = (barBounds.y - 10) + 'px';
		*     this._customAdorner.style.width = '1px';
		*     this._customAdorner.style.height = '10px';
		*     this._customAdorner.style.transition = 'left 0ms linear'; // stop animation
		*   },
		*   transitionBeatCursor(beatCursor, beatBounds, startBeatX, endBeatX, duration, cursorMode) {
		*     this._customAdorner.style.transition = `left ${duration}ms linear`; // start animation
		*     this._customAdorner.style.left = endBeatX + 'px';
		*   }
		* }
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.CustomCursorHandler = new CustomCursorHandler();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.customCursorHandler = CustomCursorHandler();
		* ```
		*/
		get customCursorHandler() {
			return this._customCursorHandler;
		}
		set customCursorHandler(value) {
			if (this._customCursorHandler === value) return;
			const currentHandler = this._customCursorHandler ?? this._defaultCursorHandler;
			this._customCursorHandler = value;
			if (this._cursorWrapper) {
				const cursors = new Cursors(this._cursorWrapper, this._barCursor, this._beatCursor, this._selectionWrapper);
				currentHandler?.onDetach(cursors);
				if (value) value?.onDetach(cursors);
				else if (this._defaultCursorHandler) this._defaultCursorHandler.onAttach(cursors);
			}
		}
		_tickCache = null;
		/**
		* A custom scroll handler which will be used to handle scrolling operations during playback.
		*
		* @category Properties - Player
		* @since 1.8.0
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.customScrollHandler = {
		*   forceScrollTo(currentBeatBounds) {
		*     const scroll = api.uiFacade.getScrollElement();
		*     api.uiFacade.scrollToY(scroll, currentBeatBounds.barBounds.masterBarBounds.realBounds.y, 0);
		*   },
		*   onBeatCursorUpdating(startBeat, endBeat, cursorMode, relativePosition, actualBeatCursorStartX, actualBeatCursorEndX, actualBeatCursorTransitionDuration) {
		*     const scroll = api.uiFacade.getScrollElement();
		*     api.uiFacade.scrollToY(scroll, startBeat.barBounds.masterBarBounds.realBounds.y, 0);
		*   }
		* }
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.CustomScrollHandler = new CustomScrollHandler();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.customScrollHandler = CustomScrollHandler();
		* ```
		*/
		customScrollHandler;
		/**
		* The tick cache allowing lookup of midi ticks to beats.
		* @remarks
		* Gets the tick cache allowing lookup of midi ticks to beats. If the player is enabled, a midi file will be generated
		* for the loaded {@link Score} for later playback. During this generation this tick cache is filled with the
		* exact midi ticks when beats are played.
		*
		* The {@link MidiTickLookup.findBeat} method allows a lookup of the beat related to a given input midi tick.
		*
		* @category Properties - Player
		* @since 1.2.3
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* const lookupResult = api.tickCache.findBeat(new Set([0, 1]), 100);
		* const currentBeat = lookupResult?.currentBeat;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* var lookupResult = api.TickCache.FindBeat(new AlphaTab.Core.EcmaScript.Set(0, 1), 100);
		* var currentBeat = lookupResult?.CurrentBeat;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* val lookupResult = api.tickCache.findBeat(alphaTab.core.ecmaScript.Set(0, 1), 100);
		* val currentBeat = lookupResult?.CurrentBeat;
		* ```
		*/
		get tickCache() {
			return this._tickCache;
		}
		/**
		* The tick cache allowing lookup of midi ticks to beats.
		* @remarks
		* In older versions of alphaTab you can access the `boundsLookup` via {@link IScoreRenderer.boundsLookup} on {@link renderer}.
		*
		* After the rendering completed alphaTab exposes via this lookup the location of the individual
		* notation elements. The lookup provides fast access to the bars and beats at a given location.
		* If the {@link CoreSettings.includeNoteBounds} option was activated also the location of the individual notes can be obtained.
		*
		* The property contains a `BoundsLookup` instance which follows a hierarchical structure that represents
		* the tree of rendered elements.
		*
		* The hierarchy is: `staffSystems > bars(1) > bars(2) > beats > notes`
		*
		* * `staffSystems` - Represent the bounds of the individual systems ("rows") where staves are contained.
		* * `bars(1)` - Represent the bounds of all bars for a particular master bar across all tracks.
		* * `bars(2)` - Represent the bounds of an individual bar of a track. The bounds on y-axis span the region of the staff and notes might exceed this bounds.
		* * `beats` - Represent the bounds of the individual beats within a track. The bounds on y-axis are equal to the bar bounds.
		* * `notes` - Represent the bounds of the individual note heads/numbers within a track.
		*
		* Each bounds hierarchy have a `visualBounds` and `realBounds`.
		*
		* * `visualBounds` - Represent the area covering all visually visible elements
		* * `realBounds` - Represents the actual bounds of the elements in this beat including whitespace areas.
		* * `noteHeadBounds` (only on `notes` level) - Represents the area of the note heads or number based on the staff
		*
		* You can check out the individual sizes and regions.
		* @category Properties - Core
		* @since 1.5.0
		*/
		get boundsLookup() {
			return this._renderer.boundsLookup;
		}
		/**
		* The alphaSynth player used for playback.
		* @remarks
		* This is the low-level API to the Midi synthesizer used for playback.
		* Gets access to the underling {@link IAlphaSynth} that is used for the audio playback.
		* @category Properties - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* setupPlayerEvents(api.settings);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* SetupPlayerEvents(api.Player);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* setupPlayerEvents(api.player)
		* ```
		*/
		get player() {
			return this._player.instance ? this._player : null;
		}
		/**
		* Whether the player is ready for starting the playback.
		* @remarks
		* Gets whether the synthesizer is ready for playback. The player is ready for playback when
		* all background workers are started, the audio output is initialized, a soundfont is loaded, and a song was loaded into the player as midi file.
		* @category Properties - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* if(api.isReadyForPlayback)) api.play();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* if(api.IsReadyForPlayback) api.Play();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* if (api.isReadyForPlayback) api.play()
		* ```
		*/
		get isReadyForPlayback() {
			return this._player.isReadyForPlayback;
		}
		/**
		* The current player state.
		* @remarks
		* Gets the current player state, meaning whether it is paused or playing.
		* @category Properties - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* if(api.playerState != alphaTab.synth.PlayerState.Playing) api.play();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* if(api.PlayerState != PlayerState.Playing) api.Play();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* if (api.playerState != PlayerState.Playing) api.play()
		* ```
		*/
		get playerState() {
			return this._player.state;
		}
		/**
		* The current master volume as percentage (0-1).
		* @remarks
		* Gets or sets the master volume of the overall audio being played. The volume is annotated in percentage where 1.0 would be the normal volume and 0.5 only 50%.
		* @category Properties - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.masterVolume = 0.5;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.MasterVolume = 0.5;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.masterVolume = 0.5
		* ```
		*/
		get masterVolume() {
			return this._player.masterVolume;
		}
		set masterVolume(value) {
			this._player.masterVolume = value;
		}
		/**
		* The metronome volume as percentage (0-1).
		* @remarks
		* Gets or sets the volume of the metronome. By default the metronome is disabled but can be enabled by setting the volume different.
		* @category Properties - Player
		* @defaultValue `0`
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.metronomeVolume = 0.5;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.MetronomeVolume = 0.5;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.metronomeVolume = 0.5
		* ```
		*/
		get metronomeVolume() {
			return this._player.metronomeVolume;
		}
		set metronomeVolume(value) {
			this._player.metronomeVolume = value;
		}
		/**
		* The volume of the count-in metronome ticks.
		* @remarks
		* Gets or sets the volume of the metronome during the count-in of the song. By default the count-in is disabled but can be enabled by setting the volume different.
		* @category Properties - Player
		* @since 1.1.0
		* @defaultValue `0`
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.countInVolume = 0.5;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.CountInVolume = 0.5;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.countInVolume = 0.5
		* ```
		*/
		get countInVolume() {
			return this._player.countInVolume;
		}
		set countInVolume(value) {
			this._player.countInVolume = value;
		}
		/**
		* The midi events which will trigger the `midiEventsPlayed` event
		* @remarks
		* Gets or sets the midi events which will trigger the `midiEventsPlayed` event. With this filter set you can enable
		* that alphaTab will signal any midi events as they are played by the synthesizer. This allows reacing on various low level
		* audio playback elements like notes/rests played or metronome ticks.
		*
		* Refer to the [related guide](https://alphatab.net/docs/guides/handling-midi-events) to learn more about this feature.
		* @defaultValue `[]`
		* @category Properties - Player
		* @since 1.2.0
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.midiEventsPlayedFilter = [alphaTab.midi.MidiEventType.AlphaTabMetronome];
		* api.midiEventsPlayed.on(function(e) {
		*   for(const midi of e.events) {
		*     if(midi.isMetronome) {
		*       console.log('Metronome tick ' + midi.metronomeNumerator);
		*     }
		*   }
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.MidiEventsPlayedFilter = new MidiEventType[] { AlphaTab.Midi.MidiEventType.AlphaTabMetronome };
		* api.MidiEventsPlayed.On(e =>
		* {
		*   foreach(var midi of e.events)
		*   {
		*     if(midi is AlphaTab.Midi.AlphaTabMetronomeEvent metronome)
		*     {
		*       Console.WriteLine("Metronome tick " + metronome.MetronomeNumerator);
		*     }
		*   }
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...);
		* api.midiEventsPlayedFilter = alphaTab.collections.List<alphaTab.midi.MidiEventType>( alphaTab.midi.MidiEventType.AlphaTabMetronome )
		* api.midiEventsPlayed.on { e ->
		*   for (midi in e.events) {
		*     if(midi instanceof alphaTab.midi.AlphaTabMetronomeEvent && midi.isMetronome) {
		*       println("Metronome tick " + midi.tick);
		*     }
		*   }
		* }
		* ```
		*/
		get midiEventsPlayedFilter() {
			return this._player.midiEventsPlayedFilter;
		}
		set midiEventsPlayedFilter(value) {
			this._player.midiEventsPlayedFilter = value;
		}
		/**
		* The position within the song in midi ticks.
		* @category Properties - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.tickPosition = 4000;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.TickPosition = 4000;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.tickPosition = 4000
		* ```
		*/
		get tickPosition() {
			return this._player.tickPosition;
		}
		set tickPosition(value) {
			this._player.tickPosition = value;
		}
		/**
		* The position within the song in milliseconds
		* @category Properties - Player
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.timePosition = 4000;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.TimePosition = 4000;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.timePosition = 4000
		* ```
		*/
		get timePosition() {
			return this._player.timePosition;
		}
		set timePosition(value) {
			this._player.timePosition = value;
		}
		/**
		* The total length of the song in midi ticks.
		* @category Properties - Player
		* @since 1.6.2
		*/
		get endTick() {
			return this._player.currentPosition.endTick;
		}
		/**
		* The total length of the song in milliseconds.
		* @category Properties - Player
		* @since 1.6.2
		*/
		get endTime() {
			return this._player.currentPosition.endTime;
		}
		/**
		* The range of the song that should be played.
		* @remarks
		* Gets or sets the range of the song that should be played. The range is defined in midi ticks or the whole song is played if the range is set to null
		* @category Properties - Player
		* @defaultValue `null`
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playbackRange = { startTick: 1000, endTick: 50000 };
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlaybackRange = new PlaybackRange { StartTick = 1000, EndTick = 50000 };
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playbackRange = PlaybackRange.apply {
		*     startTick = 1000
		*     endTick = 50000
		* }
		* ```
		*/
		get playbackRange() {
			return this._player.playbackRange;
		}
		set playbackRange(value) {
			this._player.playbackRange = value;
			if (this._tickCache) this._tickCache.playbackRange = value;
			this._updateSelectionCursor(value);
		}
		/**
		* The current playback speed as percentage
		* @remarks
		* Controls the current playback speed as percentual value. Normal speed is 1.0 (100%) and 0.5 would be 50%.
		* @category Properties - Player
		* @defaultValue `1`
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playbackSpeed = 0.5;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlaybackSpeed = 0.5;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playbackSpeed = 0.5
		* ```
		*/
		get playbackSpeed() {
			return this._player.playbackSpeed;
		}
		set playbackSpeed(value) {
			this._player.playbackSpeed = value;
		}
		/**
		* Whether the playback should automatically restart after it finished.
		* @remarks
		* This setting controls whether the playback should automatically restart after it finished to create a playback loop.
		* @category Properties - Player
		* @defaultValue `false`
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.isLooping = true;
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.IsLooping = true;
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.isLooping = true
		* ```
		*/
		get isLooping() {
			return this._player.isLooping;
		}
		set isLooping(value) {
			this._player.isLooping = value;
		}
		_destroyPlayer() {
			this._player.destroy();
			this._previousTick = 0;
			this._destroyCursors();
		}
		/**
		*
		* @returns true if a new player was created, false if no player was created (includes destroy & reuse of the current one)
		*/
		_setupOrDestroyPlayer() {
			let mode = this.settings.player.playerMode;
			if (mode === PlayerMode.EnabledAutomatic) {
				const score = this.score;
				if (!score) return false;
				if (score?.backingTrack?.rawAudioFile) mode = PlayerMode.EnabledBackingTrack;
				else mode = PlayerMode.EnabledSynthesizer;
			}
			let newPlayer = null;
			if (mode !== this._actualPlayerMode) {
				this._destroyPlayer();
				this._updateCursors();
				switch (mode) {
					case PlayerMode.Disabled:
						newPlayer = null;
						break;
					case PlayerMode.EnabledSynthesizer:
						newPlayer = this.uiFacade.createWorkerPlayer();
						break;
					case PlayerMode.EnabledBackingTrack:
						newPlayer = this.uiFacade.createBackingTrackPlayer();
						break;
					case PlayerMode.EnabledExternalMedia:
						newPlayer = new ExternalMediaPlayer(this.settings.player.bufferTimeInMilliseconds);
						break;
				}
			} else {
				this._updateCursors();
				return false;
			}
			this._actualPlayerMode = mode;
			if (!newPlayer) return false;
			this._player.instance = newPlayer;
			return false;
		}
		/**
		* Re-creates the midi for the current score and loads it.
		* @remarks
		* This will result in the player to stop playback. Some setting changes require re-genration of the midi song.
		* @category Methods - Player
		* @since 1.6.0
		*/
		loadMidiForScore() {
			if (!this.score) return;
			const score = this.score;
			Logger.debug("AlphaTab", "Generating Midi");
			const midiFile = new MidiFile();
			const handler = new AlphaSynthMidiFileHandler(midiFile);
			const generator = new MidiFileGenerator(score, this.settings, handler);
			const startIndex = ModelUtils.computeFirstDisplayedBarIndex(score, this.settings);
			const endIndex = ModelUtils.computeLastDisplayedBarIndex(score, this.settings, startIndex);
			generator.tickLookup.multiBarRestInfo = ModelUtils.buildMultiBarRestInfo(this.tracks, startIndex, endIndex);
			generator.applyTranspositionPitches = false;
			generator.generate();
			this._tickCache = generator.tickLookup;
			this._tickCache.playbackRange = this.playbackRange;
			this._onMidiLoad(midiFile);
			const player = this._player;
			player.midiTickShift = handler.tickShift;
			player.loadMidiFile(midiFile);
			player.loadBackingTrack(score);
			player.updateSyncPoints(generator.syncPoints);
			player.applyTranspositionPitches(generator.transpositionPitches);
		}
		/**
		* Triggers an update of the sync points for the current score after modification within the data model
		* @category Methods - Player
		* @since 1.6.0
		*/
		updateSyncPoints() {
			if (!this.score) return;
			const score = this.score;
			this._player.updateSyncPoints(MidiFileGenerator.generateSyncPoints(score));
		}
		/**
		* Changes the volume of the given tracks.
		* @param tracks The tracks for which the volume should be changed.
		* @param volume The volume to set for all tracks in percent (0-1)
		*
		* @remarks
		* This will result in a volume change of the primary and secondary midi channel that the track uses for playback.
		* If the track shares the channels with another track, all related tracks will be changed as they cannot be distinguished.
		* @category Methods - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.changeTrackVolume([api.score.tracks[0], api.score.tracks[1]], 1.5);
		* api.changeTrackVolume([api.score.tracks[2]], 0.5);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, 1.5);
		* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[2] }, 0.5);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...);
		* api.changeTrackVolume(alphaTab.collections.List<alphaTab.model.Track>(api.score.tracks[0], api.score.tracks[1]), 1.5);
		* api.changeTrackVolume(alphaTab.collections.List<alphaTab.model.Track>(api.score.tracks[2]), 0.5);
		* ```
		*/
		changeTrackVolume(tracks, volume) {
			for (const track of tracks) {
				this._player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
				this._player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
			}
		}
		/**
		* Changes the given tracks to be played solo or not.
		* @param tracks The list of tracks to play solo or not.
		* @param solo If set to true, the tracks will be added to the solo list. If false, they are removed.
		*
		* @remarks
		* If any track is set to solo, all other tracks are muted, unless they are also flagged as solo.
		* This will result in a solo playback of the primary and secondary midi channel that the track uses for playback.
		* If the track shares the channels with another track, all related tracks will be played as they cannot be distinguished.
		* @category Methods - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.changeTrackSolo([api.score.tracks[0], api.score.tracks[1]], true);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ChangeTrackSolo(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, true);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.changeTrackSolo(alphaTab.collections.List<alphaTab.model.Track>(api.score.tracks[0], api.score.tracks[1]), true);
		* ```
		*/
		changeTrackSolo(tracks, solo) {
			for (const track of tracks) {
				this._player.setChannelSolo(track.playbackInfo.primaryChannel, solo);
				this._player.setChannelSolo(track.playbackInfo.secondaryChannel, solo);
			}
		}
		/**
		* Changes the given tracks to be muted or not.
		* @param tracks The list of track to mute or unmute.
		* @param mute If set to true, the tracks will be muted. If false they are unmuted.
		*
		* @remarks
		* This will result in a muting of the primary and secondary midi channel that the track uses
		* for playback. If the track shares the channels with another track, all tracks will be muted as during playback they cannot be distinguished.
		* @category Methods - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.changeTrackMute([api.score.tracks[0], api.score.tracks[1]], true);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ChangeTrackMute(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, true);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.changeTrackMute(alphaTab.collections.List<alphaTab.model.Track>(api.score.tracks[0], api.score.tracks[1]), true);
		* ```
		*/
		changeTrackMute(tracks, mute) {
			for (const track of tracks) {
				this._player.setChannelMute(track.playbackInfo.primaryChannel, mute);
				this._player.setChannelMute(track.playbackInfo.secondaryChannel, mute);
			}
		}
		/**
		* Changes the pitch transpose applied to the given tracks.
		* @param tracks The list of tracks to change.
		* @param semitones The number of semitones to apply as pitch offset.
		*
		* @remarks
		* These pitches are additional to the ones applied to the song via the settings and data model and allows a more live-update via a UI.
		* @category Methods - Player
		* @since 1.4.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.changeTrackTranspositionPitch([api.score.tracks[0], api.score.tracks[1]], 3);
		* api.changeTrackTranspositionPitch([api.score.tracks[2]], 2);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ChangeTrackTranspositionPitch(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, 3);
		* api.ChangeTrackTranspositionPitch(new Track[] { api.Score.Tracks[2] }, 3);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...);
		* api.changeTrackTranspositionPitch(alphaTab.collections.List<alphaTab.model.Track>(api.score.tracks[0], api.score.tracks[1]), 3);
		* api.changeTrackTranspositionPitch(alphaTab.collections.List<alphaTab.model.Track>(api.score.tracks[2]), 2);
		* ```
		*/
		changeTrackTranspositionPitch(tracks, semitones) {
			for (const track of tracks) {
				this._player.setChannelTranspositionPitch(track.playbackInfo.primaryChannel, semitones);
				this._player.setChannelTranspositionPitch(track.playbackInfo.secondaryChannel, semitones);
			}
		}
		/**
		* Starts the playback of the current song.
		* @returns true if the playback was started, otherwise false. Reasons for not starting can be that the player is not ready or already playing.
		* @category Methods - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.play();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Play();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.play()
		* ```
		*/
		play() {
			return this._player.play();
		}
		/**
		* Pauses the playback of the current song.
		* @category Methods - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.pause();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Pause();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.pause();
		* ```
		*/
		pause() {
			this._player.pause();
		}
		/**
		* Toggles between play/pause depending on the current player state.
		* @remarks
		* If the player was playing, it will pause. If it is paused, it will initiate a play.
		* @category Methods - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playPause();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayPause();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playPause()
		* ```
		*/
		playPause() {
			this._player.playPause();
		}
		/**
		* Stops the playback of the current song, and moves the playback position back to the start.
		* @remarks
		* If a dedicated playback range is selected, it will move the playback position to the start of this range, not the whole song.
		* @category Methods - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.stop();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Stop();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.stop()
		* ```
		*/
		stop() {
			this._player.stop();
		}
		/**
		* Triggers the play of the given beat.
		* @param beat the single beat to play
		* @remarks
		* This will stop the any other current ongoing playback.
		* This method can be used in applications when individual beats need to be played for lesson or editor style purposes.
		* The player will not report any change in state or playback position during the playback of the requested beat.
		* It is a playback of audio separate to the main song playback.
		* @returns true if the playback was started, otherwise false. Reasons for not starting can be that the player is not ready or already playing.
		* @category Methods - Player
		* @since 1.1.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playBeat(api.score.tracks[0].staves[0].bars[0].voices[0].beats[0]);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayBeat(api.Score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0]);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playBeat(api.score.tracks[0].staves[0].bars[0].voices[0].beats[0])
		* ```
		*/
		playBeat(beat) {
			const midiFile = new MidiFile();
			const handler = new AlphaSynthMidiFileHandler(midiFile);
			new MidiFileGenerator(beat.voice.bar.staff.track.score, this.settings, handler).generateSingleBeat(beat);
			this._player.playOneTimeMidiFile(midiFile);
		}
		/**
		* Triggers the play of the given note.
		* @param note the single note to play
		* @remarks
		* This will stop the any other current ongoing playback.
		* This method can be used in applications when individual notes need to be played for lesson or editor style purposes.
		* The player will not report any change in state or playback position during the playback of the requested note.
		* It is a playback of audio separate to the main song playback.
		* @category Methods - Player
		* @since 1.1.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playNote(api.score.tracks[0].staves[0].bars[0].voices[0].beats[0].notes[0]);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayNote(api.Score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0].Notes[0]);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playNote(api.score.tracks[0].staves[0].bars[0].voices[0].beats[0].notes[0]);
		* ```
		*/
		playNote(note) {
			const midiFile = new MidiFile();
			const handler = new AlphaSynthMidiFileHandler(midiFile);
			new MidiFileGenerator(note.beat.voice.bar.staff.track.score, this.settings, handler).generateSingleNote(note);
			this._player.playOneTimeMidiFile(midiFile);
		}
		_cursorWrapper = null;
		_barCursor = null;
		_beatCursor = null;
		_selectionWrapper = null;
		_previousTick = 0;
		_currentBeat = null;
		_currentBeatBounds = null;
		_isInitialBeatCursorUpdate = true;
		_previousStateForCursor = PlayerState.Paused;
		_previousCursorCache = null;
		_destroyCursors() {
			if (!this._cursorWrapper) return;
			(this.customCursorHandler ?? this._defaultCursorHandler)?.onDetach(new Cursors(this._cursorWrapper, this._barCursor, this._beatCursor, this._selectionWrapper));
			this.uiFacade.destroyCursors();
			this._cursorWrapper = null;
			this._barCursor = null;
			this._beatCursor = null;
			this._selectionWrapper = null;
		}
		_createCursors() {
			if (this._cursorWrapper) return;
			const cursors = this.uiFacade.createCursors();
			if (cursors) {
				this._cursorWrapper = cursors.cursorWrapper;
				this._barCursor = cursors.barCursor;
				this._beatCursor = cursors.beatCursor;
				this._selectionWrapper = cursors.selectionWrapper;
				(this.customCursorHandler ?? this._defaultCursorHandler)?.onAttach(cursors);
				this._isInitialBeatCursorUpdate = true;
			}
			const currentBeat = this._currentBeat;
			if (currentBeat) this._cursorUpdateBeat(currentBeat, false, this._previousTick > 10, 1, true);
		}
		_updateCursors() {
			this._updateCursorHandler();
			this._updateScrollHandler();
			const enable = this._hasCursor;
			if (enable) this._createCursors();
			else if (!enable && this._cursorWrapper) this._destroyCursors();
		}
		_cursorHandlerMode = false;
		_updateCursorHandler() {
			const currentHandler = this._defaultCursorHandler;
			const cursorHandlerMode = this.settings.player.enableAnimatedBeatCursor;
			if (currentHandler !== void 0 && this._cursorHandlerMode === cursorHandlerMode) return;
			if (cursorHandlerMode) this._defaultCursorHandler = new ToNextBeatAnimatingCursorHandler();
			else this._defaultCursorHandler = new NonAnimatingCursorHandler();
		}
		_scrollHandlerMode = ScrollMode.Off;
		_scrollHandlerVertical = true;
		_updateScrollHandler() {
			const currentHandler = this._defaultScrollHandler;
			const scrollMode = this.settings.player.scrollMode;
			const isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
			if (this._scrollHandlerMode === scrollMode && this._scrollHandlerVertical === isVertical) return;
			if (currentHandler) {
				currentHandler[Symbol.dispose]();
				const scroll = this.uiFacade.getScrollContainer();
				this.uiFacade.stopScrolling(scroll);
			}
			switch (scrollMode) {
				case ScrollMode.Off:
					this._defaultScrollHandler = void 0;
					break;
				case ScrollMode.Continuous:
					if (isVertical) this._defaultScrollHandler = new VerticalContinuousScrollHandler(this);
					else this._defaultScrollHandler = new HorizontalContinuousScrollHandler(this);
					break;
				case ScrollMode.OffScreen:
					if (isVertical) this._defaultScrollHandler = new VerticalOffScreenScrollHandler(this);
					else this._defaultScrollHandler = new HorizontalOffScreenScrollHandler(this);
					break;
				case ScrollMode.Smooth:
					if (isVertical) this._defaultScrollHandler = new VerticalSmoothScrollHandler(this);
					else this._defaultScrollHandler = new HorizontalSmoothScrollHandler(this);
					break;
			}
		}
		/**
		* updates the cursors to highlight the beat at the specified tick position
		* @param tick
		* @param stop
		* @param shouldScroll whether we should scroll to the bar (if scrolling is active)
		*/
		_cursorUpdateTick(tick, stop, cursorSpeed, shouldScroll = false, forceUpdate = false) {
			this._previousTick = tick;
			const cache = this._tickCache;
			if (cache) {
				const beat = cache.findBeatWithChecker(this._beatVisibilityChecker, tick, this._currentBeat);
				if (beat) this._cursorUpdateBeat(beat, stop, shouldScroll, cursorSpeed, forceUpdate || this.playerState === PlayerState.Paused);
			}
		}
		/**
		* updates the cursors to highlight the specified beat
		*/
		_cursorUpdateBeat(lookupResult, stop, shouldScroll, cursorSpeed, forceUpdate = false) {
			const beat = lookupResult.beat;
			if (!beat) return;
			const cache = this._renderer.boundsLookup;
			if (!cache) return;
			const previousBeat = this._currentBeat;
			const previousCache = this._previousCursorCache;
			const previousState = this._previousStateForCursor;
			if (!forceUpdate && beat === previousBeat?.beat && cache === previousCache && previousState === this._player.state && previousBeat?.start === lookupResult.start) return;
			const beatBoundings = cache.findBeat(beat);
			if (!beatBoundings) return;
			this._currentBeat = lookupResult;
			this._previousCursorCache = cache;
			this._previousStateForCursor = this._player.state;
			this.uiFacade.beginInvoke(() => {
				this._internalCursorUpdateBeat(lookupResult, stop, cache, beatBoundings, shouldScroll, cursorSpeed, forceUpdate);
			});
		}
		/**
		* Initiates a scroll to the cursor.
		* @since 1.2.3
		* @category Methods - Player
		*/
		scrollToCursor() {
			const beatBounds = this._currentBeatBounds;
			if (beatBounds) {
				const handler = this.customScrollHandler ?? this._defaultScrollHandler;
				if (handler) handler.forceScrollTo(beatBounds);
			}
		}
		_internalCursorUpdateBeat(lookupResult, stop, boundsLookup, beatBoundings, shouldScroll, cursorSpeed, forceUpdate) {
			const beat = lookupResult.beat;
			const nextBeat = lookupResult.nextBeat?.beat;
			let duration = lookupResult.duration;
			const beatsToHighlight = lookupResult.beatLookup.highlightedBeats;
			const cursorMode = lookupResult.cursorMode;
			const cursorHandler = this.customCursorHandler ?? this._defaultCursorHandler;
			const beatCursor = this._beatCursor;
			const barCursor = this._barCursor;
			const barBoundings = beatBoundings.barBounds.masterBarBounds;
			const barBounds = barBoundings.visualBounds;
			const previousBeatBounds = this._currentBeatBounds;
			this._currentBeatBounds = beatBoundings;
			if (barCursor) cursorHandler.placeBarCursor(barCursor, beatBoundings);
			const isPlayingUpdate = this._player.state === PlayerState.Playing && !stop;
			let nextBeatX = beatBoundings.realBounds.x + beatBoundings.realBounds.w;
			let nextBeatBoundings = null;
			if (nextBeat && cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext) {
				nextBeatBoundings = boundsLookup.findBeat(nextBeat);
				if (nextBeatBoundings && nextBeatBoundings.barBounds.masterBarBounds.staffSystemBounds === barBoundings.staffSystemBounds) nextBeatX = nextBeatBoundings.onNotesX;
			}
			let startBeatX = beatBoundings.onNotesX;
			if (beatCursor) {
				const animationWidth = nextBeatX - beatBoundings.onNotesX;
				const relativePosition = this._previousTick - lookupResult.start;
				let ratioPosition = lookupResult.tickDuration > 0 ? relativePosition / lookupResult.tickDuration : 0;
				if (ratioPosition > 1) ratioPosition = 1;
				startBeatX = beatBoundings.onNotesX + animationWidth * ratioPosition;
				duration -= duration * ratioPosition;
				duration = duration / cursorSpeed;
				if (isPlayingUpdate) {
					if (!previousBeatBounds || forceUpdate || this._isInitialBeatCursorUpdate || barBounds.y !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.y || startBeatX < previousBeatBounds.onNotesX || barBoundings.index > previousBeatBounds.barBounds.masterBarBounds.index + 1 || barBounds.h !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.h) cursorHandler.placeBeatCursor(beatCursor, beatBoundings, startBeatX);
					this.uiFacade.beginInvoke(() => {
						cursorHandler.transitionBeatCursor(beatCursor, beatBoundings, startBeatX, nextBeatX, duration, cursorMode);
					});
				} else {
					duration = 0;
					cursorHandler.placeBeatCursor(beatCursor, beatBoundings, startBeatX);
				}
				this._isInitialBeatCursorUpdate = false;
			} else this._isInitialBeatCursorUpdate = true;
			this.uiFacade.removeHighlights();
			let shouldNotifyBeatChange = false;
			if (isPlayingUpdate) {
				if (this.settings.player.enableElementHighlighting) for (const highlight of beatsToHighlight) {
					const className = BeatContainerGlyph.getGroupId(highlight.beat);
					this.uiFacade.highlightElements(className, beat.voice.bar.index);
				}
				shouldScroll = !stop;
				shouldNotifyBeatChange = true;
			}
			if (shouldScroll && !this._isBeatMouseDown && this.settings.player.scrollMode !== ScrollMode.Off) {
				const handler = this.customScrollHandler ?? this._defaultScrollHandler;
				if (handler) handler.onBeatCursorUpdating(beatBoundings, nextBeatBoundings === null ? void 0 : nextBeatBoundings, cursorMode, startBeatX, nextBeatX, duration);
			}
			if (shouldNotifyBeatChange) {
				this._onPlayedBeatChanged(beat);
				this._onActiveBeatsChanged(new ActiveBeatsChangedEventArgs(beatsToHighlight.map((i) => i.beat)));
			}
		}
		/**
		* This event is fired when the played beat changed.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playedBeatChanged.on((beat) => {
		*     updateFretboard(beat);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayedBeatChanged.On(beat =>
		* {
		*     UpdateFretboard(beat);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playedBeatChanged.on { beat ->
		*     updateFretboard(beat)
		* }
		* ```
		*
		*/
		playedBeatChanged;
		_onPlayedBeatChanged(beat) {
			if (this._isDestroyed) return;
			this.playedBeatChanged.trigger(beat);
			this.uiFacade.triggerEvent(this.container, "playedBeatChanged", beat);
		}
		/**
		* This event is fired when the currently active beats across all tracks change.
		*
		* @remarks
		* Unlike the {@link playedBeatChanged} event this event contains the beats of all tracks and voices independent of them being rendered.
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.2.3
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.activeBeatsChanged.on(args => {
		*    updateHighlights(args.activeBeats);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ActiveBeatsChanged.On(args =>
		* {
		*     UpdateHighlights(args.ActiveBeats);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.activeBeatsChanged.on { args ->
		*     updateHighlights(args.activeBeats)
		* }
		* ```
		*
		*/
		activeBeatsChanged;
		_onActiveBeatsChanged(e) {
			if (this._isDestroyed) return;
			this.activeBeatsChanged.trigger(e);
			this.uiFacade.triggerEvent(this.container, "activeBeatsChanged", e);
		}
		_isBeatMouseDown = false;
		_isNoteMouseDown = false;
		_selectionStart;
		_selectionEnd;
		/**
		* This event is fired whenever a the user presses the mouse button on a beat.
		* @eventProperty
		* @category Events - Player
		* @since 0.9.7
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.beatMouseDown.on((beat) => {
		*     startSelectionOnBeat(beat);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.BeatMouseDown.On(beat =>
		* {
		*     StartSelectionOnBeat(args);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.beatMouseDown.on { beat ->
		*     startSelectionOnBeat(args)
		* }
		* ```
		*/
		beatMouseDown = new EventEmitterOfT();
		/**
		* This event is fired whenever the user moves the mouse over a beat after the user already pressed the button on a beat.
		* @eventProperty
		* @category Events - Player
		* @since 0.9.7
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.beatMouseMove.on((beat) => {
		*     expandSelectionToBeat(beat);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.BeatMouseMove.On(beat =>
		* {
		*     ExpandSelectionToBeat(beat);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.beatMouseMove.on { beat ->
		*     expandSelectionToBeat(beat)
		* }
		* ```
		*/
		beatMouseMove = new EventEmitterOfT();
		/**
		* This event is fired whenever the user releases the mouse after a mouse press on a beat.
		* @remarks
		* This event is fired regardless of whether the mouse was released on a beat.
		* The parameter is null if the mouse was released somewhere beside the beat.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.7
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.beatMouseUp.on((beat) => {
		*     hideSelection(beat);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.BeatMouseUp.On(beat =>
		* {
		*     HideSelection(beat);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.beatMouseUp.on { beat ->
		*     hideSelection(beat)
		* }
		* ```
		*/
		beatMouseUp = new EventEmitterOfT();
		/**
		* This event is fired whenever a the user presses the mouse button on a note head/number.
		* @remarks
		* This event is fired whenever a the user presses the mouse button on a note.
		* It is only fired if {@link CoreSettings.includeNoteBounds} was set to `true` because
		* only then this hit detection can be done. A click on a note is considered if the note head or the note number on tabs are clicked as documented in {@link boundsLookup}.
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.2.3
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.noteMouseDown.on((note) => {
		*     api.playNote(note);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.NoteMouseDown.On(note =>
		* {
		*     api.PlayNote(note);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.noteMouseDown.on { note ->
		*     api.playNote(note)
		* }
		* ```
		*
		*/
		noteMouseDown = new EventEmitterOfT();
		/**
		* This event is fired whenever the user moves the mouse over a note after the user already pressed the button on a note.
		* @remarks
		* This event is fired whenever the user moves the mouse over a note after the user already pressed the button on a note.
		* It is only fired if {@link CoreSettings.includeNoteBounds} was set to `true` because
		* only then this hit detection can be done. A click on a note is considered if the note head or the note number on tabs are clicked as documented in {@link boundsLookup}
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.2.3
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.noteMouseMove.on((note) => {
		*     changeNote(note)
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.NoteMouseMove.On(note =>
		* {
		*     ChangeNote(note);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.noteMouseMove.on { note ->
		*     changeNote(note)
		* }
		* ```
		*
		*/
		noteMouseMove = new EventEmitterOfT();
		/**
		* This event is fired whenever the user releases the mouse after a mouse press on a note.
		* @remarks
		* This event is fired whenever a the user presses the mouse button on a note.
		* This event is fired regardless of whether the mouse was released on a note.
		* The parameter is null if the mouse was released somewhere beside the note.
		* It is only fired if {@link CoreSettings.includeNoteBounds} was set to `true` because
		* only then this hit detection can be done. A click on a note is considered if the note head or the note number on tabs are clicked as documented in the {@link boundsLookup}.
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.2.3
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.noteMouseUp.on((note) => {
		*     api.playNote(note);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.NoteMouseUp.On(note =>
		* {
		*     api.PlayNote(note);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.noteMouseUp.on { note ->
		*     api.playNote(note)
		* }
		* ```
		*
		*/
		noteMouseUp = new EventEmitterOfT();
		get _hasCursor() {
			return this.settings.player.playerMode !== PlayerMode.Disabled && this.settings.player.enableCursor;
		}
		_onBeatMouseDown(originalEvent, beat) {
			if (this._isDestroyed) return;
			if (this._hasCursor && this.settings.player.enableUserInteraction) {
				this._selectionStart = { beat };
				this._selectionEnd = void 0;
			}
			this._isBeatMouseDown = true;
			this.beatMouseDown.trigger(beat);
			this.uiFacade.triggerEvent(this.container, "beatMouseDown", beat, originalEvent);
		}
		_onNoteMouseDown(originalEvent, note) {
			if (this._isDestroyed) return;
			this._isNoteMouseDown = true;
			this.noteMouseDown.trigger(note);
			this.uiFacade.triggerEvent(this.container, "noteMouseDown", note, originalEvent);
		}
		_onBeatMouseMove(originalEvent, beat) {
			if (this._isDestroyed) return;
			if (this.settings.player.enableUserInteraction) {
				if (!this._selectionEnd || this._selectionEnd.beat !== beat) {
					this._selectionEnd = { beat };
					this._cursorSelectRange(this._selectionStart, this._selectionEnd);
				}
			}
			this.beatMouseMove.trigger(beat);
			this.uiFacade.triggerEvent(this.container, "beatMouseMove", beat, originalEvent);
		}
		_onNoteMouseMove(originalEvent, note) {
			if (this._isDestroyed) return;
			this.noteMouseMove.trigger(note);
			this.uiFacade.triggerEvent(this.container, "noteMouseMove", note, originalEvent);
		}
		_onBeatMouseUp(originalEvent, beat) {
			if (this._isDestroyed) return;
			if (this._hasCursor && this.settings.player.enableUserInteraction) this.applyPlaybackRangeFromHighlight();
			this.beatMouseUp.trigger(beat);
			this.uiFacade.triggerEvent(this.container, "beatMouseUp", beat, originalEvent);
			this._isBeatMouseDown = false;
		}
		_onNoteMouseUp(originalEvent, note) {
			if (this._isDestroyed) return;
			this.noteMouseUp.trigger(note);
			this.uiFacade.triggerEvent(this.container, "noteMouseUp", note, originalEvent);
			this._isNoteMouseDown = false;
		}
		_updateSelectionCursor(range) {
			if (!this._tickCache) return;
			if (range) {
				const startBeat = this._tickCache.findBeat(this._trackIndexLookup, range.startTick);
				const endBeat = this._tickCache.findBeat(this._trackIndexLookup, range.endTick);
				if (startBeat && endBeat) {
					const selectionStart = { beat: startBeat.beat };
					const selectionEnd = { beat: endBeat.beat };
					this._cursorSelectRange(selectionStart, selectionEnd);
				}
			} else this._cursorSelectRange(void 0, void 0);
		}
		_setupClickHandling() {
			this.canvasElement.mouseDown.on((e) => {
				if (!e.isLeftMouseButton) return;
				if (this.settings.player.enableUserInteraction) e.preventDefault();
				const relX = e.getX(this.canvasElement);
				const relY = e.getY(this.canvasElement);
				const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
				if (beat) {
					this._onBeatMouseDown(e, beat);
					if (this.settings.core.includeNoteBounds) {
						const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
						if (note) this._onNoteMouseDown(e, note);
					}
				}
			});
			this.canvasElement.mouseMove.on((e) => {
				if (!this._isBeatMouseDown) return;
				const relX = e.getX(this.canvasElement);
				const relY = e.getY(this.canvasElement);
				const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
				if (beat) {
					this._onBeatMouseMove(e, beat);
					if (this._isNoteMouseDown) {
						const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
						if (note) this._onNoteMouseMove(e, note);
					}
				}
			});
			this.canvasElement.mouseUp.on((e) => {
				if (!this._isBeatMouseDown) return;
				if (this.settings.player.enableUserInteraction) e.preventDefault();
				const relX = e.getX(this.canvasElement);
				const relY = e.getY(this.canvasElement);
				const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
				this._onBeatMouseUp(e, beat);
				if (this._isNoteMouseDown) if (beat) {
					const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY) ?? null;
					this._onNoteMouseUp(e, note);
				} else this._onNoteMouseUp(e, null);
			});
			this._renderer.postRenderFinished.on(() => {
				if (!this._selectionStart || !this._hasCursor || !this.settings.player.enableUserInteraction) return;
				this._cursorSelectRange(this._selectionStart, this._selectionEnd);
			});
		}
		/**
		* Places the highlight markers at the specified start and end-beat range.
		* @param startBeat The start beat where the selection should start
		* @param endBeat The end beat where the selection should end.
		*
		* @remarks
		* Unlike actually setting {@link playbackRange} this method only places the selection markers without actually
		* changing the playback range. This method can be used when building custom selection systems (e.g. having draggable handles).
		*
		* @category Methods - Player
		* @since 1.8.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* const startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0];
		* const endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0];
		* api.highlightPlaybackRange(startBeat, endBeat);
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, 1.5);
		* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[2] }, 0.5);
		* var startBeat = api.Score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0];
		* var endBeat = api.Score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[0];
		* api.HighlightPlaybackRange(startBeat, endBeat);
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* val startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0]
		* val endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0]
		* api.highlightPlaybackRange(startBeat, endBeat)
		* ```
		*/
		highlightPlaybackRange(startBeat, endBeat) {
			this._selectionStart = { beat: startBeat };
			this._selectionEnd = { beat: endBeat };
			this._cursorSelectRange(this._selectionStart, this._selectionEnd);
		}
		/**
		* Applies the playback range from the currently highlighted range.
		*
		* @remarks
		* This method can be used when building custom selection systems (e.g. having draggable handles).
		*
		* @category Methods - Player
		* @since 1.8.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* const startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0];
		* const endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0];
		* api.highlightPlaybackRange(startBeat, endBeat);
		* api.applyPlaybackRangeFromHighlight();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, 1.5);
		* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[2] }, 0.5);
		* var startBeat = api.Score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0];
		* var endBeat = api.Score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[0];
		* api.HighlightPlaybackRange(startBeat, endBeat);
		* api.ApplyPlaybackRangeFromHighlight();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* val startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0]
		* val endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0]
		* api.highlightPlaybackRange(startBeat, endBeat)
		* api.applyPlaybackRangeFromHighlight()
		* ```
		*/
		applyPlaybackRangeFromHighlight() {
			if (this._selectionEnd) {
				const startTick = this._tickCache?.getBeatStart(this._selectionStart.beat) ?? this._selectionStart.beat.absolutePlaybackStart;
				if ((this._tickCache?.getBeatStart(this._selectionEnd.beat) ?? this._selectionEnd.beat.absolutePlaybackStart) < startTick) {
					const t = this._selectionStart;
					this._selectionStart = this._selectionEnd;
					this._selectionEnd = t;
				}
			}
			if (this._selectionStart && this._tickCache) {
				const tickCache = this._tickCache;
				const realStartMasterBarStart = tickCache.getMasterBarStart(this._selectionStart.beat.voice.bar.masterBar);
				const startBeatPlaybackStart = tickCache.getRelativeBeatPlaybackRange(this._selectionStart.beat)?.startTick ?? this._selectionStart.beat.playbackStart;
				this._currentBeat = null;
				if (this._player.state === PlayerState.Paused) this._cursorUpdateTick(realStartMasterBarStart + startBeatPlaybackStart, false, 1);
				this.tickPosition = realStartMasterBarStart + startBeatPlaybackStart;
				if (this._selectionEnd && this._selectionStart.beat !== this._selectionEnd.beat) {
					const realEndMasterBarStart = tickCache.getMasterBarStart(this._selectionEnd.beat.voice.bar.masterBar);
					const endBeatPlaybackEnd = tickCache.getRelativeBeatPlaybackRange(this._selectionEnd.beat)?.endTick ?? this._selectionEnd.beat.playbackStart + this._selectionEnd.beat.playbackDuration;
					const range = new PlaybackRange();
					range.startTick = realStartMasterBarStart + startBeatPlaybackStart;
					range.endTick = realEndMasterBarStart + endBeatPlaybackEnd - 50;
					this.playbackRange = range;
				} else {
					this._selectionStart = void 0;
					this.playbackRange = null;
					this._cursorSelectRange(this._selectionStart, this._selectionEnd);
				}
			}
		}
		/**
		* Clears the highlight markers marking the currently selected playback range.
		*
		* @remarks
		* Unlike actually setting {@link playbackRange} this method only clears the selection markers without actually
		* changing the playback range. This method can be used when building custom selection systems (e.g. having draggable handles).
		*
		* @category Methods - Player
		* @since 1.8.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.clearPlaybackRangeHighlight();
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.clearPlaybackRangeHighlight();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.clearPlaybackRangeHighlight()
		* ```
		*/
		clearPlaybackRangeHighlight() {
			this._cursorSelectRange(void 0, void 0);
		}
		/**
		* This event is fired the shown highlights for the selected playback range changes.
		*
		* @remarks
		* This event is fired already during selection and not only when the selection is completed.
		* This event can be used to place additional custom selection markers (like drag handles).
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.8.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playbackRangeHighlightChanged.on(e => {
		*    updateSelectionHandles(e);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlaybackRangeHighlightChanged.On(e =>
		* {
		*    UpdateSelectionHandles(e);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playbackRangeHighlightChanged.on { e ->
		*     updateSelectionHandles(e)
		* }
		* ```
		*
		*/
		playbackRangeHighlightChanged = new EventEmitterOfT();
		_cursorSelectRange(startBeat, endBeat) {
			const cache = this._renderer.boundsLookup;
			if (!cache) {
				this.playbackRangeHighlightChanged.trigger({});
				return;
			}
			const selectionWrapper = this._selectionWrapper;
			if (!selectionWrapper) {
				this.playbackRangeHighlightChanged.trigger({});
				return;
			}
			selectionWrapper.clear();
			if (!startBeat || !endBeat || startBeat.beat === endBeat.beat) {
				this.playbackRangeHighlightChanged.trigger({});
				return;
			}
			if (!startBeat.bounds) startBeat.bounds = cache.findBeat(startBeat.beat) ?? void 0;
			if (!endBeat.bounds) endBeat.bounds = cache.findBeat(endBeat.beat) ?? void 0;
			const startTick = this._tickCache?.getBeatStart(startBeat.beat) ?? startBeat.beat.absolutePlaybackStart;
			if ((this._tickCache?.getBeatStart(endBeat.beat) ?? endBeat.beat.absolutePlaybackStart) < startTick) {
				const t = startBeat;
				startBeat = endBeat;
				endBeat = t;
			}
			const eventArgs = {
				startBeat: startBeat.beat,
				startBeatBounds: startBeat.bounds,
				endBeat: endBeat.beat,
				endBeatBounds: endBeat.bounds,
				highlightBlocks: []
			};
			let startX = startBeat.bounds.realBounds.x;
			if (startBeat.beat.index === 0) startX = startBeat.bounds.barBounds.masterBarBounds.realBounds.x;
			let endX = endBeat.bounds.realBounds.x + endBeat.bounds.realBounds.w;
			if (endBeat.beat.index === endBeat.beat.voice.beats.length - 1) endX = endBeat.bounds.barBounds.masterBarBounds.realBounds.x + endBeat.bounds.barBounds.masterBarBounds.realBounds.w;
			if (startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds !== endBeat.bounds.barBounds.masterBarBounds.staffSystemBounds) {
				const staffStartX = startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.visualBounds.x;
				const staffEndX = startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.visualBounds.x + startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.visualBounds.w;
				const startSelection = this.uiFacade.createSelectionElement();
				const startSelectionBounds = new Bounds(startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.y, staffEndX - startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.h);
				startSelection.setBounds(startSelectionBounds.x, startSelectionBounds.y, startSelectionBounds.w, startSelectionBounds.h);
				eventArgs.highlightBlocks.push(startSelectionBounds);
				selectionWrapper.appendChild(startSelection);
				const staffStartIndex = startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.index + 1;
				const staffEndIndex = endBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.index;
				for (let staffIndex = staffStartIndex; staffIndex < staffEndIndex; staffIndex++) {
					const staffBounds = cache.staffSystems[staffIndex];
					const middleSelection = this.uiFacade.createSelectionElement();
					const middleSelectionBounds = new Bounds(staffStartX, staffBounds.visualBounds.y, staffEndX - staffStartX, staffBounds.visualBounds.h);
					eventArgs.highlightBlocks.push(middleSelectionBounds);
					middleSelection.setBounds(middleSelectionBounds.x, middleSelectionBounds.y, middleSelectionBounds.w, middleSelectionBounds.h);
					selectionWrapper.appendChild(middleSelection);
				}
				const endSelection = this.uiFacade.createSelectionElement();
				const endSelectionBounds = new Bounds(staffStartX, endBeat.bounds.barBounds.masterBarBounds.visualBounds.y, endX - staffStartX, endBeat.bounds.barBounds.masterBarBounds.visualBounds.h);
				eventArgs.highlightBlocks.push(endSelectionBounds);
				endSelection.setBounds(endSelectionBounds.x, endSelectionBounds.y, endSelectionBounds.w, endSelectionBounds.h);
				selectionWrapper.appendChild(endSelection);
			} else {
				const selection = this.uiFacade.createSelectionElement();
				const selectionBounds = new Bounds(startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.y, endX - startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.h);
				selection.setBounds(selectionBounds.x, selectionBounds.y, selectionBounds.w, selectionBounds.h);
				eventArgs.highlightBlocks.push(selectionBounds);
				selectionWrapper.appendChild(selection);
			}
			this.playbackRangeHighlightChanged.trigger(eventArgs);
		}
		/**
		* This event is fired whenever a new song is loaded.
		* @remarks
		* This event is fired whenever a new song is loaded or changing due to {@link renderScore} or {@link renderTracks} calls.
		* It is fired after the transposition midi pitches from the settings were applied, but before any midi is generated or rendering is started.
		* This allows any modification of the score before further processing.
		*
		* @eventProperty
		* @category Events - Core
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.scoreLoaded.on((score) => {
		*     updateSongInformationInUi(score);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.ScoreLoaded.On(score =>
		* {
		*     UpdateSongInformationInUi(score);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.scoreLoaded.on { score ->
		*     updateSongInformationInUi(score)
		* }
		* ```
		*
		*/
		scoreLoaded;
		_onScoreLoaded(score) {
			if (this._isDestroyed) return;
			this.scoreLoaded.trigger(score);
			this.uiFacade.triggerEvent(this.container, "scoreLoaded", score);
			if (!this._setupOrDestroyPlayer()) this.loadMidiForScore();
		}
		/**
		* This event is fired when alphaTab was resized and is about to rerender the music notation.
		* @remarks
		* This event is fired when alphaTab was resized and is about to rerender the music notation. Before the re-rendering on resize
		* the settings will be updated in the related components. This means that any changes to the layout options or other display settings are
		* considered. This allows to implement scenarios where maybe the scale or the layout mode dynamically changes along the resizing.
		*
		* @eventProperty
		* @category Events - Core
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.resize.on((args) => {
		*     args.settings.scale = args.newWidth > 1300
		*         ? 1.5
		*         : (args.newWidth > 800) ? 1.3 : 1;
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Resize.On(args =>
		* {
		*     args.Settings.Display.Scale = args.NewWidth > 1300
		*         ? 1.5
		*         : (args.NewWidth > 800) ? 1.3 : 1;
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.resize.on { args ->
		*     args.settings.display.scale = args.newWidth > 1300
		*         ? 1.5
		*         : (args.newWidth > 800) ? 1.3 : 1;
		* });
		* ```
		*
		*/
		resize = new EventEmitterOfT();
		_onResize(e) {
			if (this._isDestroyed) return;
			this.resize.trigger(e);
			this.uiFacade.triggerEvent(this.container, "resize", e);
		}
		/**
		* This event is fired when the rendering of the whole music sheet is starting.
		* @remarks
		* All preparations are completed and the layout and render sequence is about to start.
		*
		* @eventProperty
		* @category Events - Core
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.renderStarted.on(() => {
		*     updateProgressBar("Rendering");
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.RenderStarted.On(resized =>
		* {
		*     UpdateProgressBar("Rendering");
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.renderStarted.on { resized ->
		*     updateProgressBar("Rendering");
		* }
		* ```
		*
		*/
		renderStarted = new EventEmitterOfT();
		_onRenderStarted(resize) {
			if (this._isDestroyed) return;
			this.renderStarted.trigger(resize);
			this.uiFacade.triggerEvent(this.container, "renderStarted", resize);
		}
		/**
		* This event is fired when the rendering of the whole music sheet is finished.
		* @remarks
		* This event is fired when the rendering of the whole music sheet is finished from the render engine side. There might be still tasks open for
		* the display component to visually display the rendered components when this event is notified (e.g. resizing of DOM elements are done).
		*
		* @eventProperty
		* @category Events - Core
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.renderFinished.on(() => {
		*     updateProgressBar("Finishing");
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.RenderFinished.On(() =>
		* {
		*     UpdateProgressBar("Finishing");
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.renderFinished.on {
		*     updateProgressBar("Finishing")
		* }
		* ```
		*
		*/
		renderFinished = new EventEmitterOfT();
		_onRenderFinished(renderingResult) {
			if (this._isDestroyed) return;
			this.renderFinished.trigger(renderingResult);
			this.uiFacade.triggerEvent(this.container, "renderFinished", renderingResult);
		}
		/**
		* This event is fired when the rendering of the whole music sheet is finished, and all handlers of `renderFinished` ran.
		* @remarks
		* If {@link CoreSettings.enableLazyLoading} is enabled not all partial images of the music sheet might be rendered.
		* In this case the `renderFinished` event rather represents that the whole music sheet has been layouted and arranged
		* and every partial image can be requested for rendering. If you neeed more fine-grained access
		* to the actual layouting and rendering progress, you need to look at the low-level apis {@link IScoreRenderer.partialLayoutFinished} and
		* {@link IScoreRenderer.partialRenderFinished} accessible via {@link renderer}.
		*
		* @eventProperty
		* @category Events - Core
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.postRenderFinished.on(() => {
		*     hideLoadingIndicator();
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PostRenderFinished.On(() =>
		* {
		*     HideLoadingIndicator();
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.postRenderFinished.on {
		*     hideLoadingIndicator();
		* }
		* ```
		*
		*/
		postRenderFinished = new EventEmitter();
		_onPostRenderFinished() {
			if (this._isDestroyed) return;
			this._beatVisibilityChecker.bounds = this.boundsLookup;
			this._currentBeat = null;
			this._cursorUpdateTick(this._previousTick, false, 1, true, true);
			if (this._selectionStart) this.highlightPlaybackRange(this._selectionStart.beat, this._selectionEnd.beat);
			this.postRenderFinished.trigger();
			this.uiFacade.triggerEvent(this.container, "postRenderFinished", null);
		}
		/**
		* This event is fired when an error within alphatab occurred.
		*
		* @remarks
		* This event is fired when an error within alphatab occurred. Use this event as global error handler to show errors
		* to end-users. Due to the asynchronous nature of alphaTab, no call to the API will directly throw an error if it fails.
		* Instead a signal to this error handlers will be sent.
		*
		* @eventProperty
		* @category Events - Core
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.error.on((error) {
		*     displayError(error);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.Error.On((error) =>
		* {
		*     DisplayError(error);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.error.on { error ->
		*     displayError(error)
		* }
		* ```
		*
		*/
		error = new EventEmitterOfT();
		/**
		* @internal
		*/
		onError(error) {
			if (this._isDestroyed) return;
			Logger.error("API", "An unexpected error occurred", error);
			this.error.trigger(error);
			this.uiFacade.triggerEvent(this.container, "error", error);
		}
		/**
		* This event is fired when all required data for playback is loaded and ready.
		* @remarks
		* This event is fired when all required data for playback is loaded and ready. The player is ready for playback when
		* all background workers are started, the audio output is initialized, a soundfont is loaded, and a song was loaded into the player as midi file.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playerReady.on(() => {
		*     enablePlayerControls();
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayerReady.On(() =>
		* {
		*     EnablePlayerControls()
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playerReady.on {
		*     enablePlayerControls()
		* }
		* ```
		*/
		get playerReady() {
			return this._player.readyForPlayback;
		}
		_onPlayerReady() {
			if (this._isDestroyed) return;
			this.uiFacade.triggerEvent(this.container, "playerReady", null);
		}
		/**
		* This event is fired when the playback of the whole song finished.
		* @remarks
		* This event is finished regardless on whether looping is enabled or not.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playerFinished.on((args) => {
		*     // speed trainer
		*     api.playbackSpeed = Math.min(1.0, api.playbackSpeed + 0.1);
		* });
		* api.isLooping = true;
		* api.playbackSpeed = 0.5;
		* api.play()
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayerFinished.On(() =>
		* {
		*     // speed trainer
		*     api.PlaybackSpeed = Math.Min(1.0, api.PlaybackSpeed + 0.1);
		* });
		* api.IsLooping = true;
		* api.PlaybackSpeed = 0.5;
		* api.Play();
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playerFinished.on {
		*     // speed trainer
		*     api.playbackSpeed = min(1.0, api.playbackSpeed + 0.1);
		* }
		* api.isLooping = true
		* api.playbackSpeed = 0.5
		* api.play()
		* ```
		*
		*/
		get playerFinished() {
			return this._player.finished;
		}
		_onPlayerFinished() {
			if (this._isDestroyed) return;
			this.uiFacade.triggerEvent(this.container, "playerFinished", null);
		}
		/**
		* This event is fired when the SoundFont needed for playback was loaded.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.soundFontLoaded.on(() => {
		*     hideSoundFontLoadingIndicator();
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.SoundFontLoaded.On(() =>
		* {
		*     HideSoundFontLoadingIndicator();
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...);
		* api.soundFontLoaded.on {
		*     hideSoundFontLoadingIndicator();
		* }
		* ```
		*
		*/
		get soundFontLoaded() {
			return this._player.soundFontLoaded;
		}
		_onSoundFontLoaded() {
			if (this._isDestroyed) return;
			this.uiFacade.triggerEvent(this.container, "soundFontLoaded", null);
		}
		/**
		* This event is fired when a Midi file is being loaded.
		*
		* @remarks
		* This event is fired when a Midi file for the song was generated and is being loaded
		* by the synthesizer. This event can be used to inspect or modify the midi events
		* which will be played for the song. This can be used to generate other visual representations
		* of the song.
		*
		* > [!NOTE]
		* > The generated midi file will NOT contain any metronome and count-in related events. The metronome and
		* > count-in ticks are handled within the synthesizer.
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.2.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.midiLoad.on(file => {
		*     initializePianoPractice(file);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.MidiLoad.On(file =>
		* {
		*     InitializePianoPractice(file);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.midiLoad.on { file ->
		*     initializePianoPractice(file)
		* }
		* ```
		*
		*/
		midiLoad = new EventEmitterOfT();
		_onMidiLoad(e) {
			if (this._isDestroyed) return;
			this.midiLoad.trigger(e);
			this.uiFacade.triggerEvent(this.container, "midiLoad", e);
		}
		/**
		* This event is fired when the Midi file needed for playback was loaded.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.midiLoaded.on(e => {
		*     hideGeneratingAudioIndicator();
		*     updateSongDuration(e.endTime);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.MidiLoaded.On(e =>
		* {
		*     HideGeneratingAudioIndicator();
		*     UpdateSongDuration(e.EndTime);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.midiLoaded.on { e ->
		*     hideGeneratingAudioIndicator()
		*     updateSongDuration(e.endTime)
		* }
		* ```
		*
		*/
		midiLoaded;
		_onMidiLoaded(e) {
			if (this._isDestroyed) return;
			this.midiLoaded.trigger(e);
			this.uiFacade.triggerEvent(this.container, "midiFileLoaded", e);
		}
		/**
		* This event is fired when the playback state changed.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playerStateChanged.on((args) => {
		*     updatePlayerControls(args.state, args.stopped);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayerStateChanged.On(args =>
		* {
		*     UpdatePlayerControls(args);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playerStateChanged.on { args ->
		*     updatePlayerControls(args)
		* }
		* ```
		*
		*/
		get playerStateChanged() {
			return this._player.stateChanged;
		}
		_onPlayerStateChanged(e) {
			if (this._isDestroyed) return;
			if (!e.stopped && e.state === PlayerState.Paused) {
				const currentBeat = this._currentBeat;
				const tickCache = this._tickCache;
				if (currentBeat && tickCache) {
					this._player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
					this.scrollToCursor();
				}
			}
			this.uiFacade.triggerEvent(this.container, "playerStateChanged", e);
		}
		/**
		* This event is fired when the current playback position of the song changed.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playerPositionChanged.on((args) => {
		*     updatePlayerPosition(args);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlayerPositionChanged.On(args =>
		* {
		*     UpdatePlayerPosition(args);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playerPositionChanged.on { args ->
		*     updatePlayerPosition(args)
		* }
		* ```
		*
		*/
		get playerPositionChanged() {
			return this._player.positionChanged;
		}
		_onPlayerPositionChanged(e) {
			if (this._isDestroyed) return;
			this.uiFacade.beginInvoke(() => {
				const cursorSpeed = e.modifiedTempo / e.originalTempo;
				this._cursorUpdateTick(e.currentTick, false, cursorSpeed, false, e.isSeek);
			});
			this.uiFacade.triggerEvent(this.container, "playerPositionChanged", e);
		}
		/**
		* This event is fired when the synthesizer played certain midi events.
		*
		* @remarks
		* This event is fired when the synthesizer played certain midi events. This allows reacing on various low level
		* audio playback elements like notes/rests played or metronome ticks.
		*
		* Refer to the [related guide](https://www.alphatab.net/docs/guides/handling-midi-events) to learn more about this feature.
		*
		* Also note that the provided data models changed significantly in {@version 1.3.0}. We try to provide backwards compatibility
		* until some extend but highly encourage changing to the new models in case of problems.
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.2.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.midiEventsPlayedFilter = [alphaTab.midi.MidiEventType.AlphaTabMetronome];
		* api.midiEventsPlayed.on(function(e) {
		*   for(const midi of e.events) {
		*     if(midi.isMetronome) {
		*       console.log('Metronome tick ' + midi.tick);
		*     }
		*   }
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.MidiEventsPlayedFilter = new MidiEventType[] { AlphaTab.Midi.MidiEventType.AlphaTabMetronome };
		* api.MidiEventsPlayed.On(e =>
		* {
		*   foreach(var midi of e.events)
		*   {
		*     if(midi is AlphaTab.Midi.AlphaTabMetronomeEvent sysex && sysex.IsMetronome)
		*     {
		*       Console.WriteLine("Metronome tick " + midi.Tick);
		*     }
		*   }
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...);
		* api.midiEventsPlayedFilter = alphaTab.collections.List<alphaTab.midi.MidiEventType>( alphaTab.midi.MidiEventType.AlphaTabMetronome )
		* api.midiEventsPlayed.on { e ->
		*   for (midi in e.events) {
		*     if(midi instanceof alphaTab.midi.AlphaTabMetronomeEvent && midi.isMetronome) {
		*       println("Metronome tick " + midi.tick);
		*     }
		*   }
		* }
		* ```
		* @see {@link MidiEvent}
		* @see {@link TimeSignatureEvent}
		* @see {@link AlphaTabMetronomeEvent}
		* @see {@link AlphaTabRestEvent}
		* @see {@link NoteOnEvent}
		* @see {@link NoteOffEvent}
		* @see {@link ControlChangeEvent}
		* @see {@link ProgramChangeEvent}
		* @see {@link TempoChangeEvent}
		* @see {@link PitchBendEvent}
		* @see {@link NoteBendEvent}
		* @see {@link EndOfTrackEvent}
		* @see {@link MetaEvent}
		* @see {@link MetaDataEvent}
		* @see {@link MetaNumberEvent}
		* @see {@link Midi20PerNotePitchBendEvent}
		* @see {@link SystemCommonEvent}
		* @see {@link SystemExclusiveEvent}
		*/
		get midiEventsPlayed() {
			return this._player.midiEventsPlayed;
		}
		_onMidiEventsPlayed(e) {
			if (this._isDestroyed) return;
			this.uiFacade.triggerEvent(this.container, "midiEventsPlayed", e);
		}
		/**
		* This event is fired when the playback range changed.
		*
		* @eventProperty
		* @category Events - Player
		* @since 1.2.3
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.playbackRangeChanged.on((args) => {
		*     if (args.playbackRange) {
		*         highlightRangeInProgressBar(args.playbackRange.startTick, args.playbackRange.endTick);
		*     } else {
		*         clearHighlightInProgressBar();
		*     }
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.PlaybackRangeChanged.On(args =>
		* {
		*     if (args.PlaybackRange != null)
		*     {
		*         HighlightRangeInProgressBar(args.PlaybackRange.StartTick, args.PlaybackRange.EndTick);
		*     }
		*     else
		*     {
		*         ClearHighlightInProgressBar();
		*     }
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.playbackRangeChanged.on { args ->
		*     val playbackRange = args.playbackRange
		*     if (playbackRange != null) {
		*         highlightRangeInProgressBar(playbackRange.startTick, playbackRange.endTick)
		*     } else {
		*         clearHighlightInProgressBar()
		*     }
		* }
		* ```
		*
		*/
		get playbackRangeChanged() {
			return this._player.playbackRangeChanged;
		}
		_onPlaybackRangeChanged(e) {
			if (this._isDestroyed) return;
			this.uiFacade.triggerEvent(this.container, "playbackRangeChanged", e);
		}
		/**
		* This event is fired when a settings update was requested.
		*
		* @eventProperty
		* @category Events - Core
		* @since 1.6.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.settingsUpdated.on(() => {
		*     updateSettingsUI(api.settings);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* api.SettingsUpdated.On(() =>
		* {
		*     UpdateSettingsUI(api.settings);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* val api = AlphaTabApi<MyControl>(...)
		* api.SettingsUpdated.on {
		*     updateSettingsUI(api.settings)
		* }
		* ```
		*
		*/
		settingsUpdated = new EventEmitter();
		_onSettingsUpdated() {
			if (this._isDestroyed) return;
			this.settingsUpdated.trigger();
			this.uiFacade.triggerEvent(this.container, "settingsUpdated", null);
		}
		/**
		* Loads and lists the available output devices which can be used by the player.
		* @returns the list of available devices or an empty list if there are no permissions, or the player is not enabled.
		*
		* @remarks
		* Will request permissions if needed.
		*
		* The values provided, can be passed into {@link setOutputDevice} to change dynamically the output device on which
		* the sound is played.
		*
		* In the web version this functionality relies on experimental APIs and might not yet be available in all browsers. https://caniuse.com/mdn-api_audiocontext_sinkid
		* @category Methods - Player
		* @since 1.5.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* const devices = await api.enumerateOutputDevices();
		*
		* buildDeviceSelector(devices, async selectedDevice => {
		*   await api.setOutputDevice(selectedDevice);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* var devices = await api.EnumerateOutputDevices();
		*
		* BuildDeviceSelector(devices, async selectedDevice => {
		*   await api.SetOutputDevice(selectedDevice);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* fun init() = kotlinx.coroutines.runBlocking {
		*   val api = AlphaTabApi<MyControl>(...)
		*   val devices = api.enumerateOutputDevices().await()
		*
		*   buildDeviceSelector(devices, fun (selectedDevice) {
		*     suspend {
		*       await api.setOutputDevice(selectedDevice)
		*     }
		*   });
		* }
		* ```
		*/
		async enumerateOutputDevices() {
			return await this._player.output.enumerateOutputDevices();
		}
		/**
		* Changes the output device which should be used for playing the audio (player must be enabled).
		* @param device The output device to use, or null to switch to the default device.
		*
		* @remarks
		* Use {@link enumerateOutputDevices} to load the list of available devices.
		*
		* In the web version this functionality relies on experimental APIs and might not yet be available in all browsers. https://caniuse.com/mdn-api_audiocontext_sinkid
		* @category Methods - Player
		* @since 1.5.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* const devices = await api.enumerateOutputDevices();
		*
		* buildDeviceSelector(devices, async selectedDevice => {
		*   await api.setOutputDevice(selectedDevice);
		* });
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* var devices = await api.EnumerateOutputDevices();
		*
		* BuildDeviceSelector(devices, async selectedDevice => {
		*   await api.SetOutputDevice(selectedDevice);
		* });
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* fun init() = kotlinx.coroutines.runBlocking {
		*   val api = AlphaTabApi<MyControl>(...)
		*   val devices = api.enumerateOutputDevices().await()
		*
		*   buildDeviceSelector(devices, fun (selectedDevice) {
		*     suspend {
		*       await api.setOutputDevice(selectedDevice)
		*     }
		*   });
		* }
		* ```
		*/
		async setOutputDevice(device) {
			await this._player.output.setOutputDevice(device);
		}
		/**
		* The currently configured output device if changed via {@link setOutputDevice}.
		* @returns The custom configured output device which was set via {@link setOutputDevice} or `null`
		* if the default outputDevice is used.
		* The output device might change dynamically if devices are connected/disconnected (e.g. bluetooth headset).
		*
		* @remarks
		* Assumes {@link setOutputDevice} has been used.
		* In the web version this functionality relies on experimental APIs and might not yet be available in all browsers. https://caniuse.com/mdn-api_audiocontext_sinkid
		*
		* @category Methods - Player
		* @since 1.5.0
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* updateOutputDeviceUI(await api.getOutputDevice())
		* ```
		*
		* @example
		* C#
		* ```cs
		* var api = new AlphaTabApi<MyControl>(...);
		* UpdateOutputDeviceUI(await api.GetOutputDevice())
		* ```
		*
		* @example
		* Android
		* ```kotlin
		* fun init() = kotlinx.coroutines.runBlocking {
		*   val api = AlphaTabApi<MyControl>(...)
		*   updateOutputDeviceUI(api.getOutputDevice().await())
		* }
		* ```
		*
		*/
		async getOutputDevice() {
			return await this._player.output.getOutputDevice();
		}
		/**
		* Starts the audio export for the currently loaded song.
		* @remarks
		* This will not export or use any backing track media but will always use the synthesizer to generate the output.
		* This method works with any PlayerMode active but changing the mode during export can lead to unexpected side effects.
		*
		* See [Audio Export](https://www.alphatab.net/docs/guides/audio-export) for further guidance how to use this feature.
		*
		* @param options The export options.
		* @category Methods - Player
		* @since 1.6.0
		* @returns An exporter instance to export the audio in a streaming fashion.
		*/
		async exportAudio(options) {
			if (!this.score) throw new AlphaTabError(AlphaTabErrorType.General, "No song loaded");
			let exporter;
			switch (this._actualPlayerMode) {
				case PlayerMode.EnabledSynthesizer:
					exporter = this.uiFacade.createWorkerAudioExporter(this._player.instance);
					break;
				default:
					exporter = this.uiFacade.createWorkerAudioExporter(null);
					break;
			}
			const score = this.score;
			const midiFile = new MidiFile();
			const handler = new AlphaSynthMidiFileHandler(midiFile);
			const generator = new MidiFileGenerator(score, this.settings, handler);
			generator.applyTranspositionPitches = false;
			generator.generate();
			const optionsWithChannels = new AudioExportOptions();
			optionsWithChannels.soundFonts = options.soundFonts;
			optionsWithChannels.sampleRate = options.sampleRate;
			optionsWithChannels.useSyncPoints = options.useSyncPoints;
			optionsWithChannels.masterVolume = options.masterVolume;
			optionsWithChannels.metronomeVolume = options.metronomeVolume;
			optionsWithChannels.playbackRange = options.playbackRange;
			for (const [trackIndex, volume] of options.trackVolume) if (trackIndex < this.score.tracks.length) {
				const track = this.score.tracks[trackIndex];
				optionsWithChannels.trackVolume.set(track.playbackInfo.primaryChannel, volume);
				optionsWithChannels.trackVolume.set(track.playbackInfo.secondaryChannel, volume);
			}
			for (const [trackIndex, semitones] of options.trackTranspositionPitches) if (trackIndex < this.score.tracks.length) {
				const track = this.score.tracks[trackIndex];
				optionsWithChannels.trackTranspositionPitches.set(track.playbackInfo.primaryChannel, semitones);
				optionsWithChannels.trackTranspositionPitches.set(track.playbackInfo.secondaryChannel, semitones);
			}
			await exporter.initialize(optionsWithChannels, midiFile, generator.syncPoints, generator.transpositionPitches);
			return exporter;
		}
	};
	//#endregion
	//#region src/ProgressEventArgs.ts
	/**
	* Represents the progress of any data being loaded.
	* @public
	*/
	var ProgressEventArgs = class {
		/**
		* Gets the currently loaded bytes.
		*/
		loaded;
		/**
		* Gets the total number of bytes to load.
		*/
		total;
		/**
		* Initializes a new instance of the {@link ProgressEventArgs} class.
		* @param loaded
		* @param total
		*/
		constructor(loaded, total) {
			this.loaded = loaded;
			this.total = total;
		}
	};
	//#endregion
	//#region src/platform/javascript/AlphaTabApi.ts
	/**
	* @target web
	* @public
	*/
	var AlphaTabApi = class AlphaTabApi extends AlphaTabApiBase {
		/**
		* Initializes a new instance of the {@link AlphaTabApi} class.
		* @param element The HTML element into which alphaTab should be initialized.
		* @param settings The settings to use.
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'), { display: { scale: 1.2 }});
		* ```
		*/
		constructor(element, options) {
			super(new BrowserUiFacade(element), options);
		}
		/**
		* @inheritdoc
		*/
		tex(tex, tracks) {
			const browser = this.uiFacade;
			super.tex(tex, browser.parseTracks(tracks));
		}
		/**
		* Opens a popup window with the rendered music notation for printing.
		* @param width An optional custom width as CSS width that should be used. Best is to use a CSS width that is suitable for your preferred page size.
		* @param additionalSettings An optional parameter to specify additional setting values which should be respected during printing ({@since 1.2.0})
		* @remarks
		* Opens a popup window with the rendered music notation for printing. The default display of alphaTab in the browser is not very
		* suitable for printing. The items are lazy loaded, the width can be dynamic, and the scale might be better suitable for screens.
		* This function opens a popup window which is filled with a by-default A4 optimized view of the rendered score:
		*
		* * Lazy loading is disabled
		* * The scale is reduced to 0.8
		* * The stretch force is reduced to 0.8
		* * The width is optimized to A4. Portrait if the page-layout is used, landscape if the horizontal-layout is used.
		*
		* @category Methods - Core
		* @since 0.9.4
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.print();
		* api.print(undefined, { display: { barsPerRow: 5 } });
		* ```
		*/
		print(width, additionalSettings = null) {
			const preview = window.open("", "", "width=0,height=0");
			const a4 = preview.document.createElement("div");
			if (width) a4.style.width = width;
			else if (this.settings.display.layoutMode === LayoutMode.Horizontal) a4.style.width = "297mm";
			else a4.style.width = "210mm";
			preview.document.write(`
        <!DOCTYPE html>
        <html>
          <head>
            <style>
            .at-surface {
                width: auto !important;
                height: auto !important;
            }
            .at-surface > div {
                position: relative!important;
                left: auto !important;
                top: auto !important;
                break-inside: avoid;
            }
            </style>
          </head>
          <body></body>
        </html>
        `);
			const score = this.score;
			if (score) {
				if (score.artist && score.title) preview.document.title = `${score.title} - ${score.artist}`;
				else if (score.title) preview.document.title = `${score.title}`;
			}
			preview.document.body.appendChild(a4);
			const dualScreenLeft = typeof window.screenLeft !== "undefined" ? window.screenLeft : window.left;
			const dualScreenTop = typeof window.screenTop !== "undefined" ? window.screenTop : window.top;
			const screenWidth = "innerWidth" in window ? window.innerWidth : "clientWidth" in document.documentElement ? document.documentElement.clientWidth : window.screen.width;
			const screenHeight = "innerHeight" in window ? window.innerHeight : "clientHeight" in document.documentElement ? document.documentElement.clientHeight : window.screen.height;
			const w = a4.offsetWidth + 50;
			const h = window.innerHeight;
			const left = (screenWidth / 2 | 0) - (w / 2 | 0) + dualScreenLeft;
			const top = (screenHeight / 2 | 0) - (h / 2 | 0) + dualScreenTop;
			preview.resizeTo(w, h);
			preview.moveTo(left, top);
			preview.focus();
			const settings = JsonConverter.jsObjectToSettings(JsonConverter.settingsToJsObject(this.settings));
			settings.core.enableLazyLoading = false;
			settings.core.useWorkers = true;
			settings.core.file = null;
			settings.core.tracks = null;
			settings.player.enableCursor = false;
			settings.player.playerMode = PlayerMode.Disabled;
			settings.player.enableElementHighlighting = false;
			settings.player.enableUserInteraction = false;
			settings.player.soundFont = null;
			settings.display.scale = .8;
			settings.display.stretchForce = .8;
			SettingsSerializer.fromJson(settings, additionalSettings);
			const alphaTab = new AlphaTabApi(a4, settings);
			preview.onunload = () => {
				alphaTab.destroy();
			};
			alphaTab.renderer.postRenderFinished.on(() => {
				preview.print();
			});
			alphaTab.renderTracks(this.tracks);
		}
		/**
		* Generates an SMF1.0 file and downloads it
		* @remarks
		* Generates a SMF1.0 compliant MIDI file of the currently loaded song and starts the download of it.
		* Please be aware that SMF1.0 does not support bends per note which might result in wrong bend effects
		* in case multiple bends are applied on the same beat (e.g. two notes bending or vibrato + bends).
		*
		* @category Methods - Core
		* @since 1.3.0
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.downloadMidi();
		* ```
		*/
		downloadMidi(format = MidiFileFormat.SingleTrackMultiChannel) {
			if (!this.score) return;
			const midiFile = new MidiFile();
			midiFile.format = format;
			const handler = new AlphaSynthMidiFileHandler(midiFile, true);
			new MidiFileGenerator(this.score, this.settings, handler).generate();
			const binary = midiFile.toBinary();
			const fileName = !this.score.title ? "File.mid" : `${this.score.title}.mid`;
			const dlLink = document.createElement("a");
			dlLink.download = fileName;
			const blob = new Blob([binary], { type: "audio/midi" });
			dlLink.href = URL.createObjectURL(blob);
			dlLink.style.display = "none";
			document.body.appendChild(dlLink);
			dlLink.click();
			document.body.removeChild(dlLink);
		}
		/**
		* @inheritdoc
		*/
		changeTrackMute(tracks, mute) {
			const trackList = this._trackIndexesToTracks(this.uiFacade.parseTracks(tracks));
			super.changeTrackMute(trackList, mute);
		}
		/**
		* @inheritdoc
		*/
		changeTrackSolo(tracks, solo) {
			const trackList = this._trackIndexesToTracks(this.uiFacade.parseTracks(tracks));
			super.changeTrackSolo(trackList, solo);
		}
		/**
		* @inheritdoc
		*/
		changeTrackVolume(tracks, volume) {
			const trackList = this._trackIndexesToTracks(this.uiFacade.parseTracks(tracks));
			super.changeTrackVolume(trackList, volume);
		}
		_trackIndexesToTracks(trackIndexes) {
			if (!this.score) return [];
			const tracks = [];
			if (trackIndexes.length === 1 && trackIndexes[0] === -1) for (const track of this.score.tracks) tracks.push(track);
			else for (const index of trackIndexes) if (index >= 0 && index < this.score.tracks.length) tracks.push(this.score.tracks[index]);
			return tracks;
		}
		/**
		* This event is fired when the SoundFont is being loaded.
		* @remarks
		* This event is fired when the SoundFont is being loaded and reports the progress accordingly.
		*
		* @eventProperty
		* @category Events - Player
		* @since 0.9.4
		*
		* @example
		* JavaScript
		* ```js
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
		* api.soundFontLoad.on((e) => {
		*     updateProgress(e.loaded, e.total);
		* });
		* ```
		*/
		soundFontLoad = new EventEmitterOfT();
		/**
		* Triggers a load of the soundfont from the given URL.
		* @param url The URL from which to load the soundfont
		* @param append Whether to fully replace or append the data from the given soundfont.
		* @category Methods - Player
		* @since 0.9.4
		*/
		loadSoundFontFromUrl(url, append) {
			const player = this.player;
			if (!player) return;
			Logger.debug("AlphaSynth", `Start loading Soundfont from url ${url}`);
			const request = new XMLHttpRequest();
			request.open("GET", url, true, null, null);
			request.responseType = "arraybuffer";
			request.onload = (_) => {
				const buffer = new Uint8Array(request.response);
				this.loadSoundFont(buffer, append);
			};
			request.onerror = (e) => {
				Logger.error("AlphaSynth", `Loading failed: ${e.message}`);
				player.soundFontLoadFailed.trigger(new FileLoadError(e.message, request));
			};
			request.onprogress = (e) => {
				Logger.debug("AlphaSynth", `Soundfont downloading: ${e.loaded}/${e.total} bytes`);
				const args = new ProgressEventArgs(e.loaded, e.total);
				this.soundFontLoad.trigger(args);
				this.uiFacade.triggerEvent(this.container, "soundFontLoad", args);
			};
			request.send();
		}
	};
	//#endregion
	//#region src/platform/javascript/JQueryAlphaTab.ts
	/**
	* @target web
	* @deprecated Migrate to {@link AlphaTabApi}.
	* @internal
	*/
	var JQueryAlphaTab = class {
		exec(element, method, args) {
			if (typeof method !== "string") {
				args = [method];
				method = "init";
			}
			if (method.charCodeAt(0) === 95 || method === "exec") return null;
			const jElement = new jQuery(element);
			const context = jElement.data("alphaTab");
			if (method === "destroy" && !context) return null;
			if (method !== "init" && !context) throw new Error("alphaTab not initialized");
			const apiMethod = this[method];
			if (apiMethod) {
				const realArgs = [jElement, context].concat(args);
				return apiMethod.apply(this, realArgs);
			}
			Logger.error("Api", `Method '${method}' does not exist on jQuery.alphaTab`);
			return null;
		}
		init(element, context, options) {
			if (!context) {
				context = new AlphaTabApi(element[0], options);
				element.data("alphaTab", context);
				for (const listener of this._initListeners) listener(element, context, options);
			}
		}
		destroy(element, context) {
			element.removeData("alphaTab");
			context.destroy();
		}
		print(_element, context, width, additionalSettings) {
			context.print(width, additionalSettings);
		}
		load(_element, context, data, tracks) {
			return context.load(data, tracks);
		}
		render(_element, context) {
			context.render();
		}
		renderScore(_element, context, score, tracks) {
			context.renderScore(score, tracks);
		}
		renderTracks(_element, context, tracks) {
			context.renderTracks(tracks);
		}
		invalidate(_element, context) {
			context.render();
		}
		tex(_element, context, tex, tracks) {
			context.tex(tex, tracks);
		}
		muteTrack(_element, context, tracks, mute) {
			context.changeTrackMute(tracks, mute);
		}
		soloTrack(_element, context, tracks, solo) {
			context.changeTrackSolo(tracks, solo);
		}
		trackVolume(_element, context, tracks, volume) {
			context.changeTrackVolume(tracks, volume);
		}
		loadSoundFont(_element, context, value, append) {
			context.loadSoundFont(value, append);
		}
		resetSoundFonts(_element, context) {
			context.resetSoundFonts();
		}
		pause(_element, context) {
			context.pause();
		}
		play(_element, context) {
			return context.play();
		}
		playPause(_element, context) {
			context.playPause();
		}
		stop(_element, context) {
			context.stop();
		}
		api(_element, context) {
			return context;
		}
		player(_element, context) {
			return context.player;
		}
		isReadyForPlayback(_element, context) {
			return context.isReadyForPlayback;
		}
		playerState(_element, context) {
			return context.playerState;
		}
		masterVolume(_element, context, masterVolume) {
			if (typeof masterVolume === "number") context.masterVolume = masterVolume;
			return context.masterVolume;
		}
		metronomeVolume(_element, context, metronomeVolume) {
			if (typeof metronomeVolume === "number") context.metronomeVolume = metronomeVolume;
			return context.metronomeVolume;
		}
		countInVolume(_element, context, countInVolume) {
			if (typeof countInVolume === "number") context.countInVolume = countInVolume;
			return context.countInVolume;
		}
		midiEventsPlayedFilter(_element, context, midiEventsPlayedFilter) {
			if (Array.isArray(midiEventsPlayedFilter)) context.midiEventsPlayedFilter = midiEventsPlayedFilter;
			return context.midiEventsPlayedFilter;
		}
		playbackSpeed(_element, context, playbackSpeed) {
			if (typeof playbackSpeed === "number") context.playbackSpeed = playbackSpeed;
			return context.playbackSpeed;
		}
		tickPosition(_element, context, tickPosition) {
			if (typeof tickPosition === "number") context.tickPosition = tickPosition;
			return context.tickPosition;
		}
		timePosition(_element, context, timePosition) {
			if (typeof timePosition === "number") context.timePosition = timePosition;
			return context.timePosition;
		}
		loop(_element, context, loop) {
			if (typeof loop === "boolean") context.isLooping = loop;
			return context.isLooping;
		}
		renderer(_element, context) {
			return context.renderer;
		}
		score(_element, context) {
			return context.score;
		}
		settings(_element, context) {
			return context.settings;
		}
		tracks(_element, context) {
			return context.tracks;
		}
		_initListeners = [];
		_oninit(listener) {
			this._initListeners.push(listener);
		}
		static restore(selector) {
			new jQuery(selector).empty().removeData("alphaTab");
		}
	};
	//#endregion
	//#region \0@oxc-project+runtime@0.132.0/helpers/usingCtx.js
	function _usingCtx() {
		var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
			var n = Error();
			return n.name = "SuppressedError", n.error = r, n.suppressed = e, n;
		}, e = {}, n = [];
		function using(r, e) {
			if (null != e) {
				if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
				if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
				if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o;
				if ("function" != typeof o) throw new TypeError("Object is not disposable.");
				t && (o = function o() {
					try {
						t.call(e);
					} catch (r) {
						return Promise.reject(r);
					}
				}), n.push({
					v: e,
					d: o,
					a: r
				});
			} else r && n.push({
				d: e,
				a: r
			});
			return e;
		}
		return {
			e,
			u: using.bind(null, !1),
			a: using.bind(null, !0),
			d: function d() {
				var o, t = this.e, s = 0;
				function next() {
					for (; o = n.pop();) try {
						if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
						if (o.d) {
							var r = o.d.call(o.v);
							if (o.a) return s |= 2, Promise.resolve(r).then(next, err);
						} else s |= 1;
					} catch (r) {
						return err(r);
					}
					if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
					if (t !== e) throw t;
				}
				function err(n) {
					return t = t !== e ? new r(n, t) : n, next();
				}
				return next();
			}
		};
	}
	//#endregion
	//#region src/platform/skia/SkiaCanvas.ts
	/**
	* A canvas implementation using alphaSkia as rendering backend
	* @partial
	* @internal
	*/
	var SkiaCanvas = class SkiaCanvas {
		/**
		* @target web
		* @delegated csharp
		* @delegated kotlin
		*/
		static _alphaSkia;
		static _defaultMusicTextStyle = null;
		/**
		* @target web
		* @partial
		*/
		static enable(musicFontData, alphaSkia) {
			SkiaCanvas._alphaSkia = alphaSkia;
			SkiaCanvas.initializeMusicFont(SkiaCanvas._alphaSkia.AlphaSkiaTypeface.register(musicFontData));
		}
		static initializeMusicFont(musicFont) {
			SkiaCanvas._defaultMusicTextStyle = new SkiaCanvas._alphaSkia.AlphaSkiaTextStyle([musicFont.familyName], musicFont.weight, musicFont.isItalic);
		}
		static registerFont(fontData, fontInfo) {
			const typeface = SkiaCanvas._alphaSkia.AlphaSkiaTypeface.register(fontData.buffer);
			if (!fontInfo) fontInfo = Font.withFamilyList([typeface.familyName], 12, typeface.isItalic ? FontStyle.Italic : FontStyle.Plain, typeface.weight > 400 ? FontWeight.Bold : FontWeight.Regular);
			return fontInfo;
		}
		_canvas;
		_color = new Color(0, 0, 0, 0);
		_lineWidth = 0;
		_textStyle = null;
		_scale = 1;
		_textStyles = /* @__PURE__ */ new Map();
		_font = new Font("Arial", 10, FontStyle.Plain);
		_musicTextStyle = null;
		settings;
		get font() {
			return this._font;
		}
		set font(value) {
			if (this._font === value) return;
			this._font = value;
			const key = this._textStyleKey(value);
			if (this._textStyles.has(key)) this._textStyle = this._textStyles.get(key);
			else {
				const textStyle = new SkiaCanvas._alphaSkia.AlphaSkiaTextStyle(value.families, value.weight === FontWeight.Bold ? 700 : 400, value.isItalic);
				this._textStyles.set(key, textStyle);
				this._textStyle = textStyle;
			}
		}
		_textStyleKey(font) {
			return [
				...font.families,
				font.weight.toString(),
				font.isItalic ? "italic" : "upright"
			].join("_");
		}
		constructor() {
			this._canvas = new SkiaCanvas._alphaSkia.AlphaSkiaCanvas();
			this.color = new Color(0, 0, 0, 255);
		}
		destroy() {
			this._canvas[Symbol.dispose]();
			for (const textStyle of this._textStyles.values()) textStyle[Symbol.dispose]();
		}
		onRenderFinished() {
			return null;
		}
		beginRender(width, height) {
			this._scale = this.settings.display.scale;
			this._canvas.beginRender(width, height, Environment.highDpiFactor);
			const customFont = this.settings.display.resources.smuflFontFamilyName;
			if (customFont && customFont !== SkiaCanvas._defaultMusicTextStyle.familyNames[0]) if (!this._textStyles.has(customFont)) {
				this._musicTextStyle = new SkiaCanvas._alphaSkia.AlphaSkiaTextStyle([customFont], SkiaCanvas._defaultMusicTextStyle.weight, SkiaCanvas._defaultMusicTextStyle.isItalic);
				this._textStyles.set(customFont, this._musicTextStyle);
			} else this._musicTextStyle = this._textStyles.get(customFont);
			else this._musicTextStyle = SkiaCanvas._defaultMusicTextStyle;
		}
		endRender() {
			return this._canvas.endRender();
		}
		get color() {
			return this._color;
		}
		set color(value) {
			if (this._color.rgba === value.rgba) return;
			this._color = value;
			this._canvas.color = SkiaCanvas._alphaSkia.AlphaSkiaCanvas.rgbaToColor(value.r, value.g, value.b, value.a);
		}
		get lineWidth() {
			return this._lineWidth;
		}
		set lineWidth(value) {
			this._lineWidth = value;
			this._canvas.lineWidth = value;
		}
		fillRect(x, y, w, h) {
			if (w > 0) this._canvas.fillRect(x * this._scale, y * this._scale, w * this._scale, h * this._scale);
		}
		strokeRect(x, y, w, h) {
			const blurOffset = this.lineWidth % 2 === 0 ? 0 : .5;
			this._canvas.strokeRect(x * this._scale + blurOffset, y * this._scale + blurOffset, w * this._scale, h * this._scale);
		}
		beginPath() {
			this._canvas.beginPath();
		}
		closePath() {
			this._canvas.closePath();
		}
		moveTo(x, y) {
			this._canvas.moveTo(x * this._scale, y * this._scale);
		}
		lineTo(x, y) {
			this._canvas.lineTo(x * this._scale, y * this._scale);
		}
		quadraticCurveTo(cpx, cpy, x, y) {
			this._canvas.quadraticCurveTo(cpx * this._scale, cpy * this._scale, x * this._scale, y * this._scale);
		}
		bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, x, y) {
			this._canvas.bezierCurveTo(cp1X * this._scale, cp1Y * this._scale, cp2X * this._scale, cp2Y * this._scale, x * this._scale, y * this._scale);
		}
		fillCircle(x, y, radius) {
			this._canvas.fillCircle(x * this._scale, y * this._scale, radius * this._scale);
		}
		strokeCircle(x, y, radius) {
			this._canvas.strokeCircle(x * this._scale, y * this._scale, radius * this._scale);
		}
		fill() {
			this._canvas.fill();
		}
		stroke() {
			this._canvas.stroke();
		}
		textAlign = TextAlign.Left;
		textBaseline = TextBaseline.Top;
		beginGroup(_identifier) {}
		endGroup() {}
		fillText(text, x, y) {
			if (text.length === 0) return;
			let textAlign = SkiaCanvas._alphaSkia.AlphaSkiaTextAlign.Left;
			switch (this.textAlign) {
				case TextAlign.Left:
					textAlign = SkiaCanvas._alphaSkia.AlphaSkiaTextAlign.Left;
					break;
				case TextAlign.Center:
					textAlign = SkiaCanvas._alphaSkia.AlphaSkiaTextAlign.Center;
					break;
				case TextAlign.Right:
					textAlign = SkiaCanvas._alphaSkia.AlphaSkiaTextAlign.Right;
					break;
			}
			let textBaseline = SkiaCanvas._alphaSkia.AlphaSkiaTextBaseline.Top;
			switch (this.textBaseline) {
				case TextBaseline.Top:
					textBaseline = SkiaCanvas._alphaSkia.AlphaSkiaTextBaseline.Top;
					break;
				case TextBaseline.Middle:
					textBaseline = SkiaCanvas._alphaSkia.AlphaSkiaTextBaseline.Middle;
					break;
				case TextBaseline.Bottom:
					textBaseline = SkiaCanvas._alphaSkia.AlphaSkiaTextBaseline.Bottom;
					break;
				case TextBaseline.Alphabetic:
					textBaseline = SkiaCanvas._alphaSkia.AlphaSkiaTextBaseline.Alphabetic;
					break;
			}
			this._canvas.fillText(text, this._textStyle, this._font.size * this._scale, x * this._scale, y * this._scale, textAlign, textBaseline);
		}
		measureText(text) {
			try {
				var _usingCtx$4 = _usingCtx();
				const metrics = _usingCtx$4.u(this._canvas.measureText(text, this._textStyle, this._font.size, SkiaCanvas._alphaSkia.AlphaSkiaTextAlign.Left, SkiaCanvas._alphaSkia.AlphaSkiaTextBaseline.Alphabetic));
				const [width, height] = this._getTextWidthAndHeight(metrics, text);
				return new MeasuredText(width, height);
			} catch (_) {
				_usingCtx$4.e = _;
			} finally {
				_usingCtx$4.d();
			}
		}
		_getTextWidthAndHeight(metrics, text) {
			let width = metrics.width;
			if (text.length > 0 && width < 1) for (let i = 0; i < 5; i++) {
				width = metrics.width;
				if (width > 1) break;
			}
			const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
			return [width, height];
		}
		fillMusicFontSymbol(x, y, relativeScale, symbol, centerAtPosition) {
			if (symbol === MusicFontSymbol.None) return;
			this._fillMusicFontSymbolText(x, y, relativeScale, String.fromCharCode(symbol), centerAtPosition);
		}
		fillMusicFontSymbols(x, y, relativeScale, symbols, centerAtPosition) {
			let s = "";
			for (const symbol of symbols) if (symbol !== MusicFontSymbol.None) s += String.fromCharCode(symbol);
			this._fillMusicFontSymbolText(x, y, relativeScale, s, centerAtPosition);
		}
		_fillMusicFontSymbolText(x, y, relativeScale, symbols, centerAtPosition) {
			this._canvas.fillText(symbols, this._musicTextStyle, this.settings.display.resources.engravingSettings.musicFontSize * this._scale * relativeScale, x * this._scale, y * this._scale, centerAtPosition ? SkiaCanvas._alphaSkia.AlphaSkiaTextAlign.Center : SkiaCanvas._alphaSkia.AlphaSkiaTextAlign.Left, SkiaCanvas._alphaSkia.AlphaSkiaTextBaseline.Alphabetic);
		}
		beginRotate(centerX, centerY, angle) {
			this._canvas.beginRotate(centerX * this._scale, centerY * this._scale, angle);
		}
		endRotate() {
			this._canvas.endRotate();
		}
	};
	//#endregion
	//#region src/platform/svg/SvgCanvas.ts
	/**
	* A canvas implementation storing SVG data
	* @internal
	*/
	var SvgCanvas = class SvgCanvas {
		buffer = "";
		_currentPath = "";
		_currentPathIsEmpty = true;
		scale = 1;
		color = new Color(255, 255, 255, 255);
		lineWidth = 1;
		font = new Font("Arial", 10, FontStyle.Plain);
		textAlign = TextAlign.Left;
		textBaseline = TextBaseline.Top;
		settings;
		destroy() {}
		beginRender(width, height) {
			this.scale = this.settings.display.scale;
			this.buffer = `<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width | 0}px" height="${height | 0}px" class="at-surface-svg">\n`;
			this._currentPath = "";
			this._currentPathIsEmpty = true;
			this.textBaseline = TextBaseline.Top;
		}
		beginGroup(identifier) {
			this.buffer += `<g class="${identifier}">`;
		}
		endGroup() {
			this.buffer += "</g>";
		}
		endRender() {
			this.buffer += "</svg>";
			return this.buffer;
		}
		fillRect(x, y, w, h) {
			if (w > 0) this.buffer += `<rect x="${x * this.scale}" y="${y * this.scale}" width="${w * this.scale}" height="${h * this.scale}" fill="${this.color.rgba}" />\n`;
		}
		strokeRect(x, y, w, h) {
			const blurOffset = this.lineWidth * this.scale % 2 === 0 ? 0 : .5;
			this.buffer += `<rect x="${x * this.scale + blurOffset}" y="${y * this.scale + blurOffset}" width="${w * this.scale}" height="${h * this.scale}" stroke="${this.color.rgba}"`;
			if (this.lineWidth !== 1) this.buffer += ` stroke-width="${this.lineWidth * this.scale}"`;
			this.buffer += " fill=\"transparent\" />\n";
		}
		beginPath() {}
		closePath() {
			this._currentPath += " z";
		}
		moveTo(x, y) {
			this._currentPath += ` M${x * this.scale},${y * this.scale}`;
		}
		lineTo(x, y) {
			this._currentPathIsEmpty = false;
			this._currentPath += ` L${x * this.scale},${y * this.scale}`;
		}
		quadraticCurveTo(cpx, cpy, x, y) {
			this._currentPathIsEmpty = false;
			this._currentPath += ` Q${cpx * this.scale},${cpy * this.scale},${x * this.scale},${y * this.scale}`;
		}
		bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, x, y) {
			this._currentPathIsEmpty = false;
			this._currentPath += ` C${cp1X * this.scale},${cp1Y * this.scale},${cp2X * this.scale},${cp2Y * this.scale},${x * this.scale},${y * this.scale}`;
		}
		fillCircle(x, y, radius) {
			this._currentPathIsEmpty = false;
			x *= this.scale;
			y *= this.scale;
			radius *= this.scale;
			this._currentPath += ` M${x - radius},${y} A1,1 0 0,0 ${x + radius},${y} A1,1 0 0,0 ${x - radius},${y} z`;
			this.fill();
		}
		strokeCircle(x, y, radius) {
			this._currentPathIsEmpty = false;
			x *= this.scale;
			y *= this.scale;
			radius *= this.scale;
			this._currentPath += ` M${x - radius},${y} A1,1 0 0,0 ${x + radius},${y} A1,1 0 0,0 ${x - radius},${y} z`;
			this.stroke();
		}
		fill() {
			if (!this._currentPathIsEmpty) {
				this.buffer += `<path d="${this._currentPath}"`;
				if (this.color.rgba !== "#000000") this.buffer += ` fill="${this.color.rgba}"`;
				this.buffer += " style=\"stroke: none\"/>";
			}
			this._currentPath = "";
			this._currentPathIsEmpty = true;
		}
		stroke() {
			if (!this._currentPathIsEmpty) {
				let s = `<path d="${this._currentPath}" stroke="${this.color.rgba}"`;
				if (this.lineWidth !== 1 || this.scale !== 1) s += ` stroke-width="${this.lineWidth * this.scale}"`;
				s += " style=\"fill: none\" />";
				this.buffer += s;
			}
			this._currentPath = "";
			this._currentPathIsEmpty = true;
		}
		fillText(text, x, y) {
			if (text === "") return;
			let s = `<text x="${x * this.scale}" y="${y * this.scale}" style='stroke: none; font:${this.font.toCssString(this.settings.display.scale)}; ${this.getSvgBaseLine()}'`;
			if (this.color.rgba !== "#000000") s += ` fill="${this.color.rgba}"`;
			if (this.textAlign !== TextAlign.Left) s += ` text-anchor="${this.getSvgTextAlignment(this.textAlign)}"`;
			s += `>${SvgCanvas._escapeText(text)}</text>`;
			this.buffer += s;
		}
		static _escapeText(text) {
			return text.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
		}
		getSvgTextAlignment(textAlign) {
			switch (textAlign) {
				case TextAlign.Left: return "start";
				case TextAlign.Center: return "middle";
				case TextAlign.Right: return "end";
			}
			return "";
		}
		getSvgBaseLine() {
			switch (this.textBaseline) {
				case TextBaseline.Top: return "dominant-baseline: hanging";
				case TextBaseline.Bottom: return "dominant-baseline: ideographic";
				case TextBaseline.Alphabetic: return "";
				case TextBaseline.Middle: return "dominant-baseline: middle";
				default: return "";
			}
		}
		measureText(text) {
			if (!text) return new MeasuredText(0, 0);
			return FontSizes.measureString(text, this.font.families, this.font.size, this.font.style, this.font.weight);
		}
		onRenderFinished() {
			return null;
		}
		beginRotate(centerX, centerY, angle) {
			this.buffer += `<g transform="translate(${centerX * this.scale} ,${centerY * this.scale}) rotate( ${angle})">`;
		}
		endRotate() {
			this.buffer += "</g>";
		}
	};
	//#endregion
	//#region src/platform/svg/CssFontSvgCanvas.ts
	/**
	* This SVG canvas renders the music symbols by adding a CSS class 'at' to all elements.
	* @internal
	*/
	var CssFontSvgCanvas = class extends SvgCanvas {
		fillMusicFontSymbol(x, y, relativeScale, symbol, centerAtPosition) {
			if (symbol === MusicFontSymbol.None) return;
			this._fillMusicFontSymbolText(x, y, relativeScale, `&#${symbol};`, centerAtPosition);
		}
		fillMusicFontSymbols(x, y, relativeScale, symbols, centerAtPosition) {
			let s = "";
			for (const symbol of symbols) if (symbol !== MusicFontSymbol.None) s += `&#${symbol};`;
			this._fillMusicFontSymbolText(x, y, relativeScale, s, centerAtPosition);
		}
		_fillMusicFontSymbolText(x, y, relativeScale, symbols, centerAtPosition) {
			x *= this.scale;
			y *= this.scale;
			this.buffer += `<g transform="translate(${x} ${y})" class="at" ><text`;
			const scale = this.scale * relativeScale;
			if (scale !== 1) this.buffer += ` style="font-size: ${scale * 100}%; stroke:none"`;
			else this.buffer += " style=\"stroke:none\"";
			if (this.color.rgba !== "#000000") this.buffer += ` fill="${this.color.rgba}"`;
			if (centerAtPosition) this.buffer += ` text-anchor="${this.getSvgTextAlignment(TextAlign.Center)}"`;
			this.buffer += `>${symbols}</text></g>`;
		}
	};
	//#endregion
	//#region src/platform/worker/AlphaSynthWorkerSynthOutput.ts
	/**
	* @internal
	*/
	var AlphaSynthWorkerSynthOutput = class AlphaSynthWorkerSynthOutput {
		static preferredSampleRate = 0;
		_main;
		get sampleRate() {
			return AlphaSynthWorkerSynthOutput.preferredSampleRate;
		}
		constructor(main) {
			this._main = main;
		}
		open(_sampleRate) {
			Logger.debug("AlphaSynth", "Initializing synth worker");
			this._main.addEventListener("message", this._handleMessage.bind(this));
			this.ready.trigger();
		}
		destroy() {
			this._main.postMessage({ cmd: "alphaSynth.output.destroy" });
		}
		_handleMessage(e) {
			const data = e.data;
			switch (data.cmd) {
				case "alphaSynth.output.sampleRequest":
					this.sampleRequest.trigger();
					break;
				case "alphaSynth.output.samplesPlayed":
					this.samplesPlayed.trigger(data.samples);
					break;
			}
		}
		ready = new EventEmitter();
		samplesPlayed = new EventEmitterOfT();
		sampleRequest = new EventEmitter();
		addSamples(samples) {
			this._main.postMessage({
				cmd: "alphaSynth.output.addSamples",
				samples: Environment.prepareForPostMessage(samples)
			});
		}
		play() {
			this._main.postMessage({ cmd: "alphaSynth.output.play" });
		}
		pause() {
			this._main.postMessage({ cmd: "alphaSynth.output.pause" });
		}
		resetSamples() {
			this._main.postMessage({ cmd: "alphaSynth.output.resetSamples" });
		}
		activate() {}
		async enumerateOutputDevices() {
			return [];
		}
		async setOutputDevice(_device) {}
		async getOutputDevice() {
			return null;
		}
	};
	//#endregion
	//#region src/platform/worker/AlphaSynthWebWorker.ts
	/**
	* This class implements a HTML5 WebWorker based version of alphaSynth
	* which can be controlled via WebWorker messages.
	* @internal
	* @partial
	*/
	var AlphaSynthWebWorker = class AlphaSynthWebWorker {
		_player;
		_main;
		_exporter = /* @__PURE__ */ new Map();
		constructor(main) {
			this._main = main;
			main.addEventListener("message", (e) => this.handleMessage(e));
		}
		static init() {
			new AlphaSynthWebWorker(Environment.getGlobalWorkerScope());
		}
		handleMessage(e) {
			const data = e.data;
			switch (data.cmd) {
				case "alphaSynth.initialize":
					AlphaSynthWorkerSynthOutput.preferredSampleRate = data.sampleRate;
					Logger.logLevel = data.logLevel;
					this._player = new AlphaSynth(new AlphaSynthWorkerSynthOutput(this._main), data.bufferTimeInMilliseconds);
					this._player.positionChanged.on((e) => this.onPositionChanged(e));
					this._player.stateChanged.on((e) => this.onPlayerStateChanged(e));
					this._player.finished.on(() => this.onFinished());
					this._player.soundFontLoaded.on(() => this.onSoundFontLoaded());
					this._player.soundFontLoadFailed.on((e) => this.onSoundFontLoadFailed(e));
					this._player.midiLoaded.on((e) => this.onMidiLoaded(e));
					this._player.midiLoadFailed.on((e) => this.onMidiLoadFailed(e));
					this._player.readyForPlayback.on(() => this.onReadyForPlayback());
					this._player.midiEventsPlayed.on((e) => this.onMidiEventsPlayed(e));
					this._player.playbackRangeChanged.on((e) => this.onPlaybackRangeChanged(e));
					this._main.postMessage({ cmd: "alphaSynth.ready" });
					break;
				case "alphaSynth.setLogLevel":
					Logger.logLevel = data.value;
					break;
				case "alphaSynth.setMasterVolume":
					this._player.masterVolume = data.value;
					break;
				case "alphaSynth.setMetronomeVolume":
					this._player.metronomeVolume = data.value;
					break;
				case "alphaSynth.setPlaybackSpeed":
					this._player.playbackSpeed = data.value;
					break;
				case "alphaSynth.setTickPosition":
					this._player.tickPosition = data.value;
					break;
				case "alphaSynth.setTimePosition":
					this._player.timePosition = data.value;
					break;
				case "alphaSynth.setPlaybackRange":
					this._player.playbackRange = data.value;
					break;
				case "alphaSynth.setIsLooping":
					this._player.isLooping = data.value;
					break;
				case "alphaSynth.setCountInVolume":
					this._player.countInVolume = data.value;
					break;
				case "alphaSynth.setMidiEventsPlayedFilter":
					this._player.midiEventsPlayedFilter = data.value;
					break;
				case "alphaSynth.play":
					this._player.play();
					break;
				case "alphaSynth.pause":
					this._player.pause();
					break;
				case "alphaSynth.playPause":
					this._player.playPause();
					break;
				case "alphaSynth.stop":
					this._player.stop();
					break;
				case "alphaSynth.playOneTimeMidiFile":
					this._player.playOneTimeMidiFile(JsonConverter.jsObjectToMidiFile(data.midi));
					break;
				case "alphaSynth.loadSoundFontBytes":
					this._player.loadSoundFont(data.data, data.append);
					break;
				case "alphaSynth.resetSoundFonts":
					this._player.resetSoundFonts();
					break;
				case "alphaSynth.loadMidi":
					this._player.loadMidiFile(JsonConverter.jsObjectToMidiFile(data.midi));
					break;
				case "alphaSynth.setChannelMute":
					this._player.setChannelMute(data.channel, data.mute);
					break;
				case "alphaSynth.setChannelTranspositionPitch":
					this._player.setChannelTranspositionPitch(data.channel, data.semitones);
					break;
				case "alphaSynth.setChannelSolo":
					this._player.setChannelSolo(data.channel, data.solo);
					break;
				case "alphaSynth.setChannelVolume":
					this._player.setChannelVolume(data.channel, data.volume);
					break;
				case "alphaSynth.resetChannelStates":
					this._player.resetChannelStates();
					break;
				case "alphaSynth.destroy":
					this._player.destroy();
					this._main.postMessage({ cmd: "alphaSynth.destroyed" });
					break;
				case "alphaSynth.applyTranspositionPitches":
					this._player.applyTranspositionPitches(data.transpositionPitches);
					break;
			}
			if (data.cmd.startsWith("alphaSynth.exporter")) this._handleExporterMessage(e);
		}
		_handleExporterMessage(ev) {
			const data = ev.data;
			const cmd = data.cmd;
			let exporter = void 0;
			let exporterId = 0;
			try {
				switch (cmd) {
					case "alphaSynth.exporter.initialize":
						exporterId = data.exporterId;
						exporter = this._player.exportAudio(data.options, JsonConverter.jsObjectToMidiFile(data.midi), data.syncPoints, data.transpositionPitches);
						this._exporter.set(data.exporterId, exporter);
						this._main.postMessage({
							cmd: "alphaSynth.exporter.initialized",
							exporterId: data.exporterId
						});
						break;
					case "alphaSynth.exporter.render":
						exporterId = data.exporterId;
						if (this._exporter.has(data.exporterId)) {
							exporter = this._exporter.get(data.exporterId);
							const chunk = exporter.render(data.milliseconds);
							this._main.postMessage({
								cmd: "alphaSynth.exporter.rendered",
								exporterId: data.exporterId,
								chunk
							});
						} else this._main.postMessage({
							cmd: "alphaSynth.exporter.error",
							exporterId: data.exporterId,
							error: /* @__PURE__ */ new Error("Unknown exporter ID")
						});
						break;
					case "alphaSynth.exporter.destroy":
						exporterId = data.exporterId;
						this._exporter.delete(data.exporterId);
						break;
				}
			} catch (e) {
				this._main.postMessage({
					cmd: "alphaSynth.exporter.error",
					exporterId,
					error: e
				});
			}
		}
		onPositionChanged(e) {
			this._main.postMessage({
				cmd: "alphaSynth.positionChanged",
				args: e
			});
		}
		onPlayerStateChanged(e) {
			this._main.postMessage({
				cmd: "alphaSynth.playerStateChanged",
				state: e.state,
				stopped: e.stopped
			});
		}
		onFinished() {
			this._main.postMessage({ cmd: "alphaSynth.finished" });
		}
		onSoundFontLoaded() {
			this._main.postMessage({ cmd: "alphaSynth.soundFontLoaded" });
		}
		onSoundFontLoadFailed(e) {
			this._main.postMessage({
				cmd: "alphaSynth.soundFontLoadFailed",
				error: e
			});
		}
		onMidiLoaded(e) {
			this._main.postMessage({
				cmd: "alphaSynth.midiLoaded",
				args: e
			});
		}
		onMidiLoadFailed(e) {
			this._main.postMessage({
				cmd: "alphaSynth.midiLoadFailed",
				error: e
			});
		}
		onReadyForPlayback() {
			this._main.postMessage({ cmd: "alphaSynth.readyForPlayback" });
		}
		onMidiEventsPlayed(args) {
			this._main.postMessage({
				cmd: "alphaSynth.midiEventsPlayed",
				events: args.events.map(JsonConverter.midiEventToJsObject)
			});
		}
		onPlaybackRangeChanged(args) {
			this._main.postMessage({
				cmd: "alphaSynth.playbackRangeChanged",
				playbackRange: args.playbackRange
			});
		}
	};
	//#endregion
	//#region src/platform/worker/AlphaTabWebWorker.ts
	/**
	* @internal
	* @partial
	*/
	var AlphaTabWebWorker = class AlphaTabWebWorker {
		_renderer;
		_main;
		constructor(main) {
			this._main = main;
			main.addEventListener("message", (e) => this._handleMessage(e));
		}
		static init() {
			new AlphaTabWebWorker(Environment.getGlobalWorkerScope());
		}
		_handleMessage(e) {
			const data = e.data;
			if (!data?.cmd) return;
			switch (data.cmd) {
				case "alphaTab.initialize":
					const settings = JsonConverter.jsObjectToSettings(data.settings);
					Logger.logLevel = settings.core.logLevel;
					this._renderer = new ScoreRenderer(settings);
					this._renderer.partialRenderFinished.on((result) => {
						this._main.postMessage({
							cmd: "alphaTab.partialRenderFinished",
							result
						});
					});
					this._renderer.partialLayoutFinished.on((result) => {
						this._main.postMessage({
							cmd: "alphaTab.partialLayoutFinished",
							result
						});
					});
					this._renderer.renderFinished.on((result) => {
						this._main.postMessage({
							cmd: "alphaTab.renderFinished",
							result
						});
					});
					this._renderer.postRenderFinished.on(() => {
						this._main.postMessage({
							cmd: "alphaTab.postRenderFinished",
							boundsLookup: this._renderer.boundsLookup?.toJson() ?? null
						});
					});
					this._renderer.preRender.on((resize) => {
						this._main.postMessage({
							cmd: "alphaTab.preRender",
							resize
						});
					});
					this._renderer.error.on(this._error.bind(this));
					break;
				case "alphaTab.render":
					this._renderer.render(data.renderHints);
					break;
				case "alphaTab.resizeRender":
					this._renderer.resizeRender();
					break;
				case "alphaTab.renderResult":
					this._renderer.renderResult(data.resultId);
					break;
				case "alphaTab.setWidth":
					this._renderer.width = data.width;
					break;
				case "alphaTab.renderScore":
					this._updateFontSizes(data.fontSizes);
					const renderHints = data.renderHints;
					const score = data.score == null ? null : JsonConverter.jsObjectToScore(data.score, this._renderer.settings);
					this._renderMultiple(score, data.trackIndexes, renderHints);
					break;
				case "alphaTab.updateSettings":
					this._updateSettings(data.settings);
					break;
			}
		}
		_updateFontSizes(fontSizes) {
			for (const [k, v] of fontSizes) FontSizes.fontSizeLookupTables.set(k, v);
		}
		_updateSettings(json) {
			SettingsSerializer.fromJson(this._renderer.settings, json);
		}
		_renderMultiple(score, trackIndexes, renderHints) {
			try {
				this._renderer.renderScore(score, trackIndexes, renderHints);
			} catch (e) {
				this._error(e);
			}
		}
		_error(error) {
			Logger.error("Worker", "An unexpected error occurred in worker", error);
			this._main.postMessage({
				cmd: "alphaTab.error",
				error
			});
		}
	};
	//#endregion
	//#region src/rendering/BarRendererFactory.ts
	/**
	* The different modes on how effect bands are applied to bar renderers.
	* @internal
	*/
	var EffectBandMode = /* @__PURE__ */ function(EffectBandMode) {
		/**
		* The band is owned by the specific renderer.
		* If the owning renderer is not shown, the band will not be shown either.
		* The band is shown on top of the main renderer.
		*/
		EffectBandMode[EffectBandMode["OwnedTop"] = 0] = "OwnedTop";
		/**
		* The band is owned by the specific renderer.
		* If the owning renderer is not shown, the band will not be shown either.
		* The band is shown on bottom of the main renderer.
		*/
		EffectBandMode[EffectBandMode["OwnedBottom"] = 1] = "OwnedBottom";
		/**
		* The band is shared across renderers.
		* If the owning renderer is shown, the band is shown on top the main renderer.
		* If the renderer is not shown, the band is shown on the top of the next renderer which is visible.
		*
		* If no visible render follows, they are added to the bottom of the previous visible renderer.
		*/
		EffectBandMode[EffectBandMode["SharedTop"] = 2] = "SharedTop";
		/**
		* The band is shared across renderers.
		* If the owning renderer is shown, the band is shown on bottom of the main renderer.
		* If the owning renderer is not shown, the band is shown on the **bottom** of the next renderer which is visible.
		*
		* If no visible render follows, they are added to the bottom of the previous visible renderer.
		*/
		EffectBandMode[EffectBandMode["SharedBottom"] = 3] = "SharedBottom";
		return EffectBandMode;
	}({});
	/**
	* This is the base public class for creating factories providing BarRenderers
	* @internal
	*/
	var BarRendererFactory = class {
		hideOnMultiTrack = false;
		hideOnPercussionTrack = false;
		effectBands;
		constructor(effectBands) {
			this.effectBands = effectBands;
		}
		canCreate(_track, staff) {
			return !this.hideOnPercussionTrack || !staff.isPercussion;
		}
	};
	//#endregion
	//#region src/rendering/EffectBarGlyphSizing.ts
	/**
	* Lists all sizing types of the effect bar glyphs
	* @internal
	*/
	var EffectBarGlyphSizing = /* @__PURE__ */ function(EffectBarGlyphSizing) {
		/**
		* The effect glyph is placed above the pre-beat glyph which is before
		* the actual note in the area where also accidentals are renderered.
		*/
		EffectBarGlyphSizing[EffectBarGlyphSizing["SinglePreBeat"] = 0] = "SinglePreBeat";
		/**
		* The effect glyph is placed above the on-beat glyph which is where
		* the actual note head glyphs are placed.
		*/
		EffectBarGlyphSizing[EffectBarGlyphSizing["SingleOnBeat"] = 1] = "SingleOnBeat";
		/**
		* The effect glyph is placed above the on-beat glyph which is where
		* the actual note head glyphs are placed. The glyph will size to the end of
		* the applied beat.
		*/
		EffectBarGlyphSizing[EffectBarGlyphSizing["SingleOnBeatToEnd"] = 2] = "SingleOnBeatToEnd";
		/**
		* The effect glyph is placed above the on-beat glyph and expaded to the
		* on-beat position of the next beat.
		*/
		EffectBarGlyphSizing[EffectBarGlyphSizing["GroupedOnBeat"] = 3] = "GroupedOnBeat";
		/**
		* The effect glyph is placed above the on-beat glyph and expaded to the
		* on-beat position of the next beat. The glyph will size to the end of
		* the applied beat.
		*/
		EffectBarGlyphSizing[EffectBarGlyphSizing["GroupedOnBeatToEnd"] = 4] = "GroupedOnBeatToEnd";
		/**
		* The effect glyph is placed on the whole bar covering the whole width
		*/
		EffectBarGlyphSizing[EffectBarGlyphSizing["FullBar"] = 5] = "FullBar";
		return EffectBarGlyphSizing;
	}({});
	//#endregion
	//#region src/rendering/glyphs/EffectGlyph.ts
	/**
	* Effect-Glyphs implementing this public interface get notified
	* as they are expanded over multiple beats.
	* @internal
	*/
	var EffectGlyph = class extends Glyph {
		/**
		* Gets or sets the beat where the glyph belongs to.
		*/
		beat = null;
		/**
		* Gets or sets the next glyph of the same type in case
		* the effect glyph is expanded when using {@link EffectBarGlyphSizing.groupedOnBeat}.
		*/
		nextGlyph = null;
		/**
		* Gets or sets the previous glyph of the same type in case
		* the effect glyph is expanded when using {@link EffectBarGlyphSizing.groupedOnBeat}.
		*/
		previousGlyph = null;
		constructor(x = 0, y = 0) {
			super(x, y);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/AlternateEndingsGlyph.ts
	/**
	* @internal
	*/
	var AlternateEndingsGlyph = class extends EffectGlyph {
		_endings;
		_endingsString = "";
		_openLine;
		_closeLine;
		_indent;
		constructor(x, y, alternateEndings, openLine, closeLine, indent) {
			super(x, y);
			this._endings = ModelUtils.getAlternateEndingsList(alternateEndings);
			this._openLine = openLine;
			this._closeLine = closeLine;
			this._indent = indent;
		}
		doLayout() {
			super.doLayout();
			this.height = this.renderer.resources.elementFonts.get(NotationElement.EffectAlternateEndings).size + this.renderer.smuflMetrics.alternateEndingsPadding * 2;
			let endingsStrings = "";
			for (let i = 0, j = this._endings.length; i < j; i++) {
				endingsStrings += this._endings[i] + 1;
				endingsStrings += ". ";
			}
			this._endingsString = endingsStrings;
		}
		paint(cx, cy, canvas) {
			let width = this._closeLine ? this.width - canvas.lineWidth : this.width;
			if (this.renderer.bar.getActualBarLineRight() === BarLineStyle.LightHeavy) width -= this.renderer.smuflMetrics.thickBarlineThickness + this.renderer.smuflMetrics.barlineSeparation;
			cx = (cx | 0) + canvas.lineWidth / 2;
			cy = (cy | 0) + canvas.lineWidth / 2;
			if (this._indent) {
				cx += this.renderer.smuflMetrics.alternateEndingsPadding;
				width -= this.renderer.smuflMetrics.alternateEndingsPadding;
			}
			if (this._openLine) {
				canvas.moveTo(cx + this.x, cy + this.y + this.height);
				canvas.lineTo(cx + this.x, cy + this.y);
			} else canvas.moveTo(cx + this.x, cy + this.y);
			canvas.lineTo(cx + this.x + width, cy + this.y);
			if (this._closeLine) canvas.lineTo(cx + this.x + width, cy + this.y + this.height);
			canvas.stroke();
			if (this._openLine) {
				const baseline = canvas.textBaseline;
				canvas.textBaseline = TextBaseline.Top;
				canvas.font = this.renderer.resources.elementFonts.get(NotationElement.EffectAlternateEndings);
				canvas.fillText(this._endingsString, cx + this.x + this.renderer.smuflMetrics.alternateEndingsPadding, cy + this.y + this.renderer.smuflMetrics.alternateEndingsPadding);
				canvas.textBaseline = baseline;
			}
		}
	};
	//#endregion
	//#region src/rendering/EffectInfo.ts
	/**
	* A classes inheriting from this base can provide the
	* data needed by a EffectBarRenderer to create effect glyphs dynamically.
	* @internal
	*/
	var EffectInfo = class {
		/**
		* Gets the unique effect name for this effect. (Used for grouping)
		*/
		get effectId() {
			return this.notationElement.toString();
		}
		/**
		* Override this method to finalize an effect band with all glyphs created.
		* Allows special layout logic like for whammys where we center-align the glyphs and size the band accordingly.
		* @param _band The band which is being finalized.
		*/
		finalizeBand(_band) {}
		/**
		* Override this method when glyphs are for this effect is being re-aligned during resizing.
		* @param _band The band holding the glyph
		*/
		onAlignGlyphs(_band) {}
	};
	//#endregion
	//#region src/rendering/effects/AlternateEndingsEffectInfo.ts
	/**
	* @internal
	*/
	var AlternateEndingsEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectAlternateEndings;
		}
		get hideOnMultiTrack() {
			return true;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.FullBar;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.voice.index === 0 && beat.index === 0 && beat.voice.bar.masterBar.alternateEndings !== 0;
		}
		createNewGlyph(_renderer, beat) {
			const masterBar = beat.voice.bar.masterBar;
			const openLine = masterBar.previousMasterBar === null || masterBar.alternateEndings !== masterBar.previousMasterBar.alternateEndings;
			let closeLine = masterBar.isRepeatEnd || masterBar.nextMasterBar === null || masterBar.alternateEndings !== masterBar.nextMasterBar.alternateEndings;
			if (!masterBar.repeatGroup.closings.some((c) => c.index >= masterBar.index)) closeLine = false;
			const indent = masterBar.previousMasterBar !== null && masterBar.alternateEndings !== masterBar.previousMasterBar.alternateEndings && masterBar.previousMasterBar.alternateEndings > 0;
			return new AlternateEndingsGlyph(0, 0, masterBar.alternateEndings, openLine, closeLine, indent);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/GroupedEffectGlyph.ts
	/**
	* @internal
	*/
	var GroupedEffectGlyph = class extends EffectGlyph {
		endPosition;
		forceGroupedRendering = false;
		endOnBarLine = false;
		constructor(endPosition) {
			super();
			this.endPosition = endPosition;
		}
		get isLinkedWithPrevious() {
			return !!this.previousGlyph && this.previousGlyph.renderer.staff?.system === this.renderer.staff.system;
		}
		get isLinkedWithNext() {
			return !!this.nextGlyph && this.nextGlyph.renderer.isFinalized && this.nextGlyph.renderer.staff?.system === this.renderer.staff.system;
		}
		paint(cx, cy, canvas) {
			if (this.isLinkedWithPrevious) return;
			if (!this.isLinkedWithNext && !this.forceGroupedRendering) {
				this.paintNonGrouped(cx, cy, canvas);
				return;
			}
			let lastLinkedGlyph;
			if (!this.isLinkedWithNext && this.forceGroupedRendering) lastLinkedGlyph = this;
			else {
				lastLinkedGlyph = this.nextGlyph;
				while (lastLinkedGlyph.isLinkedWithNext) lastLinkedGlyph = lastLinkedGlyph.nextGlyph;
			}
			const endBeatRenderer = lastLinkedGlyph.renderer;
			const endBeat = lastLinkedGlyph.beat;
			const position = this.endPosition;
			const cxRenderer = cx - this.renderer.x;
			const endX = this.calculateEndX(endBeatRenderer, endBeat, cxRenderer, position);
			this.paintGrouped(cx, cy, endX, canvas);
		}
		calculateEndX(endBeatRenderer, endBeat, cx, endPosition) {
			if (!endBeat) return cx + endBeatRenderer.x + this.x + this.width;
			return cx + endBeatRenderer.x + endBeatRenderer.getBeatX(endBeat, endPosition);
		}
		paintNonGrouped(cx, cy, canvas) {
			const cxRenderer = cx - this.renderer.x;
			const endX = this.calculateEndX(this.renderer, this.beat, cxRenderer, this.endPosition);
			this.paintGrouped(cx, cy, endX, canvas);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/LineRangedGlyph.ts
	/**
	* @internal
	*/
	var LineRangedGlyph = class extends GroupedEffectGlyph {
		_label;
		_dashed;
		_labelWidth = 0;
		_fontElement;
		constructor(label, fontElement, dashed = true) {
			super(BeatXPosition.OnNotes);
			this._label = label;
			this._dashed = dashed;
			this._fontElement = fontElement;
		}
		doLayout() {
			if (this.renderer.settings.notation.extendLineEffectsToBeatEnd) {
				this.endPosition = BeatXPosition.EndBeat;
				this.forceGroupedRendering = true;
			}
			super.doLayout();
			this.renderer.scoreRenderer.canvas.font = this.renderer.resources.elementFonts.get(this._fontElement);
			const size = this.renderer.scoreRenderer.canvas.measureText(this._label);
			this.height = size.height;
			this._labelWidth = size.width;
		}
		paintNonGrouped(cx, cy, canvas) {
			canvas.font = this.renderer.resources.elementFonts.get(this._fontElement);
			const b = canvas.textBaseline;
			canvas.textBaseline = TextBaseline.Middle;
			canvas.fillText(this._label, cx + this.x - this._labelWidth / 2, cy + this.y + this.height / 2);
			canvas.textBaseline = b;
		}
		paintGrouped(cx, cy, endX, canvas) {
			this.paintNonGrouped(cx, cy, canvas);
			const dashGap = this.renderer.smuflMetrics.lineRangedGlyphDashGap;
			const dashSize = this.renderer.smuflMetrics.lineRangedGlyphDashSize;
			const dashThickness = this.renderer.smuflMetrics.pedalLineThickness;
			const startX = cx + this.x + this._labelWidth / 2 + dashGap / 2;
			const lineY = cy + this.y + this.height / 2 - dashThickness / 2;
			if (this._dashed) {
				if (endX > startX) {
					let lineX = startX;
					while (lineX < endX) {
						const dashEndX = Math.min(lineX + dashSize, endX);
						canvas.fillRect(lineX, lineY, dashEndX - lineX, dashThickness);
						lineX += dashSize + dashGap;
					}
					canvas.fillRect(endX, lineY - dashSize / 2 + dashThickness / 2, dashThickness, dashSize);
				}
			} else {
				canvas.fillRect(startX, lineY, endX - startX, dashThickness);
				canvas.fillRect(endX - dashThickness, lineY, dashThickness, dashSize / 2);
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/BeatBarreEffectInfo.ts
	/**
	* @internal
	*/
	var BeatBarreEffectInfo = class BeatBarreEffectInfo extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectLetRing;
		}
		get canShareBand() {
			return false;
		}
		get hideOnMultiTrack() {
			return false;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.isBarre;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		createNewGlyph(_renderer, beat) {
			let barre = "";
			switch (beat.barreShape) {
				case BarreShape.None:
				case BarreShape.Full: break;
				case BarreShape.Half:
					barre += "1/2";
					break;
			}
			barre += `B ${BeatBarreEffectInfo.toRoman(beat.barreFret)}`;
			return new LineRangedGlyph(barre, NotationElement.EffectBeatBarre, false);
		}
		static _romanLetters = new Map([
			["L", 50],
			["XL", 40],
			["X", 10],
			["IX", 9],
			["V", 5],
			["IV", 4],
			["I", 1]
		]);
		static toRoman(num) {
			let str = "";
			if (num > 0) for (const [romanLetter, romanNumber] of BeatBarreEffectInfo._romanLetters) {
				const q = Math.floor(num / romanNumber);
				num -= q * romanNumber;
				str += romanLetter.repeat(q);
			}
			return str;
		}
		canExpand(from, to) {
			return from.barreFret === to.barreFret && from.barreShape === to.barreShape;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BeatTimerGlyph.ts
	/**
	* @internal
	*/
	var BeatTimerGlyph = class extends EffectGlyph {
		_timer;
		_text = "";
		_textWidth = 0;
		_textHeight = 0;
		constructor(timer) {
			super(0, 0);
			this._timer = timer;
		}
		doLayout() {
			const minutes = this._timer / 6e4 | 0;
			const seconds = (this._timer - minutes * 6e4) / 1e3 | 0;
			this._text = `${minutes}:${seconds.toString().padStart(2, "0")}`;
			const c = this.renderer.scoreRenderer.canvas;
			c.font = this.renderer.resources.elementFonts.get(NotationElement.EffectBeatTimer);
			const size = c.measureText(this._text);
			this._textHeight = c.font.size + this.renderer.smuflMetrics.beatTimerPadding * 2;
			this._textWidth = size.width + this.renderer.smuflMetrics.beatTimerPadding * 2;
			this.height = this._textHeight + this.renderer.smuflMetrics.beatTimerPadding * 2;
		}
		paint(cx, cy, canvas) {
			const halfWidth = this._textWidth / 2 | 0;
			canvas.strokeRect(cx + this.x - halfWidth, cy + this.y + this.renderer.smuflMetrics.beatTimerPadding, this._textWidth, this._textHeight);
			const f = canvas.font;
			const b = canvas.textBaseline;
			const a = canvas.textAlign;
			canvas.font = this.renderer.resources.elementFonts.get(NotationElement.EffectBeatTimer);
			canvas.textBaseline = TextBaseline.Middle;
			canvas.textAlign = TextAlign.Center;
			canvas.fillText(this._text, cx + this.x, cy + this.y + this.height / 2);
			canvas.font = f;
			canvas.textBaseline = b;
			canvas.textAlign = a;
		}
	};
	//#endregion
	//#region src/rendering/effects/BeatTimerEffectInfo.ts
	/**
	* @internal
	*/
	var BeatTimerEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectBeatTimer;
		}
		get hideOnMultiTrack() {
			return true;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.showTimer;
		}
		createNewGlyph(_renderer, beat) {
			return new BeatTimerGlyph(beat.timer ?? 0);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TextGlyph.ts
	/**
	* @internal
	*/
	var TextGlyph = class extends EffectGlyph {
		_lines;
		_lineHeights = null;
		font;
		textAlign;
		textBaseline;
		colorOverride;
		constructor(x, y, text, font, textAlign = TextAlign.Left, testBaseline = null, color) {
			super(x, y);
			this._lines = text.split("\n");
			this.font = font;
			this.textAlign = textAlign;
			this.textBaseline = testBaseline;
			this.colorOverride = color;
		}
		doLayout() {
			super.doLayout();
			this._lineHeights = [];
			const c = this.renderer.scoreRenderer.canvas;
			for (const line of this._lines) {
				c.font = this.font;
				const size = c.measureText(line);
				const h = size.height;
				this._lineHeights.push(h);
				this.height += h;
				this.width = Math.max(this.width, size.width);
			}
		}
		paint(cx, cy, canvas) {
			const color = canvas.color;
			canvas.color = this.colorOverride ?? color;
			canvas.font = this.font;
			const old = canvas.textAlign;
			const oldBaseLine = canvas.textBaseline;
			canvas.textAlign = this.textAlign;
			if (this.textBaseline !== null) canvas.textBaseline = this.textBaseline;
			let y = cy + this.y;
			for (let i = 0; i < this._lines.length; i++) {
				canvas.fillText(this._lines[i], cx + this.x, y);
				y += this._lineHeights[i];
			}
			canvas.textAlign = old;
			canvas.textBaseline = oldBaseLine;
			canvas.color = color;
		}
	};
	//#endregion
	//#region src/rendering/effects/CapoEffectInfo.ts
	/**
	* @internal
	*/
	var CapoEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectCapo;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.index === 0 && beat.voice.bar.index === 0 && beat.voice.bar.staff.capo !== 0;
		}
		createNewGlyph(renderer, beat) {
			return new TextGlyph(0, 0, `Capo. fret ${beat.voice.bar.staff.capo}`, renderer.resources.elementFonts.get(NotationElement.EffectCapo), TextAlign.Left);
		}
		canExpand(_from, _to) {
			return false;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ChordDiagramGlyph.ts
	/**
	* @internal
	*/
	var ChordDiagramGlyph = class ChordDiagramGlyph extends EffectGlyph {
		static _frets = 5;
		_chord;
		_textRow = 0;
		_fretRow = 0;
		_firstFretSpacing = 0;
		_center;
		_fontElement;
		constructor(x, y, chord, fontElement, center = false) {
			super(x, y);
			this._chord = chord;
			this._center = center;
			this._fontElement = fontElement;
		}
		doLayout() {
			super.doLayout();
			const font = this.renderer.resources.elementFonts.get(this._fontElement);
			this._textRow = font.size * 1.5;
			this._fretRow = font.size * 1.5;
			this.height = this._textRow;
			this.width = 2 * this.renderer.smuflMetrics.chordDiagramPaddingX;
			if (this.renderer.settings.notation.isNotationElementVisible(NotationElement.ChordDiagramFretboardNumbers)) {
				if (this._chord.firstFret > 1) this._firstFretSpacing = this.renderer.smuflMetrics.chordDiagramFretSpacing;
				else this._firstFretSpacing = 0;
				this.height += this._fretRow + ChordDiagramGlyph._frets * this.renderer.smuflMetrics.chordDiagramFretSpacing + 2 * this.renderer.smuflMetrics.chordDiagramPaddingY;
				this.width += this._firstFretSpacing + (this._chord.strings.length - 1) * this.renderer.smuflMetrics.chordDiagramStringSpacing;
			} else if (this._chord.showName) {
				const canvas = this.renderer.scoreRenderer.canvas;
				canvas.font = font;
				this.width += canvas.measureText(this._chord.name).width;
			}
		}
		paint(cx, cy, canvas) {
			cx += this.x + this.renderer.smuflMetrics.chordDiagramPaddingX + this._firstFretSpacing;
			cy += this.y;
			if (this._center) cx -= this.width / 2;
			const res = this.renderer.resources;
			const lineWidth = res.engravingSettings.chordDiagramLineWidth;
			const w = this.width - 2 * this.renderer.smuflMetrics.chordDiagramPaddingX - this._firstFretSpacing + lineWidth;
			const align = canvas.textAlign;
			const baseline = canvas.textBaseline;
			const font = res.elementFonts.get(this._fontElement);
			canvas.font = font;
			canvas.textAlign = TextAlign.Center;
			canvas.textBaseline = TextBaseline.Top;
			if (this._chord.showName) canvas.fillText(this._chord.name, cx + w / 2, cy + font.size / 2);
			if (this.renderer.settings.notation.isNotationElementVisible(NotationElement.ChordDiagramFretboardNumbers)) this._paintFretboard(cx, cy, canvas, w);
			canvas.textAlign = align;
			canvas.textBaseline = baseline;
		}
		_paintFretboard(cx, cy, canvas, w) {
			cy += this._textRow;
			const res = this.renderer.resources;
			const stringSpacing = this.renderer.smuflMetrics.chordDiagramStringSpacing;
			const fretSpacing = this.renderer.smuflMetrics.chordDiagramFretSpacing;
			const circleHeight = res.engravingSettings.glyphHeights.get(MusicFontSymbol.FretboardFilledCircle);
			const circleTopOffset = res.engravingSettings.glyphTop.get(MusicFontSymbol.FretboardFilledCircle);
			const xTopOffset = res.engravingSettings.glyphHeights.get(MusicFontSymbol.FretboardX) / 2;
			const oTopOffset = res.engravingSettings.glyphHeights.get(MusicFontSymbol.FretboardO) / 2;
			const lineWidth = res.engravingSettings.chordDiagramLineWidth;
			canvas.font = res.elementFonts.get(NotationElement.ChordDiagramFretboardNumbers);
			canvas.textBaseline = TextBaseline.Middle;
			for (let i = 0; i < this._chord.strings.length; i++) {
				const x = cx + i * stringSpacing;
				const y = cy + this._fretRow / 2;
				let fret = this._chord.strings[this._chord.strings.length - i - 1];
				if (fret < 0) CanvasHelper.fillMusicFontSymbolSafe(canvas, x, y + xTopOffset, 1, MusicFontSymbol.FretboardX, true);
				else if (fret === 0) CanvasHelper.fillMusicFontSymbolSafe(canvas, x, y + oTopOffset, 1, MusicFontSymbol.FretboardO, true);
				else {
					fret -= this._chord.firstFret - 1;
					canvas.fillText(fret.toString(), x, y);
				}
			}
			cy += this._fretRow;
			for (let i = 0; i < this._chord.strings.length; i++) {
				const x = cx + i * stringSpacing;
				canvas.fillRect(x, cy, lineWidth, fretSpacing * ChordDiagramGlyph._frets + 1);
			}
			if (this._chord.firstFret > 1) {
				canvas.textAlign = TextAlign.Left;
				canvas.fillText(this._chord.firstFret.toString(), cx - this._firstFretSpacing, cy + fretSpacing / 2);
				canvas.fillRect(cx, cy, w, lineWidth);
			} else canvas.fillRect(cx, cy - this.renderer.smuflMetrics.chordDiagramNutHeight / 2, w, this.renderer.smuflMetrics.chordDiagramNutHeight);
			for (let i = 0; i <= ChordDiagramGlyph._frets; i++) {
				const y = cy + i * fretSpacing;
				canvas.fillRect(cx, y, w, this.renderer.smuflMetrics.chordDiagramFretHeight);
			}
			const barreLookup = /* @__PURE__ */ new Map();
			for (const barreFret of this._chord.barreFrets) barreLookup.set(barreFret - this._chord.firstFret, [-1, -1]);
			for (let guitarString = 0; guitarString < this._chord.strings.length; guitarString++) {
				let fret = this._chord.strings[guitarString];
				if (fret > 0) {
					fret -= this._chord.firstFret;
					if (barreLookup.has(fret)) {
						const info = barreLookup.get(fret);
						if (info[0] === -1 || guitarString < info[0]) info[0] = guitarString;
						if (info[1] === -1 || guitarString > info[1]) info[1] = guitarString;
					}
					const y = cy + fret * fretSpacing + fretSpacing / 2 + .5;
					const x = cx + (this._chord.strings.length - guitarString - 1) * stringSpacing + lineWidth / 2;
					CanvasHelper.fillMusicFontSymbolSafe(canvas, x, y + circleTopOffset - circleHeight / 2, 1, MusicFontSymbol.FretboardFilledCircle, true);
				}
			}
			for (const [fret, strings] of barreLookup) {
				const y = cy + fret * fretSpacing + fretSpacing / 2 + .5;
				const xLeft = cx + (this._chord.strings.length - strings[1] - 1) * stringSpacing;
				const xRight = cx + (this._chord.strings.length - strings[0] - 1) * stringSpacing;
				canvas.fillRect(xLeft, y - circleHeight / 2, xRight - xLeft, circleHeight);
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/ChordsEffectInfo.ts
	/**
	* @internal
	*/
	var ChordsEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectChordNames;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.hasChord;
		}
		createNewGlyph(renderer, beat) {
			return beat.voice.bar.staff.track.score.stylesheet.globalDisplayChordDiagramsInScore ? new ChordDiagramGlyph(0, 0, beat.chord, NotationElement.EffectChordNames, true) : new TextGlyph(0, 0, beat.chord.name, renderer.resources.elementFonts.get(NotationElement.EffectChordNames), TextAlign.Center);
		}
		canExpand(_from, _to) {
			return false;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/CrescendoGlyph.ts
	/**
	* @internal
	*/
	var CrescendoGlyph = class extends GroupedEffectGlyph {
		_crescendo;
		constructor(x, y, crescendo) {
			super(BeatXPosition.EndBeat);
			this._crescendo = CrescendoType.None;
			this._crescendo = crescendo;
			this.x = x;
			this.y = y;
		}
		doLayout() {
			super.doLayout();
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.DynamicCrescendoHairpin);
		}
		paintGrouped(cx, cy, endX, canvas) {
			const startX = cx + this.x;
			const height = this.height;
			const padding = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.NoteheadBlack) / 2;
			canvas.beginPath();
			if (this._crescendo === CrescendoType.Crescendo) {
				endX -= padding;
				canvas.moveTo(endX, cy + this.y);
				canvas.lineTo(startX, cy + this.y + height / 2);
				canvas.lineTo(endX, cy + this.y + height);
			} else {
				endX -= padding;
				canvas.moveTo(startX, cy + this.y);
				canvas.lineTo(endX, cy + this.y + height / 2);
				canvas.lineTo(startX, cy + this.y + height);
			}
			const lineWidth = canvas.lineWidth;
			canvas.lineWidth = this.renderer.smuflMetrics.hairpinThickness;
			canvas.stroke();
			canvas.lineWidth = lineWidth;
		}
	};
	//#endregion
	//#region src/rendering/effects/CrescendoEffectInfo.ts
	/**
	* @internal
	*/
	var CrescendoEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectCrescendo;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeatToEnd;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.crescendo !== CrescendoType.None;
		}
		createNewGlyph(_renderer, beat) {
			return new CrescendoGlyph(0, 0, beat.crescendo);
		}
		canExpand(from, to) {
			return from.crescendo === to.crescendo;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/DirectionsContainerGlyph.ts
	/**
	* @internal
	*/
	var TargetDirectionGlyph = class extends Glyph {
		_symbols;
		_scale = 1;
		constructor(symbols) {
			super(0, 0);
			this._symbols = symbols;
		}
		doLayout() {
			this.height = 0;
			const scale = this.renderer.smuflMetrics.directionsScale;
			this._scale = scale;
			for (const s of this._symbols) {
				const h = this.renderer.smuflMetrics.glyphHeights.get(s) * scale;
				if (h > this.height) this.height = h;
			}
		}
		paint(cx, cy, canvas) {
			canvas.fillMusicFontSymbols(cx + this.x, cy + this.y + this.height, this._scale, this._symbols, true);
		}
	};
	/**
	* @internal
	*/
	var JumpDirectionGlyph = class extends Glyph {
		_text;
		constructor(text) {
			super(0, 0);
			this._text = text;
		}
		doLayout() {
			const c = this.renderer.scoreRenderer.canvas;
			c.font = this.renderer.resources.elementFonts.get(NotationElement.EffectDirections);
			this.height = c.measureText(this._text).height;
		}
		paint(cx, cy, canvas) {
			const font = canvas.font;
			const baseline = canvas.textBaseline;
			const align = canvas.textAlign;
			canvas.font = this.renderer.resources.elementFonts.get(NotationElement.EffectDirections);
			canvas.textBaseline = TextBaseline.Middle;
			canvas.textAlign = TextAlign.Right;
			canvas.fillText(this._text, cx + this.x, cy + this.y + this.height / 2);
			canvas.font = font;
			canvas.textBaseline = baseline;
			canvas.textAlign = align;
		}
	};
	/**
	* @internal
	*/
	var DirectionsContainerGlyph = class extends EffectGlyph {
		_directions;
		_barBeginGlyphs = [];
		_barEndGlyphs = [];
		constructor(x, y, directions) {
			super(x, y);
			this._directions = directions;
		}
		doLayout() {
			const d = this._directions;
			if (d.has(Direction.TargetSegnoSegno)) this._barBeginGlyphs.push(new TargetDirectionGlyph([MusicFontSymbol.Segno, MusicFontSymbol.Segno]));
			if (d.has(Direction.TargetSegno)) this._barBeginGlyphs.push(new TargetDirectionGlyph([MusicFontSymbol.Segno]));
			if (d.has(Direction.TargetDoubleCoda)) this._barBeginGlyphs.push(new TargetDirectionGlyph([MusicFontSymbol.Coda, MusicFontSymbol.Coda]));
			if (d.has(Direction.TargetCoda)) this._barBeginGlyphs.push(new TargetDirectionGlyph([MusicFontSymbol.Coda]));
			if (d.has(Direction.TargetFine)) this._barEndGlyphs.push(new JumpDirectionGlyph("Fine"));
			if (d.has(Direction.JumpDaDoubleCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("To Double Coda"));
			if (d.has(Direction.JumpDaCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("To Coda"));
			if (d.has(Direction.JumpDalSegnoSegno)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S.S."));
			if (d.has(Direction.JumpDalSegnoSegnoAlCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S.S. al Coda"));
			if (d.has(Direction.JumpDalSegnoSegnoAlDoubleCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S.S. al Double Coda"));
			if (d.has(Direction.JumpDalSegnoSegnoAlFine)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S.S. al Fine"));
			if (d.has(Direction.JumpDalSegno)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S."));
			if (d.has(Direction.JumpDalSegnoAlCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S. al Coda"));
			if (d.has(Direction.JumpDalSegnoAlDoubleCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S. al Double Coda"));
			if (d.has(Direction.JumpDalSegnoAlFine)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.S. al Fine"));
			if (d.has(Direction.JumpDaCapo)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.C."));
			if (d.has(Direction.JumpDaCapoAlCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.C. al Coda"));
			if (d.has(Direction.JumpDaCapoAlDoubleCoda)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.C. al Double Coda"));
			if (d.has(Direction.JumpDaCapoAlFine)) this._barEndGlyphs.push(new JumpDirectionGlyph("D.C. al Fine"));
			const beginHeight = this._doSideLayout(this._barBeginGlyphs);
			const endHeight = this._doSideLayout(this._barEndGlyphs);
			this.height = Math.max(beginHeight, endHeight);
		}
		_doSideLayout(glyphs) {
			let y = 0;
			const padding = this.renderer.settings.display.effectBandPaddingBottom;
			for (const g of glyphs) {
				g.y = y;
				g.renderer = this.renderer;
				g.doLayout();
				y += g.height + padding;
			}
			return y;
		}
		paint(cx, cy, canvas) {
			for (const begin of this._barBeginGlyphs) begin.paint(cx + this.x, cy + this.y, canvas);
			for (const end of this._barEndGlyphs) end.paint(cx + this.x + this.width, cy + this.y, canvas);
		}
	};
	//#endregion
	//#region src/rendering/effects/DirectionsEffectInfo.ts
	/**
	* @internal
	*/
	var DirectionsEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectDirections;
		}
		get hideOnMultiTrack() {
			return true;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.FullBar;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.voice.index === 0 && beat.index === 0 && beat.voice.bar.masterBar.directions !== null && beat.voice.bar.masterBar.directions.size > 0;
		}
		createNewGlyph(_renderer, beat) {
			return new DirectionsContainerGlyph(0, 0, beat.voice.bar.masterBar.directions);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/MusicFontGlyph.ts
	/**
	* @internal
	*/
	var MusicFontGlyph = class extends EffectGlyph {
		glyphScale = 0;
		symbol;
		center = false;
		colorOverride;
		offsetX = 0;
		offsetY = 0;
		constructor(x, y, glyphScale, symbol) {
			super(x, y);
			this.glyphScale = glyphScale;
			this.symbol = symbol;
		}
		getBoundingBoxTop() {
			const bBoxTop = this.renderer.smuflMetrics.glyphTop.get(this.symbol);
			return this.y - this.offsetY - bBoxTop;
		}
		doLayout() {
			this.width = this.renderer.smuflMetrics.glyphWidths.get(this.symbol) * this.glyphScale;
			this.height = this.renderer.smuflMetrics.glyphHeights.get(this.symbol) * this.glyphScale;
		}
		paint(cx, cy, canvas) {
			if (this.width === 0 && this.height === 0) return;
			const c = canvas.color;
			if (this.colorOverride) canvas.color = this.colorOverride;
			canvas.fillMusicFontSymbol(cx + this.x + this.offsetX, cy + this.y + this.offsetY, this.glyphScale, this.symbol, this.center);
			canvas.color = c;
		}
	};
	/**
	* @internal
	*/
	var MusicFontTextGlyph = class extends EffectGlyph {
		glyphScale = 0;
		symbols;
		center = false;
		colorOverride;
		offsetX = 0;
		offsetY = 0;
		constructor(x, y, glyphScale, symbols) {
			super(x, y);
			this.glyphScale = glyphScale;
			this.symbols = symbols;
		}
		getBoundingBoxTop() {
			let bBoxTop = 0;
			for (let i = 0; i < this.symbols.length; i++) {
				const gTop = this.renderer.smuflMetrics.glyphTop.get(this.symbols[i]);
				if (i === 0 || gTop < bBoxTop) bBoxTop = gTop;
			}
			return this.y - this.offsetY - bBoxTop;
		}
		doLayout() {
			this.width = 0;
			this.height = 0;
			for (let i = 0; i < this.symbols.length; i++) {
				const gWidth = this.renderer.smuflMetrics.glyphWidths.get(this.symbols[i]) * this.glyphScale;
				const gHeight = this.renderer.smuflMetrics.glyphHeights.get(this.symbols[i]) * this.glyphScale;
				if (i === 0 || gWidth > this.width) this.width = gWidth;
				if (i === 0 || gHeight > this.height) this.height = gHeight;
			}
		}
		paint(cx, cy, canvas) {
			if (this.width === 0 && this.height === 0) return;
			const c = canvas.color;
			if (this.colorOverride) canvas.color = this.colorOverride;
			canvas.fillMusicFontSymbols(cx + this.x + this.offsetX, cy + this.y + this.offsetY, this.glyphScale, this.symbols, this.center);
			canvas.color = c;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/DynamicsGlyph.ts
	/**
	* @internal
	*/
	var DynamicsGlyph = class DynamicsGlyph extends MusicFontGlyph {
		constructor(x, y, dynamics) {
			super(x, y, 1, DynamicsGlyph._getSymbol(dynamics));
		}
		doLayout() {
			super.doLayout();
			this.center = true;
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.DynamicForte);
			const forteBaseLine = this.renderer.smuflMetrics.glyphTop.get(MusicFontSymbol.DynamicForte);
			this.offsetY = forteBaseLine;
		}
		static _getSymbol(dynamics) {
			switch (dynamics) {
				case DynamicValue.PPP: return MusicFontSymbol.DynamicPPP;
				case DynamicValue.PP: return MusicFontSymbol.DynamicPP;
				case DynamicValue.P: return MusicFontSymbol.DynamicPiano;
				case DynamicValue.MP: return MusicFontSymbol.DynamicMP;
				case DynamicValue.MF: return MusicFontSymbol.DynamicMF;
				case DynamicValue.F: return MusicFontSymbol.DynamicForte;
				case DynamicValue.FF: return MusicFontSymbol.DynamicFF;
				case DynamicValue.FFF: return MusicFontSymbol.DynamicFFF;
				case DynamicValue.PPPP: return MusicFontSymbol.DynamicPPPP;
				case DynamicValue.PPPPP: return MusicFontSymbol.DynamicPPPPP;
				case DynamicValue.PPPPPP: return MusicFontSymbol.DynamicPPPPP;
				case DynamicValue.FFFF: return MusicFontSymbol.DynamicFFFF;
				case DynamicValue.FFFFF: return MusicFontSymbol.DynamicFFFFF;
				case DynamicValue.FFFFFF: return MusicFontSymbol.DynamicFFFFFF;
				case DynamicValue.SF: return MusicFontSymbol.DynamicSforzando1;
				case DynamicValue.SFP: return MusicFontSymbol.DynamicSforzandoPiano;
				case DynamicValue.SFPP: return MusicFontSymbol.DynamicSforzandoPianissimo;
				case DynamicValue.FP: return MusicFontSymbol.DynamicFortePiano;
				case DynamicValue.RF: return MusicFontSymbol.DynamicRinforzando1;
				case DynamicValue.RFZ: return MusicFontSymbol.DynamicRinforzando2;
				case DynamicValue.SFZ: return MusicFontSymbol.DynamicSforzato;
				case DynamicValue.SFFZ: return MusicFontSymbol.DynamicSforzatoFF;
				case DynamicValue.FZ: return MusicFontSymbol.DynamicForzando;
				case DynamicValue.N: return MusicFontSymbol.DynamicNiente;
				case DynamicValue.PF: return MusicFontSymbol.DynamicPF;
				case DynamicValue.SFZP: return MusicFontSymbol.DynamicSforzatoPiano;
				default: return MusicFontSymbol.None;
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/DynamicsEffectInfo.ts
	/**
	* @internal
	*/
	var DynamicsEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectDynamics;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return this._internalShouldCreateGlyph(beat);
		}
		_internalShouldCreateGlyph(beat) {
			if (beat.voice.bar.staff.track.score.stylesheet.hideDynamics || beat.isEmpty || beat.voice.isEmpty || beat.isRest) return false;
			const previousBeat = this._getPreviousDynamicsBeat(beat);
			let show = beat.voice.index === 0 && !previousBeat || beat.dynamics !== previousBeat?.dynamics;
			if (show && beat.voice.index > 0) {
				for (const voice of beat.voice.bar.voices) if (voice.index < beat.voice.index) {
					const beatAtSamePos = voice.getBeatAtPlaybackStart(beat.playbackStart);
					if (beatAtSamePos && beat.dynamics === beatAtSamePos.dynamics && this._internalShouldCreateGlyph(beatAtSamePos)) show = false;
				}
			}
			return show;
		}
		_getPreviousDynamicsBeat(beat) {
			let previousBeat = beat.previousBeat;
			while (previousBeat != null) {
				if (!previousBeat.isRest) return previousBeat;
				previousBeat = previousBeat.previousBeat;
			}
			return null;
		}
		createNewGlyph(_renderer, beat) {
			return new DynamicsGlyph(0, 0, beat.dynamics);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/FadeGlyph.ts
	/**
	* @internal
	*/
	var FadeGlyph = class FadeGlyph extends MusicFontGlyph {
		constructor(type) {
			super(0, 0, 1, FadeGlyph._getSymbol(type));
			this.center = true;
		}
		static _getSymbol(type) {
			switch (type) {
				case FadeType.FadeIn: return MusicFontSymbol.GuitarFadeIn;
				case FadeType.FadeOut: return MusicFontSymbol.GuitarFadeOut;
				case FadeType.VolumeSwell: return MusicFontSymbol.GuitarVolumeSwell;
			}
			return MusicFontSymbol.None;
		}
		paint(cx, cy, canvas) {
			super.paint(cx, cy + this.height, canvas);
		}
	};
	//#endregion
	//#region src/rendering/effects/FadeEffectInfo.ts
	/**
	* @internal
	*/
	var FadeEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectFadeIn;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.fade !== FadeType.None;
		}
		createNewGlyph(_renderer, beat) {
			return new FadeGlyph(beat.fade);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/FermataGlyph.ts
	/**
	* @internal
	*/
	var FermataGlyph = class FermataGlyph extends MusicFontGlyph {
		constructor(x, y, fermata) {
			super(x, y, 1, FermataGlyph._getSymbol(fermata));
		}
		static _getSymbol(accentuation) {
			switch (accentuation) {
				case FermataType.Short: return MusicFontSymbol.FermataShortAbove;
				case FermataType.Medium: return MusicFontSymbol.FermataAbove;
				case FermataType.Long: return MusicFontSymbol.FermataLongAbove;
				default: return MusicFontSymbol.None;
			}
		}
		paint(cx, cy, canvas) {
			super.paint(cx - this.width / 2, cy + this.height, canvas);
		}
	};
	//#endregion
	//#region src/rendering/effects/FermataEffectInfo.ts
	/**
	* @internal
	*/
	var FermataEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectFermata;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.voice.index === 0 && !!beat.fermata;
		}
		createNewGlyph(_renderer, beat) {
			return new FermataGlyph(0, 0, beat.fermata.type);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/GlyphGroup.ts
	/**
	* This glyph allows to group several other glyphs to be
	* drawn at the same x position
	* @internal
	*/
	var GlyphGroup = class extends Glyph {
		glyphs = null;
		get isEmpty() {
			return !this.glyphs || this.glyphs.length === 0;
		}
		getBoundingBoxTop() {
			let top = NaN;
			const glyphs = this.glyphs;
			if (glyphs) for (const g of glyphs) top = ModelUtils.minBoundingBox(top, g.getBoundingBoxTop());
			return top;
		}
		getBoundingBoxBottom() {
			let bottom = NaN;
			const glyphs = this.glyphs;
			if (glyphs) for (const g of glyphs) bottom = ModelUtils.maxBoundingBox(bottom, g.getBoundingBoxBottom());
			return bottom;
		}
		doLayout() {
			if (!this.glyphs || this.glyphs.length === 0) {
				this.width = 0;
				return;
			}
			let w = 0;
			let h = 0;
			for (let i = 0, j = this.glyphs.length; i < j; i++) {
				const g = this.glyphs[i];
				g.renderer = this.renderer;
				g.doLayout();
				w = Math.max(w, g.width);
				h = Math.max(h, g.y + g.height);
			}
			this.width = w;
			this.height = h;
		}
		addGlyph(g) {
			if (!this.glyphs) this.glyphs = [];
			if (this.renderer) g.renderer = this.renderer;
			this.glyphs.push(g);
		}
		paint(cx, cy, canvas) {
			const glyphs = this.glyphs;
			if (!glyphs || glyphs.length === 0) return;
			for (const g of glyphs) g.paint(cx + this.x, cy + this.y, canvas);
		}
	};
	//#endregion
	//#region src/rendering/utils/ElementStyleHelper.ts
	/**
	* A helper to apply element styles in a specific rendering scope via the `using` keyword
	* @internal
	*/
	var ElementStyleHelper = class ElementStyleHelper {
		static score(canvas, element, score, forceDefault = false) {
			if (!score.style && !forceDefault) return;
			const defaultColor = ElementStyleHelper._scoreDefaultColor(canvas.settings.display.resources, element);
			return new ElementStyleScope(canvas, element, score.style, defaultColor);
		}
		static scoreColor(res, element, score) {
			const defaultColor = ElementStyleHelper._scoreDefaultColor(res, element);
			if (score.style && score.style.colors.has(element)) return score.style.colors.get(element) ?? defaultColor;
		}
		static _scoreDefaultColor(res, _element) {
			return res.mainGlyphColor;
		}
		static bar(canvas, element, bar, forceDefault = false) {
			if (!bar.style && !forceDefault) return;
			let defaultColor = canvas.settings.display.resources.mainGlyphColor;
			switch (element) {
				case BarSubElement.StandardNotationRepeats:
				case BarSubElement.GuitarTabsRepeats:
				case BarSubElement.SlashRepeats:
				case BarSubElement.NumberedRepeats:
				case BarSubElement.StandardNotationClef:
				case BarSubElement.GuitarTabsClef:
				case BarSubElement.StandardNotationKeySignature:
				case BarSubElement.NumberedKeySignature:
				case BarSubElement.StandardNotationTimeSignature:
				case BarSubElement.GuitarTabsTimeSignature:
				case BarSubElement.SlashTimeSignature:
				case BarSubElement.NumberedTimeSignature: break;
				case BarSubElement.StandardNotationBarLines:
				case BarSubElement.GuitarTabsBarLines:
				case BarSubElement.SlashBarLines:
				case BarSubElement.NumberedBarLines:
					defaultColor = canvas.settings.display.resources.barSeparatorColor;
					break;
				case BarSubElement.StandardNotationBarNumber:
				case BarSubElement.SlashBarNumber:
				case BarSubElement.NumberedBarNumber:
				case BarSubElement.GuitarTabsBarNumber:
					defaultColor = canvas.settings.display.resources.barNumberColor;
					break;
				case BarSubElement.StandardNotationStaffLine:
				case BarSubElement.GuitarTabsStaffLine:
				case BarSubElement.SlashStaffLine:
				case BarSubElement.NumberedStaffLine:
					defaultColor = canvas.settings.display.resources.staffLineColor;
					break;
			}
			return new ElementStyleScope(canvas, element, bar.style, defaultColor);
		}
		static voice(canvas, element, voice, forceDefault = false) {
			if (!voice.style && !forceDefault) return;
			const defaultColor = voice.index === 0 ? canvas.settings.display.resources.mainGlyphColor : canvas.settings.display.resources.secondaryGlyphColor;
			return new ElementStyleScope(canvas, element, voice.style, defaultColor);
		}
		static trackColor(res, element, track) {
			const defaultColor = ElementStyleHelper._trackDefaultColor(res, element);
			if (track.style && track.style.colors.has(element)) return track.style.colors.get(element) ?? defaultColor;
		}
		static _trackDefaultColor(res, element) {
			let defaultColor = res.mainGlyphColor;
			switch (element) {
				case TrackSubElement.TrackName:
				case TrackSubElement.SystemSeparator:
				case TrackSubElement.StringTuning: break;
				case TrackSubElement.BracesAndBrackets:
					defaultColor = res.barSeparatorColor;
					break;
			}
			return defaultColor;
		}
		static track(canvas, element, track, forceDefault = false) {
			if (!track.style && !forceDefault) return;
			const defaultColor = ElementStyleHelper._trackDefaultColor(canvas.settings.display.resources, element);
			return new ElementStyleScope(canvas, element, track.style, defaultColor);
		}
		static beatColor(res, element, beat) {
			const defaultColor = ElementStyleHelper._beatDefaultColor(res, element, beat);
			if (beat.style && beat.style.colors.has(element)) return beat.style.colors.get(element) ?? defaultColor;
		}
		static _beatDefaultColor(res, _element, beat) {
			return beat.voice.index === 0 ? res.mainGlyphColor : res.secondaryGlyphColor;
		}
		static beat(canvas, element, beat, forceDefault = false) {
			if (!beat.style && !forceDefault) return;
			const defaultColor = ElementStyleHelper._beatDefaultColor(canvas.settings.display.resources, element, beat);
			return new ElementStyleScope(canvas, element, beat.style, defaultColor);
		}
		static noteColor(res, element, note) {
			const defaultColor = ElementStyleHelper._noteDefaultColor(res, element, note);
			if (note.style && note.style.colors.has(element)) return note.style.colors.get(element) ?? defaultColor;
		}
		static _noteDefaultColor(res, _element, note) {
			return note.beat.voice.index === 0 ? res.mainGlyphColor : res.secondaryGlyphColor;
		}
		static note(canvas, element, note, forceDefault = false) {
			if (!note.style && !forceDefault) return;
			const defaultColor = note.beat.voice.index === 0 ? canvas.settings.display.resources.mainGlyphColor : canvas.settings.display.resources.secondaryGlyphColor;
			return new ElementStyleScope(canvas, element, note.style, defaultColor);
		}
	};
	/**
	* A helper class for applying elements styles to the canvas and restoring the previous state afterwards.
	* @internal
	*/
	var ElementStyleScope = class {
		_canvas;
		_previousColor;
		constructor(canvas, element, container, defaultColor) {
			this._canvas = canvas;
			if (container && container.colors.has(element)) {
				this._previousColor = canvas.color;
				canvas.color = container.colors.get(element) ?? defaultColor;
			} else if (!container) {
				this._previousColor = canvas.color;
				canvas.color = defaultColor;
			}
		}
		[Symbol.dispose]() {
			if (this._previousColor) this._canvas.color = this._previousColor;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/FingeringGroupGlyph.ts
	/**
	* @internal
	*/
	var FingeringInfo = class {
		line = 0;
		symbols;
		color;
		constructor(line, symbols) {
			this.line = line;
			this.symbols = symbols;
		}
	};
	/**
	* @internal
	*/
	var FingeringGroupGlyph = class FingeringGroupGlyph extends GlyphGroup {
		_infos = /* @__PURE__ */ new Map();
		constructor() {
			super(0, 0);
		}
		get isEmpty() {
			return this._infos.size === 0;
		}
		addFingers(note) {
			const settings = this.renderer.settings;
			if (settings.notation.fingeringMode !== FingeringMode.ScoreDefault && settings.notation.fingeringMode !== FingeringMode.ScoreForcePiano) return;
			const symbolLeft = FingeringGroupGlyph.fingerToMusicFontSymbol(this.renderer.settings, note.beat, note.leftHandFinger, true);
			if (symbolLeft !== MusicFontSymbol.None) this._addFinger(note, symbolLeft);
			const symbolRight = FingeringGroupGlyph.fingerToMusicFontSymbol(this.renderer.settings, note.beat, note.rightHandFinger, false);
			if (symbolRight !== MusicFontSymbol.None) this._addFinger(note, symbolRight);
		}
		static fingerToMusicFontSymbol(settings, beat, finger, leftHand) {
			if (settings.notation.fingeringMode === FingeringMode.ScoreForcePiano || settings.notation.fingeringMode === FingeringMode.SingleNoteEffectBandForcePiano || GeneralMidi.isPiano(beat.voice.bar.staff.track.playbackInfo.program)) switch (finger) {
				case Fingers.Unknown:
				case Fingers.NoOrDead: return MusicFontSymbol.None;
				case Fingers.Thumb: return MusicFontSymbol.Fingering1;
				case Fingers.IndexFinger: return MusicFontSymbol.Fingering2;
				case Fingers.MiddleFinger: return MusicFontSymbol.Fingering3;
				case Fingers.AnnularFinger: return MusicFontSymbol.Fingering4;
				case Fingers.LittleFinger: return MusicFontSymbol.Fingering5;
				default: return MusicFontSymbol.None;
			}
			if (leftHand) switch (finger) {
				case Fingers.Unknown: return MusicFontSymbol.None;
				case Fingers.NoOrDead: return MusicFontSymbol.Fingering0;
				case Fingers.Thumb: return MusicFontSymbol.FingeringTLower;
				case Fingers.IndexFinger: return MusicFontSymbol.Fingering1;
				case Fingers.MiddleFinger: return MusicFontSymbol.Fingering2;
				case Fingers.AnnularFinger: return MusicFontSymbol.Fingering3;
				case Fingers.LittleFinger: return MusicFontSymbol.Fingering4;
				default: return MusicFontSymbol.None;
			}
			switch (finger) {
				case Fingers.Unknown:
				case Fingers.NoOrDead: return MusicFontSymbol.None;
				case Fingers.Thumb: return MusicFontSymbol.FingeringPLower;
				case Fingers.IndexFinger: return MusicFontSymbol.FingeringILower;
				case Fingers.MiddleFinger: return MusicFontSymbol.FingeringMLower;
				case Fingers.AnnularFinger: return MusicFontSymbol.FingeringALower;
				case Fingers.LittleFinger: return MusicFontSymbol.FingeringCLower;
				default: return MusicFontSymbol.None;
			}
		}
		_addFinger(note, symbol) {
			const sr = this.renderer;
			const steps = sr.getNoteSteps(note);
			if (!this._infos.has(steps)) {
				const info = new FingeringInfo(steps, [symbol]);
				info.color = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationEffects, note);
				this._infos.set(steps, info);
			} else this._infos.get(steps).symbols.push(symbol);
		}
		doLayout() {
			const sr = this.renderer;
			for (const [_, info] of this._infos) {
				const g = new MusicFontTextGlyph(0, 0, 1, info.symbols);
				g.colorOverride = info.color;
				g.renderer = sr;
				g.y = sr.getScoreY(info.line);
				g.doLayout();
				g.offsetY = g.height / 2;
				this.addGlyph(g);
				this.width = Math.max(this.width, g.width);
			}
			for (const g of this.glyphs) {
				const m = g;
				m.x = this.width / 2;
				m.center = true;
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/FingeringEffectInfo.ts
	/**
	* @internal
	*/
	var FingeringEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectFingering;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(settings, beat) {
			if (beat.voice.index !== 0 || beat.isRest || settings.notation.fingeringMode !== FingeringMode.SingleNoteEffectBand && settings.notation.fingeringMode !== FingeringMode.SingleNoteEffectBandForcePiano) return false;
			if (beat.notes.length !== 1) return false;
			return beat.notes[0].isFingering;
		}
		createNewGlyph(renderer, beat) {
			let finger = Fingers.Unknown;
			let isLeft = false;
			const note = beat.notes[0];
			if (note.leftHandFinger !== Fingers.Unknown) {
				finger = note.leftHandFinger;
				isLeft = true;
			} else if (note.rightHandFinger !== Fingers.Unknown) finger = note.rightHandFinger;
			const g = new MusicFontGlyph(0, 0, 1, FingeringGroupGlyph.fingerToMusicFontSymbol(renderer.settings, beat, finger, isLeft));
			g.center = true;
			g.renderer = renderer;
			g.doLayout();
			g.offsetY = renderer.smuflMetrics.glyphTop.get(g.symbol);
			return g;
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/FreeTimeEffectInfo.ts
	/**
	* @internal
	*/
	var FreeTimeEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectText;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SinglePreBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			const masterBar = beat.voice.bar.masterBar;
			return beat.voice.bar.staff.index === 0 && beat.voice.index === 0 && beat.index === 0 && masterBar.isFreeTime && (masterBar.index === 0 || masterBar.isFreeTime !== masterBar.previousMasterBar.isFreeTime);
		}
		createNewGlyph(renderer, _beat) {
			return new TextGlyph(0, 0, "Free time", renderer.resources.elementFonts.get(NotationElement.EffectFreeTime), TextAlign.Left);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/GuitarGolpeGlyph.ts
	/**
	* @internal
	*/
	var GuitarGolpeGlyph = class extends MusicFontGlyph {
		constructor(x, y, center = false) {
			super(x, y, EngravingSettings.GraceScale, MusicFontSymbol.GuitarGolpe);
			this.center = center;
		}
		doLayout() {
			super.doLayout();
			this.offsetY = this.height;
		}
	};
	//#endregion
	//#region src/rendering/effects/GolpeEffectInfo.ts
	/**
	* @internal
	*/
	var GolpeEffectInfo = class extends EffectInfo {
		_type;
		constructor(type) {
			super();
			this._type = type;
		}
		get notationElement() {
			return NotationElement.EffectGolpe;
		}
		get effectId() {
			return `${super.effectId}.${GolpeType[this._type]}`;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.golpe === this._type;
		}
		createNewGlyph(_renderer, _beat) {
			return new GuitarGolpeGlyph(0, 0, true);
		}
		canExpand(_from, _to) {
			return false;
		}
	};
	//#endregion
	//#region src/rendering/effects/NoteEffectInfoBase.ts
	/**
	* @internal
	*/
	var NoteEffectInfoBase = class extends EffectInfo {
		lastCreateInfo = null;
		shouldCreateGlyph(_settings, beat) {
			this.lastCreateInfo = [];
			for (let i = 0, j = beat.notes.length; i < j; i++) {
				const n = beat.notes[i];
				if (this.shouldCreateGlyphForNote(n)) this.lastCreateInfo.push(n);
			}
			return this.lastCreateInfo.length > 0;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/HarmonicsEffectInfo.ts
	/**
	* @internal
	*/
	var HarmonicsEffectInfo = class HarmonicsEffectInfo extends NoteEffectInfoBase {
		_harmonicType;
		_beat = null;
		_effectId;
		get effectId() {
			return this._effectId;
		}
		get notationElement() {
			return NotationElement.EffectHarmonics;
		}
		constructor(harmonicType) {
			super();
			this._harmonicType = harmonicType;
			switch (harmonicType) {
				case HarmonicType.None:
					this._effectId = "harmonics-none";
					break;
				case HarmonicType.Natural:
					this._effectId = "harmonics-natural";
					break;
				case HarmonicType.Artificial:
					this._effectId = "harmonics-artificial";
					break;
				case HarmonicType.Pinch:
					this._effectId = "harmonics-pinch";
					break;
				case HarmonicType.Tap:
					this._effectId = "harmonics-tap";
					break;
				case HarmonicType.Semi:
					this._effectId = "harmonics-semi";
					break;
				case HarmonicType.Feedback:
					this._effectId = "harmonics-feedback";
					break;
				default:
					this._effectId = "";
					break;
			}
		}
		shouldCreateGlyphForNote(note) {
			if (!note.isHarmonic || note.harmonicType !== this._harmonicType) return false;
			if (note.beat !== this._beat) this._beat = note.beat;
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		createNewGlyph(_renderer, _beat) {
			return new LineRangedGlyph(HarmonicsEffectInfo.harmonicToString(this._harmonicType), NotationElement.EffectHarmonics);
		}
		static harmonicToString(type) {
			switch (type) {
				case HarmonicType.Natural: return "N.H.";
				case HarmonicType.Artificial: return "A.H.";
				case HarmonicType.Pinch: return "P.H.";
				case HarmonicType.Tap: return "T.H.";
				case HarmonicType.Semi: return "S.H.";
				case HarmonicType.Feedback: return "Fdbk.";
			}
			return "";
		}
	};
	//#endregion
	//#region src/rendering/glyphs/LeftHandTapGlyph.ts
	/**
	* @internal
	*/
	var LeftHandTapGlyph = class extends MusicFontGlyph {
		constructor() {
			super(0, 0, 1, MusicFontSymbol.GuitarLeftHandTapping);
			this.center = true;
		}
		doLayout() {
			super.doLayout();
			this.offsetY = this.renderer.smuflMetrics.glyphTop.get(this.symbol);
		}
	};
	//#endregion
	//#region src/rendering/effects/LeftHandTapEffectInfo.ts
	/**
	* @internal
	*/
	var LeftHandTapEffectInfo = class extends NoteEffectInfoBase {
		get notationElement() {
			return NotationElement.EffectTap;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyphForNote(note) {
			return note.isLeftHandTapped;
		}
		createNewGlyph(_renderer, _beat) {
			return new LeftHandTapGlyph();
		}
	};
	//#endregion
	//#region src/rendering/effects/LetRingEffectInfo.ts
	/**
	* @internal
	*/
	var LetRingEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectLetRing;
		}
		get canShareBand() {
			return false;
		}
		get hideOnMultiTrack() {
			return false;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.isLetRing;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		createNewGlyph(_renderer, _beat) {
			return new LineRangedGlyph("LetRing", NotationElement.EffectLetRing);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/LyricsGlyph.ts
	/**
	* @internal
	*/
	var LyricsGlyph = class extends EffectGlyph {
		_lines;
		_linePositions = [];
		font;
		textAlign;
		constructor(x, y, lines, font, textAlign = TextAlign.Center) {
			super(x, y);
			this._lines = lines;
			this.font = font;
			this.textAlign = textAlign;
		}
		doLayout() {
			super.doLayout();
			const lineSpacing = this.renderer.settings.display.lyricLinesPaddingBetween;
			const canvas = this.renderer.scoreRenderer.canvas;
			canvas.font = this.font;
			let y = 0;
			for (const line of this._lines) {
				this._linePositions.push(y);
				const size = canvas.measureText(line.length > 0 ? line : " ");
				y += size.height + lineSpacing;
			}
			y -= lineSpacing;
			this.height = y;
		}
		paint(cx, cy, canvas) {
			canvas.font = this.font;
			const old = canvas.textAlign;
			canvas.textAlign = this.textAlign;
			for (let i = 0; i < this._lines.length; i++) if (this._lines[i]) canvas.fillText(this._lines[i], cx + this.x, cy + this.y + this._linePositions[i]);
			canvas.textAlign = old;
		}
	};
	//#endregion
	//#region src/rendering/effects/LyricsEffectInfo.ts
	/**
	* @internal
	*/
	var LyricsEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectLyrics;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return !!beat.lyrics;
		}
		createNewGlyph(renderer, beat) {
			return new LyricsGlyph(0, 0, beat.lyrics, renderer.resources.elementFonts.get(NotationElement.EffectLyrics), TextAlign.Center);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/MarkerEffectInfo.ts
	/**
	* @internal
	*/
	var MarkerEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectMarker;
		}
		get hideOnMultiTrack() {
			return true;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SinglePreBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.voice.bar.staff.index === 0 && beat.voice.index === 0 && beat.index === 0 && beat.voice.bar.masterBar.isSectionStart;
		}
		createNewGlyph(renderer, beat) {
			return new TextGlyph(0, 0, !beat.voice.bar.masterBar.section.marker ? beat.voice.bar.masterBar.section.text : `[${beat.voice.bar.masterBar.section.marker}] ${beat.voice.bar.masterBar.section.text}`, renderer.resources.elementFonts.get(NotationElement.EffectMarker), TextAlign.Left);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NoteOrnamentGlyph.ts
	/**
	* @internal
	*/
	var NoteOrnamentGlyph = class NoteOrnamentGlyph extends MusicFontGlyph {
		constructor(ornament) {
			super(0, 0, 1, NoteOrnamentGlyph._getSymbol(ornament));
			this.center = true;
		}
		static _getSymbol(ornament) {
			switch (ornament) {
				case NoteOrnament.InvertedTurn: return MusicFontSymbol.OrnamentTurnInverted;
				case NoteOrnament.Turn: return MusicFontSymbol.OrnamentTurn;
				case NoteOrnament.UpperMordent: return MusicFontSymbol.OrnamentShortTrill;
				case NoteOrnament.LowerMordent: return MusicFontSymbol.OrnamentMordent;
			}
			return MusicFontSymbol.None;
		}
		doLayout() {
			super.doLayout();
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.OrnamentMordent);
			this.offsetY = this.renderer.smuflMetrics.glyphTop.get(MusicFontSymbol.OrnamentMordent);
		}
	};
	//#endregion
	//#region src/rendering/effects/NoteOrnamentEffectInfo.ts
	/**
	* @internal
	*/
	var NoteOrnamentEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectNoteOrnament;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.notes.some((n) => n.ornament !== NoteOrnament.None);
		}
		createNewGlyph(_renderer, beat) {
			return new NoteOrnamentGlyph(beat.notes.find((n) => n.ornament !== NoteOrnament.None).ornament);
		}
		canExpand(_from, _to) {
			return false;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/AccidentalGlyph.ts
	/**
	* @internal
	*/
	var AccidentalGlyph = class AccidentalGlyph extends MusicFontGlyph {
		constructor(x, y, accidentalType, scale) {
			super(x, y, scale, AccidentalGlyph.getMusicSymbol(accidentalType));
		}
		static getMusicSymbol(accidentalType) {
			switch (accidentalType) {
				case AccidentalType.Natural: return MusicFontSymbol.AccidentalNatural;
				case AccidentalType.Sharp: return MusicFontSymbol.AccidentalSharp;
				case AccidentalType.Flat: return MusicFontSymbol.AccidentalFlat;
				case AccidentalType.NaturalQuarterNoteUp: return MusicFontSymbol.AccidentalQuarterToneSharpNaturalArrowUp;
				case AccidentalType.SharpQuarterNoteUp: return MusicFontSymbol.AccidentalThreeQuarterTonesSharpArrowUp;
				case AccidentalType.FlatQuarterNoteUp: return MusicFontSymbol.AccidentalQuarterToneFlatArrowUp;
				case AccidentalType.DoubleSharp: return MusicFontSymbol.AccidentalDoubleSharp;
				case AccidentalType.DoubleFlat: return MusicFontSymbol.AccidentalDoubleFlat;
			}
			return MusicFontSymbol.None;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NumberedKeySignatureGlyph.ts
	/**
	* @internal
	*/
	var NumberedKeySignatureGlyph = class extends EffectGlyph {
		_keySignature;
		_keySignatureType;
		_text = "";
		_accidental = AccidentalType.None;
		_accidentalOffset = 0;
		_padding = 0;
		constructor(x, y, keySignature, keySignatureType) {
			super(x, y);
			this._keySignature = keySignature;
			this._keySignatureType = keySignatureType;
		}
		doLayout() {
			super.doLayout();
			let text = "";
			let text2 = "";
			let accidental = AccidentalType.None;
			switch (this._keySignatureType) {
				case KeySignatureType.Major:
					text = "1 = ";
					switch (this._keySignature) {
						case KeySignature.Cb:
							text2 = "  C";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Gb:
							text2 = "  G";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Db:
							text2 = "  D";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Ab:
							text2 = "  A";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Eb:
							text2 = "  E";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Bb:
							text2 = "  B";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.F:
							text2 = "F";
							break;
						case KeySignature.C:
							text2 = "C";
							accidental = AccidentalType.None;
							break;
						case KeySignature.G:
							text2 = "G";
							accidental = AccidentalType.None;
							break;
						case KeySignature.D:
							text2 = "D";
							accidental = AccidentalType.None;
							break;
						case KeySignature.A:
							text2 = "A";
							accidental = AccidentalType.None;
							break;
						case KeySignature.E:
							text2 = "E";
							accidental = AccidentalType.None;
							break;
						case KeySignature.B:
							text2 = "B";
							accidental = AccidentalType.None;
							break;
						case KeySignature.FSharp:
							text2 = "  F";
							accidental = AccidentalType.Sharp;
							break;
						case KeySignature.CSharp:
							text2 = "  C";
							accidental = AccidentalType.Sharp;
							break;
					}
					break;
				case KeySignatureType.Minor:
					text = "6 = ";
					switch (this._keySignature) {
						case KeySignature.Cb:
							text2 = "  a";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Gb:
							text2 = "  e";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Db:
							text2 = "  b";
							accidental = AccidentalType.Flat;
							break;
						case KeySignature.Ab:
							text2 = "f";
							accidental = AccidentalType.None;
							break;
						case KeySignature.Eb:
							text2 = "c";
							accidental = AccidentalType.None;
							break;
						case KeySignature.Bb:
							text2 = "g";
							accidental = AccidentalType.None;
							break;
						case KeySignature.F:
							text2 = "d";
							break;
						case KeySignature.C:
							text2 = "a";
							accidental = AccidentalType.None;
							break;
						case KeySignature.G:
							text2 = "e";
							accidental = AccidentalType.None;
							break;
						case KeySignature.D:
							text2 = "b";
							accidental = AccidentalType.None;
							break;
						case KeySignature.A:
							text2 = "  f";
							accidental = AccidentalType.Sharp;
							break;
						case KeySignature.E:
							text2 = "  c";
							accidental = AccidentalType.Sharp;
							break;
						case KeySignature.B:
							text2 = "  g";
							accidental = AccidentalType.Sharp;
							break;
						case KeySignature.FSharp:
							text2 = "  d";
							accidental = AccidentalType.Sharp;
							break;
						case KeySignature.CSharp:
							text2 = "  a";
							accidental = AccidentalType.Sharp;
							break;
					}
					break;
			}
			this._text = text + text2;
			this._accidental = accidental;
			const c = this.renderer.scoreRenderer.canvas;
			const settings = this.renderer.settings;
			c.font = settings.display.resources.numberedNotationFont;
			this._accidentalOffset = c.measureText(text).width;
			const fullSize = c.measureText(text + text2);
			this._padding = this.renderer.index === 0 ? settings.display.firstStaffPaddingLeft : settings.display.staffPaddingLeft;
			this.width = this._padding + fullSize.width;
			this.height = fullSize.height;
		}
		paint(cx, cy, canvas) {
			const _ = ElementStyleHelper.bar(canvas, BarSubElement.NumberedKeySignature, this.renderer.bar);
			try {
				canvas.font = this.renderer.resources.numberedNotationFont;
				canvas.textBaseline = TextBaseline.Alphabetic;
				canvas.fillText(this._text, cx + this.x + this._padding, cy + this.y + this.height);
				if (this._accidental !== AccidentalType.None) CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + this._padding + this._accidentalOffset, cy + this.y + this.height, 1, AccidentalGlyph.getMusicSymbol(this._accidental), false);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/NumberedBarKeySignatureEffectInfo.ts
	/**
	* @internal
	*/
	var NumberedBarKeySignatureEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectNumberedNotationKeySignature;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.FullBar;
		}
		shouldCreateGlyph(_settings, beat) {
			const bar = beat.voice.bar;
			return beat.index === 0 && beat.voice.index === 0 && (!bar.previousBar || bar.keySignature !== bar.previousBar.keySignature);
		}
		createNewGlyph(renderer, _beat) {
			return new NumberedKeySignatureGlyph(0, 0, renderer.bar.keySignature, renderer.bar.keySignatureType);
		}
		canExpand(_from, _to) {
			return false;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/OttavaGlyph.ts
	/**
	* @internal
	*/
	var OttavaGlyph = class extends GroupedEffectGlyph {
		_ottava;
		_aboveStaff;
		constructor(ottava, aboveStaff) {
			super(BeatXPosition.PostNotes);
			this._ottava = ottava;
			this._aboveStaff = aboveStaff;
		}
		doLayout() {
			super.doLayout();
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.QuindicesimaAlta);
		}
		paintNonGrouped(cx, cy, canvas) {
			this._paintOttava(cx, cy, canvas);
		}
		_paintOttava(cx, cy, canvas) {
			let size = 0;
			switch (this._ottava) {
				case Ottavia._15ma:
					size = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.QuindicesimaAlta);
					CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x - size / 2, cy + this.y + this.height, 1, MusicFontSymbol.QuindicesimaAlta, false);
					break;
				case Ottavia._8va:
					size = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.OttavaAlta);
					CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x - size / 2, cy + this.y + this.height, 1, MusicFontSymbol.OttavaAlta, false);
					break;
				case Ottavia._8vb:
					size = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.OttavaBassaVb);
					CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x - size / 2, cy + this.y + this.height, 1, MusicFontSymbol.OttavaBassaVb, false);
					break;
				case Ottavia._15mb:
					size = (this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.Quindicesima) + this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.OctaveBaselineM) + this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.OctaveBaselineB)) * 1;
					CanvasHelper.fillMusicFontSymbolsSafe(canvas, cx + this.x - size / 2, cy + this.y + this.height, 1, [
						MusicFontSymbol.Quindicesima,
						MusicFontSymbol.OctaveBaselineM,
						MusicFontSymbol.OctaveBaselineB
					], false);
					break;
			}
			return size / 2;
		}
		paintGrouped(cx, cy, endX, canvas) {
			const size = this._paintOttava(cx, cy, canvas);
			const lineSpacing = this.renderer.smuflMetrics.lineRangedGlyphDashGap;
			const startX = cx + this.x + size + lineSpacing;
			let lineY = cy + this.y;
			const padding = this.height * .5;
			lineY += this._aboveStaff ? 0 : this.height;
			const lineSize = this.renderer.smuflMetrics.lineRangedGlyphDashSize;
			const lw = canvas.lineWidth;
			canvas.lineWidth = this.renderer.smuflMetrics.octaveLineThickness;
			if (endX > startX) {
				let lineX = startX;
				while (lineX < endX) {
					canvas.beginPath();
					canvas.moveTo(lineX, lineY | 0);
					canvas.lineTo(Math.min(lineX + lineSize, endX), lineY | 0);
					lineX += lineSize + lineSpacing;
					canvas.stroke();
				}
				canvas.beginPath();
				if (this._aboveStaff) {
					canvas.moveTo(endX, lineY);
					canvas.lineTo(endX, lineY + padding);
				} else {
					canvas.moveTo(endX, lineY);
					canvas.lineTo(endX, lineY - padding);
				}
				canvas.stroke();
			}
			canvas.lineWidth = lw;
		}
	};
	//#endregion
	//#region src/rendering/effects/OttaviaEffectInfo.ts
	/**
	* @internal
	*/
	var OttaviaEffectInfo = class extends EffectInfo {
		_aboveStaff;
		get effectId() {
			return `ottavia-${this._aboveStaff ? "above" : "below"}`;
		}
		get notationElement() {
			return NotationElement.EffectOttavia;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		constructor(aboveStaff) {
			super();
			this._aboveStaff = aboveStaff;
		}
		shouldCreateGlyph(_settings, beat) {
			switch (beat.ottava) {
				case Ottavia._15ma: return this._aboveStaff;
				case Ottavia._8va: return this._aboveStaff;
				case Ottavia._8vb: return !this._aboveStaff;
				case Ottavia._15mb: return !this._aboveStaff;
			}
			return false;
		}
		createNewGlyph(_renderer, beat) {
			return new OttavaGlyph(beat.ottava, this._aboveStaff);
		}
		canExpand(from, to) {
			return from.ottava === to.ottava;
		}
	};
	//#endregion
	//#region src/rendering/effects/PalmMuteEffectInfo.ts
	/**
	* @internal
	*/
	var PalmMuteEffectInfo = class extends NoteEffectInfoBase {
		get notationElement() {
			return NotationElement.EffectPalmMute;
		}
		shouldCreateGlyphForNote(note) {
			return note.isPalmMute;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		createNewGlyph(_renderer, _beat) {
			return new LineRangedGlyph("P.M.", NotationElement.EffectPalmMute);
		}
	};
	//#endregion
	//#region src/rendering/effects/PickSlideEffectInfo.ts
	/**
	* @internal
	*/
	var PickSlideEffectInfo = class extends NoteEffectInfoBase {
		get notationElement() {
			return NotationElement.EffectPickSlide;
		}
		shouldCreateGlyphForNote(note) {
			return note.slideOutType === SlideOutType.PickSlideDown || note.slideOutType === SlideOutType.PickSlideUp;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		createNewGlyph(_renderer, _beat) {
			return new LineRangedGlyph("P.S.", NotationElement.EffectPickSlide);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/PickStrokeGlyph.ts
	/**
	* @internal
	*/
	var PickStrokeGlyph = class PickStrokeGlyph extends MusicFontGlyph {
		constructor(x, y, pickStroke) {
			super(x, y, EngravingSettings.GraceScale, PickStrokeGlyph._getSymbol(pickStroke));
			this.center = true;
		}
		doLayout() {
			super.doLayout();
			this.offsetY = this.height;
		}
		static _getSymbol(pickStroke) {
			switch (pickStroke) {
				case PickStroke.Up: return MusicFontSymbol.StringsUpBow;
				case PickStroke.Down: return MusicFontSymbol.StringsDownBow;
				default: return MusicFontSymbol.None;
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/PickStrokeEffectInfo.ts
	/**
	* @internal
	*/
	var PickStrokeEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectPickStroke;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.pickStroke !== PickStroke.None;
		}
		createNewGlyph(_renderer, beat) {
			return new PickStrokeGlyph(0, 0, beat.pickStroke);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/RasgueadoEffectInfo.ts
	/**
	* @internal
	*/
	var RasgueadoEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectRasgueado;
		}
		get canShareBand() {
			return false;
		}
		get hideOnMultiTrack() {
			return false;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.hasRasgueado;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		createNewGlyph(_renderer, _beat) {
			return new LineRangedGlyph("rasg.", NotationElement.EffectRasgueado);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/EffectBand.ts
	/**
	* @internal
	*/
	var EffectBand = class EffectBand extends Glyph {
		_uniqueEffectGlyphs = [];
		_effectGlyphs = [];
		_container;
		isEmpty = true;
		previousBand = null;
		isLinkedToPrevious = false;
		firstBeat = null;
		lastBeat = null;
		height = 0;
		originalHeight = 0;
		voice;
		info;
		slot = null;
		constructor(voice, info, container) {
			super(0, 0);
			this.voice = voice;
			this.info = info;
			this._container = container;
		}
		*iterateAllGlyphs() {
			for (const v of this._effectGlyphs) for (const g of v.values()) yield g;
		}
		finalizeBand() {
			this.info.finalizeBand(this);
		}
		doLayout() {
			super.doLayout();
			for (let i = 0; i < this.renderer.bar.voices.length; i++) {
				this._effectGlyphs.push(/* @__PURE__ */ new Map());
				this._uniqueEffectGlyphs.push([]);
			}
		}
		static shouldCreateGlyph(beat, info, renderer) {
			return info.shouldCreateGlyph(renderer.settings, beat) && (!info.hideOnMultiTrack || renderer.staff.trackIndex === 0);
		}
		createGlyph(beat) {
			if (beat.voice !== this.voice) return;
			if (EffectBand.shouldCreateGlyph(beat, this.info, this.renderer)) {
				this.isEmpty = false;
				if (!this.firstBeat || beat.isBefore(this.firstBeat)) this.firstBeat = beat;
				if (!this.lastBeat || beat.isAfter(this.lastBeat)) {
					this.lastBeat = beat;
					switch (this.info.sizingMode) {
						case EffectBarGlyphSizing.SingleOnBeatToEnd:
						case EffectBarGlyphSizing.GroupedOnBeatToEnd:
							if (this.lastBeat.nextBeat) this.lastBeat = this.lastBeat.nextBeat;
							break;
					}
				}
				const glyph = this._createOrResizeGlyph(this.info.sizingMode, beat);
				if (glyph.height > this.height) {
					this.height = glyph.height;
					this.originalHeight = glyph.height;
				}
			}
		}
		resetHeight() {
			this.height = this.originalHeight;
		}
		_createOrResizeGlyph(sizing, b) {
			let g;
			switch (sizing) {
				case EffectBarGlyphSizing.FullBar:
					g = this.info.createNewGlyph(this.renderer, b);
					g.renderer = this.renderer;
					g.beat = b;
					g.doLayout();
					this._effectGlyphs[b.voice.index].set(b.index, g);
					this._uniqueEffectGlyphs[b.voice.index].push(g);
					return g;
				case EffectBarGlyphSizing.SinglePreBeat:
				case EffectBarGlyphSizing.SingleOnBeat:
				case EffectBarGlyphSizing.SingleOnBeatToEnd:
					g = this.info.createNewGlyph(this.renderer, b);
					g.renderer = this.renderer;
					g.beat = b;
					g.doLayout();
					this._effectGlyphs[b.voice.index].set(b.index, g);
					this._uniqueEffectGlyphs[b.voice.index].push(g);
					return g;
				case EffectBarGlyphSizing.GroupedOnBeat:
				case EffectBarGlyphSizing.GroupedOnBeatToEnd:
					const singleSizing = sizing === EffectBarGlyphSizing.GroupedOnBeat ? EffectBarGlyphSizing.SingleOnBeat : EffectBarGlyphSizing.SingleOnBeatToEnd;
					if (b.index > 0 || this.renderer.index > 0) {
						const prevBeat = b.previousBeat;
						if (this.info.shouldCreateGlyph(this.renderer.settings, prevBeat)) {
							let prevEffect = null;
							if (b.index > 0 && this._effectGlyphs[b.voice.index].has(prevBeat.index)) prevEffect = this._effectGlyphs[b.voice.index].get(prevBeat.index);
							else if (this.renderer.index > 0) {
								const previousBand = this._container.previousContainer.getBand(prevBeat.voice, this.info.effectId);
								if (previousBand) {
									const voiceGlyphs = previousBand._effectGlyphs[prevBeat.voice.index];
									if (voiceGlyphs.has(prevBeat.index)) prevEffect = voiceGlyphs.get(prevBeat.index);
								}
							}
							const newGlyph = this._createOrResizeGlyph(singleSizing, b);
							if (prevEffect && this.info.canExpand(prevBeat, b)) {
								prevEffect.nextGlyph = newGlyph;
								newGlyph.previousGlyph = prevEffect;
								this.isLinkedToPrevious = true;
							}
							return newGlyph;
						}
						return this._createOrResizeGlyph(singleSizing, b);
					}
					return this._createOrResizeGlyph(singleSizing, b);
				default: return this._createOrResizeGlyph(EffectBarGlyphSizing.SingleOnBeat, b);
			}
		}
		paint(cx, cy, canvas) {
			super.paint(cx, cy, canvas);
			for (let i = 0, j = this._uniqueEffectGlyphs.length; i < j; i++) {
				const v = this._uniqueEffectGlyphs[i];
				for (let k = 0, l = v.length; k < l; k++) {
					const g = v[k];
					const _ = ElementStyleHelper.beat(canvas, BeatSubElement.Effects, g.beat, false);
					try {
						g.paint(cx + this.x, cy + this.y, canvas);
					} finally {
						_?.[Symbol.dispose]?.();
					}
				}
			}
		}
		alignGlyphs() {
			for (let v = 0; v < this._effectGlyphs.length; v++) for (const beatIndex of this._effectGlyphs[v].keys()) {
				const g = this.renderer.bar.voices[v].beats[beatIndex];
				this._alignGlyph(this.info.sizingMode, g);
			}
			this.info.onAlignGlyphs(this);
		}
		_alignGlyph(sizing, beat) {
			const g = this._effectGlyphs[beat.voice.index].get(beat.index);
			const container = this.renderer.getBeatContainer(beat);
			switch (sizing) {
				case EffectBarGlyphSizing.SinglePreBeat:
					const offsetToBegin = this.renderer.layoutingInfo.getPreBeatSize(beat);
					g.x = this.renderer.beatGlyphsStart + container.x + container.onTimeX - offsetToBegin;
					break;
				case EffectBarGlyphSizing.SingleOnBeat:
				case EffectBarGlyphSizing.GroupedOnBeat:
					g.x = this.renderer.beatGlyphsStart + container.x + container.onTimeX;
					break;
				case EffectBarGlyphSizing.SingleOnBeatToEnd:
				case EffectBarGlyphSizing.GroupedOnBeatToEnd:
					g.x = this.renderer.beatGlyphsStart + container.x + container.onTimeX;
					if (container.isLastOfVoice) g.width = this.renderer.width - g.x;
					else g.width = this.renderer.layoutingInfo.getPostBeatSize(beat);
					break;
				case EffectBarGlyphSizing.FullBar:
					g.width = this.renderer.width;
					break;
			}
		}
	};
	//#endregion
	//#region src/rendering/EffectBandSlot.ts
	/**
	* @internal
	*/
	var EffectBandSlotShared = class {
		uniqueEffectId = null;
		y = 0;
		height = 0;
		firstBeat = null;
		lastBeat = null;
	};
	/**
	* @internal
	*/
	var EffectBandSlot = class {
		bands;
		shared;
		constructor() {
			this.bands = [];
			this.shared = new EffectBandSlotShared();
		}
		update(effectBand) {
			if (!effectBand.info.canShareBand) this.shared.uniqueEffectId = effectBand.info.effectId;
			effectBand.slot = this;
			this.bands.push(effectBand);
			if (effectBand.height > this.shared.height) this.shared.height = effectBand.height;
			if (!this.shared.firstBeat || effectBand.firstBeat.isBefore(this.shared.firstBeat)) this.shared.firstBeat = effectBand.firstBeat;
			if (!this.shared.lastBeat || effectBand.lastBeat.isAfter(this.shared.lastBeat)) this.shared.lastBeat = effectBand.lastBeat;
		}
		canBeUsed(band) {
			if (!(!this.shared.uniqueEffectId && band.info.canShareBand || band.info.effectId === this.shared.uniqueEffectId)) return false;
			if (!this.shared.firstBeat) return true;
			if (this.shared.lastBeat === band.firstBeat) return true;
			if (this.shared.lastBeat.isBefore(band.firstBeat)) return true;
			if (this.shared.lastBeat.isBefore(this.shared.firstBeat)) return true;
			return false;
		}
	};
	//#endregion
	//#region src/rendering/EffectBandSizingInfo.ts
	/**
	* @internal
	*/
	var EffectBandSizingInfo = class {
		_effectSlot;
		_assignedSlots;
		slots;
		owner;
		constructor(owner) {
			this.slots = [];
			this._effectSlot = /* @__PURE__ */ new Map();
			this._assignedSlots = /* @__PURE__ */ new Map();
			this.owner = owner;
		}
		reset() {
			this._effectSlot.clear();
			this._assignedSlots.clear();
			this.slots = [];
		}
		getOrCreateSlot(band) {
			if (this._assignedSlots.has(band)) return this._assignedSlots.get(band);
			if (this._effectSlot.has(band.info.effectId)) {
				const slot = this._effectSlot.get(band.info.effectId);
				if (slot.canBeUsed(band)) {
					this._assignedSlots.set(band, slot);
					return slot;
				}
			}
			for (const slot of this.slots) if (slot.canBeUsed(band)) {
				this._assignedSlots.set(band, slot);
				return slot;
			}
			const newSlot = new EffectBandSlot();
			this.slots.push(newSlot);
			this._assignedSlots.set(band, newSlot);
			return newSlot;
		}
		register(effectBand) {
			const freeSlot = this.getOrCreateSlot(effectBand);
			freeSlot.update(effectBand);
			this._effectSlot.set(effectBand.info.effectId, freeSlot);
		}
		sortSlots(sortOrder) {
			for (const s of this.slots) s.bands.sort((a, b) => {
				return sortOrder.get(a.info) - sortOrder.get(b.info);
			});
			this.slots.sort((a, b) => {
				return sortOrder.get(a.bands[0].info) - sortOrder.get(b.bands[0].info);
			});
		}
	};
	//#endregion
	//#region src/rendering/EffectBandContainer.ts
	/**
	* Wraps the whole effect band staff for having two times the same container
	* holding bands (one for the top effects, one for the bottom effects)
	* @internal
	*/
	var EffectBandContainer = class {
		_bands = [];
		_bandLookup = /* @__PURE__ */ new Map();
		_effectBandSizingInfo = null;
		_effectInfosSortOrder = /* @__PURE__ */ new Map();
		height = 0;
		infos;
		_renderer;
		_isTopContainer;
		alignGlyphs() {
			for (const effectBand of this._bands) effectBand.alignGlyphs();
		}
		get previousContainer() {
			return this._renderer.index === 0 ? void 0 : this._isTopContainer ? this._renderer.previousRenderer.topEffects : this._renderer.previousRenderer.bottomEffects;
		}
		get isLinkedToPreviousRenderer() {
			return this._bands.some((b) => b.isLinkedToPrevious);
		}
		constructor(renderer, isTopContainer) {
			this._renderer = renderer;
			this._isTopContainer = isTopContainer;
		}
		reLayout() {
			this.resetEffectBandSizingInfo();
			this.sizeAndAlignEffectBands();
		}
		afterStaffBarReverted() {
			this.resetEffectBandSizingInfo();
			this.sizeAndAlignEffectBands();
		}
		createVoiceGlyphs(voice) {
			let i = 0;
			const renderer = this._renderer;
			const notationSettings = renderer.settings.notation;
			for (const info of this.infos) {
				if (!notationSettings.isNotationElementVisible(info.effect.notationElement)) continue;
				let band = void 0;
				this._effectInfosSortOrder.set(info.effect, info.order ?? i);
				for (const b of voice.beats) {
					if (!band && EffectBand.shouldCreateGlyph(b, info.effect, renderer)) {
						band = new EffectBand(voice, info.effect, this);
						band.renderer = this._renderer;
						band.doLayout();
						this._bands.push(band);
						this._bandLookup.set(`${voice.index}.${info.effect.effectId}`, band);
					}
					if (band !== void 0) band.createGlyph(b);
				}
				i++;
			}
		}
		doLayout() {
			this._effectInfosSortOrder.clear();
			this._bands = [];
			this._bandLookup = /* @__PURE__ */ new Map();
			this.resetEffectBandSizingInfo();
		}
		resetEffectBandSizingInfo() {
			if (this._renderer.index > 0) this._effectBandSizingInfo = this.previousContainer._effectBandSizingInfo;
			else if (this._effectBandSizingInfo && this._effectBandSizingInfo.owner === this) this._effectBandSizingInfo.reset();
			else this._effectBandSizingInfo = new EffectBandSizingInfo(this);
		}
		finalizeEffects() {
			return this._updateEffectBandHeights(true);
		}
		updateEffectBandHeights() {
			return this._updateEffectBandHeights(false);
		}
		_updateEffectBandHeights(finalize) {
			if (!this._effectBandSizingInfo) return false;
			let y = 0;
			const paddingTop = 0;
			const paddingBottom = this._renderer.settings.display.effectBandPaddingBottom;
			for (const slot of this._effectBandSizingInfo.slots) {
				slot.shared.y = y;
				for (const band of slot.bands) {
					y += paddingTop;
					band.y = y;
					if (finalize) band.finalizeBand();
					band.height = slot.shared.height;
				}
				y += slot.shared.height + paddingBottom;
			}
			y = Math.ceil(y);
			if (y !== this.height) {
				this.height = y;
				return true;
			}
			return false;
		}
		sizeAndAlignEffectBands(register = true) {
			for (const effectBand of this._bands) {
				effectBand.resetHeight();
				effectBand.alignGlyphs();
				if (register && !effectBand.isEmpty) this._effectBandSizingInfo.register(effectBand);
			}
			if (register) this._effectBandSizingInfo.sortSlots(this._effectInfosSortOrder);
		}
		paint(cx, cy, canvas) {
			const resources = this._renderer.resources;
			for (const effectBand of this._bands) {
				canvas.color = effectBand.voice.index === 0 ? resources.mainGlyphColor : resources.secondaryGlyphColor;
				if (!effectBand.isEmpty) effectBand.paint(cx, cy, canvas);
			}
		}
		getBand(voice, effectId) {
			const id = `${voice.index}.${effectId}`;
			if (this._bandLookup.has(id)) return this._bandLookup.get(id);
			return null;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/LeftToRightLayoutingGlyphGroup.ts
	/**
	* @internal
	*/
	var LeftToRightLayoutingGlyphGroup = class extends GlyphGroup {
		gap = 0;
		constructor() {
			super(0, 0);
			this.glyphs = [];
		}
		doLayout() {}
		addGlyph(g) {
			g.x = this.width;
			g.renderer = this.renderer;
			g.doLayout();
			this.width = g.x + g.width + this.gap;
			super.addGlyph(g);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/MultiVoiceContainerGlyph.ts
	/**
	* This glyph acts as container for handling
	* multiple voice rendering
	* @internal
	*/
	var MultiVoiceContainerGlyph = class extends Glyph {
		static KeySizeBeat = "Beat";
		voiceDrawOrder;
		_beatGlyphLookup = /* @__PURE__ */ new Map();
		beatGlyphs = /* @__PURE__ */ new Map();
		tupletGroups = /* @__PURE__ */ new Map();
		constructor() {
			super(0, 0);
		}
		getBoundingBoxTop() {
			let y = NaN;
			for (const v of this.beatGlyphs.values()) for (const b of v) y = ModelUtils.minBoundingBox(y, b.getBoundingBoxTop());
			return y;
		}
		getBoundingBoxBottom() {
			let y = NaN;
			for (const v of this.beatGlyphs.values()) for (const b of v) y = ModelUtils.maxBoundingBox(y, b.getBoundingBoxBottom());
			return y;
		}
		scaleToWidth(width) {
			const force = this.renderer.layoutingInfo.spaceToForce(width);
			this._scaleToForce(force);
		}
		_scaleToForce(force) {
			this.width = this.renderer.layoutingInfo.calculateVoiceWidth(force);
			const positions = this.renderer.layoutingInfo.buildOnTimePositions(force);
			for (const beatGlyphs of this.beatGlyphs.values()) for (let i = 0, j = beatGlyphs.length; i < j; i++) {
				const currentBeatGlyph = beatGlyphs[i];
				switch (currentBeatGlyph.graceType) {
					case GraceType.None:
						currentBeatGlyph.x = positions.get(currentBeatGlyph.absoluteDisplayStart) - currentBeatGlyph.onTimeX;
						break;
					default:
						const graceDisplayStart = currentBeatGlyph.graceGroup.beats[0].absoluteDisplayStart;
						const graceGroupId = currentBeatGlyph.graceGroup.id;
						if (currentBeatGlyph.graceGroup.isComplete && positions.has(graceDisplayStart)) {
							currentBeatGlyph.x = positions.get(graceDisplayStart) - currentBeatGlyph.onTimeX;
							const graceSprings = this.renderer.layoutingInfo.allGraceRods.get(graceGroupId);
							const afterGraceBeat = currentBeatGlyph.graceGroup.beats[currentBeatGlyph.graceGroup.beats.length - 1].nextBeat;
							const preBeatStretch = afterGraceBeat ? this.renderer.layoutingInfo.getPreBeatSize(afterGraceBeat) : 0;
							currentBeatGlyph.x -= preBeatStretch;
							currentBeatGlyph.x -= graceSprings[currentBeatGlyph.graceIndex].postSpringWidth;
							currentBeatGlyph.x += graceSprings[currentBeatGlyph.graceIndex].graceBeatWidth;
							const lastGraceSpring = graceSprings[currentBeatGlyph.graceGroup.beats.length - 1];
							currentBeatGlyph.x -= lastGraceSpring.graceBeatWidth;
						} else {
							const graceSpring = this.renderer.layoutingInfo.incompleteGraceRods.get(graceGroupId);
							const relativeOffset = graceSpring[currentBeatGlyph.graceIndex].postSpringWidth - graceSpring[currentBeatGlyph.graceIndex].preSpringWidth;
							if (i > 0) if (currentBeatGlyph.graceIndex === 0) currentBeatGlyph.x = beatGlyphs[i - 1].x + beatGlyphs[i - 1].width;
							else currentBeatGlyph.x = beatGlyphs[i - 1].x + graceSpring[currentBeatGlyph.graceIndex - 1].postSpringWidth - graceSpring[currentBeatGlyph.graceIndex - 1].preSpringWidth - relativeOffset;
							else currentBeatGlyph.x = -relativeOffset;
						}
						break;
				}
				if (i > 0) {
					const beatWidth = currentBeatGlyph.x - beatGlyphs[i - 1].x;
					beatGlyphs[i - 1].scaleToWidth(beatWidth);
				}
				if (i === j - 1) {
					const beatWidth = this.width - beatGlyphs[beatGlyphs.length - 1].x;
					currentBeatGlyph.scaleToWidth(beatWidth);
				}
			}
		}
		registerLayoutingInfo(info) {
			for (const beatGlyphs of this.beatGlyphs.values()) for (const b of beatGlyphs) b.registerLayoutingInfo(info);
		}
		applyLayoutingInfo(info) {
			for (const beatGlyphs of this.beatGlyphs.values()) {
				for (const b of beatGlyphs) b.applyLayoutingInfo(info);
				this._scaleToForce(Math.max(this.renderer.settings.display.stretchForce, info.minStretchForce));
			}
		}
		addGlyph(bg) {
			let beatGlyphs;
			if (this.beatGlyphs.has(bg.voiceIndex)) beatGlyphs = this.beatGlyphs.get(bg.voiceIndex);
			else {
				beatGlyphs = [];
				this.beatGlyphs.set(bg.voiceIndex, beatGlyphs);
			}
			bg.x = beatGlyphs.length === 0 ? 0 : beatGlyphs[beatGlyphs.length - 1].x + beatGlyphs[beatGlyphs.length - 1].width;
			bg.renderer = this.renderer;
			beatGlyphs.push(bg);
			const id = bg.beatId;
			if (id >= 0) this._beatGlyphLookup.set(id, bg);
			const newWidth = bg.x + bg.width;
			if (newWidth > this.width) this.width = newWidth;
			if (bg.isFirstOfTupletGroup) {
				let tupletGroups;
				if (this.tupletGroups.has(bg.voiceIndex)) tupletGroups = this.tupletGroups.get(bg.voiceIndex);
				else {
					tupletGroups = [];
					this.tupletGroups.set(bg.voiceIndex, tupletGroups);
				}
				tupletGroups.push(bg.tupletGroup);
			}
		}
		getBeatX(beat, requestedPosition = BeatXPosition.PreNotes, useSharedSizes = false) {
			const container = this.getBeatContainer(beat);
			if (container) return container.x + container.getBeatX(requestedPosition, useSharedSizes);
			return 0;
		}
		getLowestNoteY(beat, position) {
			const container = this.getBeatContainer(beat);
			if (container) return container.y + container.getLowestNoteY(position);
			return 0;
		}
		getHighestNoteY(beat, position) {
			const container = this.getBeatContainer(beat);
			if (container) return container.y + container.getHighestNoteY(position);
			return 0;
		}
		getNoteX(note, requestedPosition) {
			const container = this.getBeatContainer(note.beat);
			if (container) return container.x + container.getNoteX(note, requestedPosition);
			return 0;
		}
		getNoteY(note, requestedPosition) {
			const beat = this.getBeatContainer(note.beat);
			if (beat) return beat.y + beat.getNoteY(note, requestedPosition);
			return 0;
		}
		getRestY(beat, requestedPosition) {
			const container = this.getBeatContainer(beat);
			if (container) return container.y + container.getRestY(requestedPosition);
			return 0;
		}
		getBeatContainer(beat) {
			if (!this._beatGlyphLookup.has(beat.id)) return;
			return this._beatGlyphLookup.get(beat.id);
		}
		buildBoundingsLookup(barBounds, cx, cy) {
			for (const [index, c] of this.beatGlyphs) {
				const voice = this.renderer.bar.voices[index];
				if (index === 0 || !voice.isEmpty) for (const bc of c) bc.buildBoundingsLookup(barBounds, cx + this.x, cy + this.y);
			}
		}
		doLayout() {
			for (const v of this.beatGlyphs.values()) {
				let x = 0;
				for (const b of v) {
					b.x = x;
					b.doLayout();
					x += b.width;
				}
				if (x > this.width) this.width = x;
			}
			if (this.renderer.bar.isMultiVoice) this._doMultiVoiceLayout();
			this.voiceDrawOrder = Array.from(this.beatGlyphs.keys());
			Environment.sortDescending(this.voiceDrawOrder);
		}
		_doMultiVoiceLayout() {
			for (const v of this.beatGlyphs.values()) {
				let x = 0;
				for (const b of v) {
					b.x = x;
					b.doMultiVoiceLayout();
					x += b.width;
				}
				if (x > this.width) this.width = x;
			}
		}
		paint(cx, cy, canvas) {
			for (const v of this.voiceDrawOrder) {
				const beatGlyphs = this.beatGlyphs.get(v);
				const voice = this.renderer.bar.voices[v];
				const _ = ElementStyleHelper.voice(canvas, VoiceSubElement.Glyphs, voice, true);
				try {
					for (let i = 0, j = beatGlyphs.length; i < j; i++) beatGlyphs[i].paint(cx + this.x, cy + this.y, canvas);
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TieGlyph.ts
	/**
	* @internal
	*/
	var TieGlyph = class TieGlyph extends Glyph {
		tieDirection = BeamDirection.Up;
		slurEffectId;
		isForEnd;
		constructor(slurEffectId, forEnd) {
			super(0, 0);
			this.slurEffectId = slurEffectId;
			this.isForEnd = forEnd;
		}
		_startX = 0;
		_startY = 0;
		_endX = 0;
		_endY = 0;
		_tieHeight = 0;
		_boundingBox;
		_shouldPaint = false;
		_resolvedLabels = [];
		_resolvedLabelCount = 0;
		_labelBaselineOffset = 0;
		get checkForOverflow() {
			return this._shouldPaint && this._boundingBox !== void 0;
		}
		getBoundingBoxTop() {
			if (this._boundingBox) return this._boundingBox.y;
			return this._startY;
		}
		getBoundingBoxBottom() {
			if (this._boundingBox) return this._boundingBox.y + this._boundingBox.h;
			return this._startY;
		}
		doLayout() {
			this.width = 0;
			const startNoteRenderer = this.lookupStartBeatRenderer();
			const endNoteRenderer = this.lookupEndBeatRenderer();
			this._startX = 0;
			this._endX = 0;
			this._startY = 0;
			this._endY = 0;
			this.height = 0;
			this.tieDirection = this.calculateTieDirection();
			const forEnd = this.isForEnd;
			this._shouldPaint = false;
			if (!forEnd) {
				if (startNoteRenderer !== endNoteRenderer) {
					this._startX = this.calculateStartX();
					this._startY = this.calculateStartY();
					if (!endNoteRenderer || startNoteRenderer.staff !== endNoteRenderer.staff) {
						const lastRendererInStaff = startNoteRenderer.staff.barRenderers[startNoteRenderer.staff.barRenderers.length - 1];
						this._endX = lastRendererInStaff.x + lastRendererInStaff.width;
						this._endY = this._startY;
						startNoteRenderer.scoreRenderer.layout.slurRegistry.startMultiSystemSlur(this);
					} else {
						this._endX = this.calculateEndX();
						this._endY = this.caclculateEndY();
					}
				} else {
					this._shouldPaint = true;
					this._startX = this.calculateStartX();
					this._endX = this.calculateEndX();
					this._startY = this.calculateStartY();
					this._endY = this.caclculateEndY();
				}
				this._shouldPaint = true;
			} else if (startNoteRenderer.staff !== endNoteRenderer.staff) {
				const firstRendererInStaff = startNoteRenderer.staff.barRenderers[0];
				this._startX = firstRendererInStaff.x;
				this._endX = this.calculateEndX();
				const startGlyph = startNoteRenderer.scoreRenderer.layout.slurRegistry.completeMultiSystemSlur(this);
				if (startGlyph) this._startY = startGlyph.calculateMultiSystemSlurY(endNoteRenderer);
				else this._startY = this.caclculateEndY();
				this._endY = this.caclculateEndY();
				this._shouldPaint = startNoteRenderer.staff !== endNoteRenderer.staff;
			}
			this._boundingBox = void 0;
			this.y = Math.min(this._startY, this._endY);
			const down = this.tieDirection === BeamDirection.Down;
			let tieBoundingBox;
			let cps = [];
			if (this.shouldDrawBendSlur()) {
				this._tieHeight = 0;
				tieBoundingBox = TieGlyph.calculateBendSlurHeight(this._startX, this._startY, this._endX, this._endY, down, this.renderer.smuflMetrics.tieHeight);
			} else {
				this._tieHeight = this.getTieHeight(this._startX, this._startY, this._endX, this._endY);
				const tieThickness = this.renderer.smuflMetrics.tieMidpointThickness;
				cps = TieGlyph._computeBezierControlPoints(1, this._startX, this._startY, this._endX, this._endY, down, this._tieHeight, tieThickness);
				tieBoundingBox = TieGlyph._calculateActualTieHeightFromCps(cps, this._startX, this._startY, this._endX, this._endY, down, tieThickness);
			}
			this._boundingBox = tieBoundingBox;
			this._resolvedLabelCount = 0;
			const labels = this.getSlurLabels();
			if (labels !== null && labels.length > 0 && this.shouldPaintLabels()) {
				const res = this.renderer.settings.display.resources;
				const padding = this.renderer.smuflMetrics.oneStaffSpace * .25;
				let maxTextHeight = 0;
				const labelLineY = cps.length > 0 ? .125 * cps[7] + .375 * cps[9] + .375 * cps[11] + .125 * cps[13] : (this._startY + this._endY) / 2;
				for (const label of labels) {
					const fromX = this.resolveLabelAnchorX(label.fromNote);
					const toX = this.resolveLabelAnchorX(label.toNote);
					if (fromX === null || toX === null) continue;
					const midX = (fromX + toX) / 2;
					if (midX < this._startX || midX > this._endX) continue;
					const font = res.getFontForNotationElement(label.element);
					if (font.size > maxTextHeight) maxTextHeight = font.size;
					let slot;
					if (this._resolvedLabelCount < this._resolvedLabels.length) {
						slot = this._resolvedLabels[this._resolvedLabelCount];
						slot.x = midX;
						slot.y = labelLineY;
						slot.text = label.text;
						slot.element = label.element;
					} else {
						slot = {
							x: midX,
							y: labelLineY,
							text: label.text,
							element: label.element
						};
						this._resolvedLabels.push(slot);
					}
					this._resolvedLabelCount++;
				}
				if (this._resolvedLabelCount > 0) {
					if (this.tieDirection === BeamDirection.Up) {
						tieBoundingBox.y -= maxTextHeight + padding;
						this._labelBaselineOffset = -(maxTextHeight + padding);
					} else this._labelBaselineOffset = padding;
					tieBoundingBox.h += maxTextHeight + padding;
				}
			}
			this.height = tieBoundingBox.h;
			if (this.tieDirection === BeamDirection.Up) {
				const overlap = this.y - tieBoundingBox.y;
				if (overlap > 0) this.y -= overlap;
			}
		}
		paint(cx, cy, canvas) {
			if (!this._shouldPaint) return;
			const isDown = this.tieDirection === BeamDirection.Down;
			if (this.shouldDrawBendSlur()) TieGlyph.drawBendSlur(canvas, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, isDown, this.renderer.smuflMetrics.tieHeight);
			else TieGlyph.paintTie(canvas, 1, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, isDown, this._tieHeight, this.renderer.smuflMetrics.tieMidpointThickness);
			if (this._resolvedLabelCount > 0) {
				const ta = canvas.textAlign;
				const tb = canvas.textBaseline;
				canvas.textAlign = TextAlign.Center;
				canvas.textBaseline = TextBaseline.Top;
				const res = this.renderer.resources;
				let lastElement = -1;
				for (let i = 0; i < this._resolvedLabelCount; i++) {
					const label = this._resolvedLabels[i];
					if (label.element !== lastElement) {
						canvas.font = res.getFontForNotationElement(label.element);
						lastElement = label.element;
					}
					canvas.fillText(label.text, cx + label.x, cy + label.y + this._labelBaselineOffset);
				}
				canvas.textAlign = ta;
				canvas.textBaseline = tb;
			}
		}
		/**
		* Returns the labels to paint along this slur, or `null` when there
		* are none. Override in subclasses.
		*/
		getSlurLabels() {
			return null;
		}
		/**
		* Whether label painting is enabled. Defaults to `true`. Subclasses
		* may override to disable labels on the bend-slur path or other
		* special cases.
		*/
		shouldPaintLabels() {
			return !this.shouldDrawBendSlur();
		}
		/**
		* Looks up the absolute X coordinate of an anchor note. Reuses
		* the start/end bar renderers already resolved by the subclass
		* (NoteTieGlyph) when the note's bar matches — most labels live
		* in the slur's start or end bar, so this avoids the double Map
		* lookup in `getRendererForBar` per label per layout. Returns
		* `null` when the note's bar is not rendered on this glyph's
		* staff (cross-system case).
		*/
		resolveLabelAnchorX(note) {
			const bar = note.beat.voice.bar;
			let renderer = null;
			const start = this.lookupStartBeatRenderer();
			if (start !== null && start.bar === bar) renderer = start;
			else {
				const end = this.lookupEndBeatRenderer();
				if (end !== null && end.bar === bar) renderer = end;
				else renderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, bar);
			}
			if (renderer === null) return null;
			return renderer.x + renderer.getNoteX(note, NoteXPosition.Center);
		}
		getTieHeight(_startX, _startY, _endX, _endY) {
			return this.renderer.smuflMetrics.tieHeight;
		}
		calculateMultiSystemSlurY(renderer) {
			const startRenderer = this.lookupStartBeatRenderer();
			const relY = this.calculateStartY() - startRenderer.y;
			return renderer.y + relY;
		}
		shouldCreateMultiSystemSlur(renderer) {
			const endStaff = this.lookupEndBeatRenderer()?.staff;
			if (!endStaff) return true;
			return renderer.staff.system.index < endStaff.system.index;
		}
		static calculateActualTieHeight(scale, x1, y1, x2, y2, down, offset, size) {
			const cp = TieGlyph._computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
			return TieGlyph._calculateActualTieHeightFromCps(cp, x1, y1, x2, y2, down, size);
		}
		/**
		* Derives the bounding box for a tie from already-computed control
		* points. Splits the bbox math from cps generation so callers that
		* need BOTH cps and bbox (e.g. multi-label slur layout) avoid a
		* second call to `_computeBezierControlPoints`.
		*/
		static _calculateActualTieHeightFromCps(cp, x1, y1, x2, y2, down, size) {
			if (cp.length === 0) return new Bounds(x1, y1, x2 - x1, y2 - y1);
			const p0x = cp[0];
			const p0y = cp[1];
			const c1x = cp[2];
			const c1y = cp[3];
			const c2x = cp[4];
			const c2y = cp[5];
			const p1x = cp[6];
			const p1y = cp[7];
			const midX = .125 * p0x + .375 * c1x + .375 * c2x + .125 * p1x;
			const midY = .125 * p0y + .375 * c1y + .375 * c2y + .125 * p1y;
			const xMin = Math.min(p0x, p1x, midX);
			const xMax = Math.max(p0x, p1x, midX);
			let yMin = Math.min(p0y, p1y, midY);
			let yMax = Math.max(p0y, p1y, midY);
			if (down) yMax += size;
			else yMin -= size;
			const b = new Bounds();
			b.x = xMin;
			b.y = yMin;
			b.w = xMax - xMin;
			b.h = yMax - yMin;
			return b;
		}
		static _computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size) {
			if (x1 === x2 && y1 === y2) return [];
			if (x2 < x1) {
				let t = x1;
				x1 = x2;
				x2 = t;
				t = y1;
				y1 = y2;
				y2 = t;
			}
			offset *= scale;
			size *= scale;
			if (down) {
				offset *= -1;
				size *= -1;
			}
			if (scale >= 1) size *= 1.2;
			const dY = y2 - y1;
			const dX = x2 - x1;
			const length = Math.sqrt(dX * dX + dY * dY);
			let cp1x = x1 + length * .25;
			let cp1y = y1 - offset;
			let cp2x = x1 + length * .75;
			let cp2y = y1 - offset;
			let cp3x = x1 + length * .75;
			let cp3y = y1 - offset - size;
			let cp4x = x1 + length * .25;
			let cp4y = y1 - offset - size;
			const angle = Math.atan2(dY, dX);
			[cp1x, cp1y] = TieGlyph._rotate(cp1x, cp1y, x1, y1, angle);
			[cp2x, cp2y] = TieGlyph._rotate(cp2x, cp2y, x1, y1, angle);
			[cp3x, cp3y] = TieGlyph._rotate(cp3x, cp3y, x1, y1, angle);
			[cp4x, cp4y] = TieGlyph._rotate(cp4x, cp4y, x1, y1, angle);
			return [
				x1,
				y1,
				cp1x,
				cp1y,
				cp2x,
				cp2y,
				x2,
				y2,
				cp3x,
				cp3y,
				cp4x,
				cp4y,
				x1,
				y1
			];
		}
		static _rotate(x, y, rotateX, rotateY, angle) {
			const dx = x - rotateX;
			const dy = y - rotateY;
			const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
			const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
			return [rotateX + rx, rotateY + ry];
		}
		static paintTie(canvas, scale, x1, y1, x2, y2, down, offset, size) {
			const cps = TieGlyph._computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
			canvas.beginPath();
			canvas.moveTo(cps[0], cps[1]);
			canvas.bezierCurveTo(cps[2], cps[3], cps[4], cps[5], cps[6], cps[7]);
			canvas.bezierCurveTo(cps[8], cps[9], cps[10], cps[11], cps[12], cps[13]);
			canvas.closePath();
			canvas.fill();
		}
		static calculateBendSlurTopY(x1, y1, x2, y2, down, scale, bendSlurHeight) {
			let normalVectorX = y2 - y1;
			let normalVectorY = x2 - x1;
			const length = Math.sqrt(normalVectorX * normalVectorX + normalVectorY * normalVectorY);
			if (down) normalVectorX *= -1;
			else normalVectorY *= -1;
			normalVectorX /= length;
			normalVectorY /= length;
			let offset = bendSlurHeight * scale;
			if (x2 - x1 < 20) offset /= 2;
			return (y2 + y1) / 2 + offset * normalVectorY;
		}
		static calculateBendSlurHeight(x1, y1, x2, y2, down, bendSlurHeight) {
			let normalVectorX = y2 - y1;
			let normalVectorY = x2 - x1;
			const length = Math.sqrt(normalVectorX * normalVectorX + normalVectorY * normalVectorY);
			if (down) normalVectorX *= -1;
			else normalVectorY *= -1;
			normalVectorX /= length;
			normalVectorY /= length;
			const centerY = (y2 + y1) / 2;
			let offset = bendSlurHeight;
			if (x2 - x1 < 20) offset /= 2;
			const cp1Y = centerY + offset * normalVectorY;
			const minY = Math.min(y1, y2, cp1Y);
			const maxY = Math.max(y1, y2, cp1Y);
			return new Bounds(x1, Math.min(y1, y2, cp1Y), x2 - x1, maxY - minY);
		}
		static drawBendSlur(canvas, x1, y1, x2, y2, down, bendSlurHeight, slurText) {
			let normalVectorX = y2 - y1;
			let normalVectorY = x2 - x1;
			const length = Math.sqrt(normalVectorX * normalVectorX + normalVectorY * normalVectorY);
			if (down) normalVectorX *= -1;
			else normalVectorY *= -1;
			normalVectorX /= length;
			normalVectorY /= length;
			const centerX = (x2 + x1) / 2;
			const centerY = (y2 + y1) / 2;
			let offset = bendSlurHeight;
			if (x2 - x1 < 20) offset /= 2;
			const cp1X = centerX + offset * normalVectorX;
			const cp1Y = centerY + offset * normalVectorY;
			canvas.beginPath();
			canvas.moveTo(x1, y1);
			canvas.lineTo(cp1X, cp1Y);
			canvas.lineTo(x2, y2);
			canvas.stroke();
			if (slurText) {
				const w = canvas.measureText(slurText).width;
				const textOffset = down ? 0 : -canvas.font.size;
				canvas.fillText(slurText, cp1X - w / 2, cp1Y + textOffset);
			}
		}
	};
	/**
	* A common tie implementation using note details for positioning
	* @internal
	*/
	var NoteTieGlyph = class extends TieGlyph {
		startNote;
		endNote;
		startNoteRenderer = null;
		endNoteRenderer = null;
		constructor(slurEffectId, startNote, endNote, forEnd) {
			super(slurEffectId, forEnd);
			this.startNote = startNote;
			this.endNote = endNote;
		}
		get isLeftHandTap() {
			return this.startNote === this.endNote;
		}
		getTieHeight(startX, startY, endX, endY) {
			if (this.isLeftHandTap) return this.renderer.smuflMetrics.tieHeight;
			return super.getTieHeight(startX, startY, endX, endY);
		}
		calculateTieDirection() {
			switch (this.lookupStartBeatRenderer().getBeatDirection(this.startNote.beat)) {
				case BeamDirection.Up: return BeamDirection.Down;
				default: return BeamDirection.Up;
			}
		}
		calculateStartX() {
			const startNoteRenderer = this.lookupStartBeatRenderer();
			if (this.isLeftHandTap) return this.calculateEndX() - startNoteRenderer.smuflMetrics.leftHandTabTieWidth;
			return startNoteRenderer.x + startNoteRenderer.getNoteX(this.startNote, this.getStartNotePosition());
		}
		getStartNotePosition() {
			return NoteXPosition.Center;
		}
		calculateStartY() {
			const startNoteRenderer = this.lookupStartBeatRenderer();
			if (this.isLeftHandTap) return startNoteRenderer.y + startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Center);
			switch (this.tieDirection) {
				case BeamDirection.Up: return startNoteRenderer.y + startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Top);
				default: return startNoteRenderer.y + startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Bottom);
			}
		}
		calculateEndX() {
			const endNoteRenderer = this.lookupEndBeatRenderer();
			if (!endNoteRenderer) return this.calculateStartY() + this.renderer.smuflMetrics.leftHandTabTieWidth;
			if (this.isLeftHandTap) return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Left);
			return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Center);
		}
		getEndNotePosition() {
			return NoteXPosition.Center;
		}
		caclculateEndY() {
			const endNoteRenderer = this.lookupEndBeatRenderer();
			if (!endNoteRenderer) return this.calculateStartY();
			if (this.isLeftHandTap) return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Center);
			switch (this.tieDirection) {
				case BeamDirection.Up: return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Top);
				default: return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Bottom);
			}
		}
		lookupEndBeatRenderer() {
			if (!this.endNoteRenderer) this.endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.endNote.beat.voice.bar);
			return this.endNoteRenderer;
		}
		lookupStartBeatRenderer() {
			if (!this.startNoteRenderer) this.startNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.startNote.beat.voice.bar);
			return this.startNoteRenderer;
		}
		shouldDrawBendSlur() {
			return false;
		}
	};
	/**
	* A tie glyph for continued multi-system ties/slurs
	* @internal
	*/
	var ContinuationTieGlyph = class extends TieGlyph {
		_startTie;
		constructor(startTie) {
			super(startTie.slurEffectId, false);
			this._startTie = startTie;
		}
		lookupStartBeatRenderer() {
			return this.renderer;
		}
		lookupEndBeatRenderer() {
			return this.renderer;
		}
		shouldDrawBendSlur() {
			return false;
		}
		calculateTieDirection() {
			return this._startTie.tieDirection;
		}
		calculateStartY() {
			return this._startTie.calculateMultiSystemSlurY(this.renderer);
		}
		caclculateEndY() {
			return this.calculateStartY();
		}
		calculateStartX() {
			return this.renderer.staff.barRenderers[0].x;
		}
		calculateEndX() {
			const last = this.renderer.staff.barRenderers[this.renderer.staff.barRenderers.length - 1];
			return last.x + last.width;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NumberGlyph.ts
	/**
	* @internal
	*/
	var NumberGlyph = class NumberGlyph extends Glyph {
		_scale = 0;
		_baseline;
		_symbols = [];
		constructor(x, y, num, baseline, scale = 1) {
			super(x, y);
			this._symbols = NumberGlyph.getSymbols(num);
			this._scale = scale;
			this._baseline = baseline;
		}
		static getSymbols(number) {
			const symbols = [];
			while (number > 0) {
				const digit = number % 10;
				symbols.unshift(NumberGlyph.getSymbol(digit));
				number = number / 10 | 0;
			}
			return symbols;
		}
		static getSymbol(digit) {
			switch (digit) {
				case 0: return MusicFontSymbol.TimeSig0;
				case 1: return MusicFontSymbol.TimeSig1;
				case 2: return MusicFontSymbol.TimeSig2;
				case 3: return MusicFontSymbol.TimeSig3;
				case 4: return MusicFontSymbol.TimeSig4;
				case 5: return MusicFontSymbol.TimeSig5;
				case 6: return MusicFontSymbol.TimeSig6;
				case 7: return MusicFontSymbol.TimeSig7;
				case 8: return MusicFontSymbol.TimeSig8;
				case 9: return MusicFontSymbol.TimeSig9;
				default: return MusicFontSymbol.None;
			}
		}
		doLayout() {
			let w = 0;
			for (const d of this._symbols) w += this.renderer.smuflMetrics.glyphWidths.get(d);
			this.width = w;
		}
		paint(cx, cy, canvas) {
			switch (this._baseline) {
				case TextBaseline.Top:
					cy += this.renderer.smuflMetrics.glyphBottom.get(this._symbols[0]);
					break;
				case TextBaseline.Bottom:
					cy += this.renderer.smuflMetrics.glyphTop.get(this._symbols[0]);
					break;
			}
			canvas.fillMusicFontSymbols(cx + this.x, cy + this.y, this._scale, this._symbols);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/MultiBarRestGlyph.ts
	/**
	* @internal
	*/
	var MultiBarRestGlyph = class MultiBarRestGlyph extends Glyph {
		static _restSymbols = [
			MusicFontSymbol.RestHBarLeft,
			MusicFontSymbol.RestHBarMiddle,
			MusicFontSymbol.RestHBarMiddle,
			MusicFontSymbol.RestHBarMiddle,
			MusicFontSymbol.RestHBarRight
		];
		_numberGlyph = [];
		_numberTop = 0;
		constructor() {
			super(0, 0);
		}
		doLayout() {
			const smufl = this.renderer.smuflMetrics;
			this.width = MultiBarRestGlyph._restSymbols.reduce((p, c) => p + smufl.glyphWidths.get(c), 0);
			const i = this.renderer.additionalMultiRestBars.length + 1;
			this._numberGlyph = NumberGlyph.getSymbols(i);
			this._numberTop = this.renderer.getLineY(-1.5);
			const numberGlyphTop = smufl.glyphTop.get(this._numberGlyph[0]);
			this.renderer.registerOverflowTop(Math.abs(this._numberTop) + numberGlyphTop);
		}
		paint(cx, cy, canvas) {
			canvas.fillMusicFontSymbols(cx + this.x, cy + this.y + this.renderer.height / 2, 1, MultiBarRestGlyph._restSymbols);
			const numberTop = this.renderer.getLineY(-1.5);
			canvas.fillMusicFontSymbols(cx + this.x + this.width / 2, cy + this.y + numberTop | 0, 1, this._numberGlyph, true);
		}
	};
	//#endregion
	//#region src/rendering/MultiBarRestBeatContainerGlyph.ts
	/**
	* @internal
	*/
	var MultiBarRestBeatContainerGlyph = class extends BeatContainerGlyphBase {
		_glyph;
		constructor() {
			super(0, 0);
		}
		get absoluteDisplayStart() {
			return this.renderer.bar.masterBar.start;
		}
		get beatId() {
			return -1;
		}
		get onTimeX() {
			return 0;
		}
		get graceType() {
			return GraceType.None;
		}
		get graceIndex() {
			return 0;
		}
		get graceGroup() {
			return null;
		}
		get voiceIndex() {
			return 0;
		}
		get isFirstOfTupletGroup() {
			return false;
		}
		get tupletGroup() {
			return null;
		}
		get isLastOfVoice() {
			return true;
		}
		get displayDuration() {
			return 0;
		}
		getRestY(requestedPosition) {
			const g = this._glyph;
			if (g) switch (requestedPosition) {
				case NoteYPosition.Top: return g.y;
				case NoteYPosition.TopWithStem: return g.y - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
				case NoteYPosition.Center:
				case NoteYPosition.StemUp:
				case NoteYPosition.StemDown: return g.y + g.height / 2;
				case NoteYPosition.Bottom: return g.y + g.height;
				case NoteYPosition.BottomWithStem: return g.y + g.height + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
			}
			return 0;
		}
		getNoteY(_note, requestedPosition) {
			return this.getRestY(requestedPosition);
		}
		getHighestNoteY(position) {
			return this.getRestY(position);
		}
		getLowestNoteY(position) {
			return this.getRestY(position);
		}
		getNoteX(_note, requestedPosition) {
			const g = this._glyph;
			if (g) switch (requestedPosition) {
				case NoteXPosition.Left: return g.x;
				case NoteXPosition.Center: return g.x + g.width / 2;
				case NoteXPosition.Right: return g.x + g.width;
			}
			return 0;
		}
		getBeatX(requestedPosition, _useSharedSizes) {
			const g = this._glyph;
			if (g) switch (requestedPosition) {
				case BeatXPosition.PreNotes: return g.x;
				case BeatXPosition.OnNotes:
				case BeatXPosition.MiddleNotes:
				case BeatXPosition.Stem:
				case BeatXPosition.PostNotes: return g.x + g.width;
				case BeatXPosition.EndBeat: return this.width;
			}
			return 0;
		}
		registerLayoutingInfo(layoutings) {
			const width = this._glyph?.width ?? 0;
			layoutings.addBeatSpring(this, 0, width);
		}
		applyLayoutingInfo(_info) {}
		buildBoundingsLookup(_barBounds, _cx, _cy) {}
		doLayout() {
			if (this.renderer.showMultiBarRest) {
				this._glyph = new MultiBarRestGlyph();
				this._glyph.renderer = this.renderer;
				this._glyph.doLayout();
				this.width = this._glyph.width;
			}
		}
		doMultiVoiceLayout() {}
		getBoundingBoxTop() {
			return this._glyph?.getBoundingBoxTop() ?? NaN;
		}
		getBoundingBoxBottom() {
			return this._glyph?.getBoundingBoxBottom() ?? NaN;
		}
		paint(cx, cy, canvas) {
			this._glyph?.paint(cx + this.x, cy + this.y, canvas);
		}
	};
	//#endregion
	//#region src/rendering/utils/BeamingHelper.ts
	/**
	* @internal
	*/
	var BeamingHelperDrawInfo = class {
		startBeat = null;
		startX = 0;
		startY = 0;
		endBeat = null;
		endX = 0;
		endY = 0;
		/**
		* calculates the Y-position given a X-pos using the current start end point
		* @param x
		*/
		calcY(x) {
			if (this.startX === this.endX) return this.startY;
			return (this.endY - this.startY) / (this.endX - this.startX) * (x - this.startX) + this.startY;
		}
	};
	/**
	* This public class helps drawing beams and bars for notes.
	* @internal
	*/
	var BeamingHelper = class BeamingHelper {
		_staff;
		_renderer;
		_beamingRuleLookup;
		voice = null;
		beats = [];
		shortestDuration = Duration.QuadrupleWhole;
		/**
		* an indicator whether any beat has a tuplet on it.
		*/
		hasTuplet = false;
		slashBeats = [];
		restBeats = [];
		lowestNoteInHelper = null;
		_lowestNoteCompareValueInHelper = -1;
		highestNoteInHelper = null;
		_highestNoteCompareValueInHelper = -1;
		invertBeamDirection = false;
		preferredBeamDirection = null;
		graceType = GraceType.None;
		get isRestBeamHelper() {
			return this.beats.length === 1 && this.beats[0].isRest;
		}
		hasStem(forceFlagOnSingleBeat, beat) {
			return forceFlagOnSingleBeat && BeamingHelper.beatHasStem(beat) || !forceFlagOnSingleBeat && BeamingHelper.beatHasStem(beat);
		}
		static beatHasStem(beat) {
			return beat.duration > Duration.Whole;
		}
		hasFlag(forceFlagOnSingleBeat, beat) {
			return forceFlagOnSingleBeat && BeamingHelper.beatHasFlag(beat) || !forceFlagOnSingleBeat && this.beats.length === 1 && BeamingHelper.beatHasFlag(this.beats[0]);
		}
		static beatHasFlag(beat) {
			return !beat.deadSlapped && !beat.isRest && (beat.duration > Duration.Quarter || beat.graceType !== GraceType.None);
		}
		constructor(staff, renderer, beamingRuleLookup) {
			this._staff = staff;
			this._renderer = renderer;
			this.beats = [];
			this._beamingRuleLookup = beamingRuleLookup;
		}
		alignWithBeats() {
			this.drawingInfos.clear();
		}
		finish() {
			this._renderer.completeBeamingHelper(this);
		}
		static computeLineHeightsForRest(duration) {
			switch (duration) {
				case Duration.QuadrupleWhole: return [2, 2];
				case Duration.DoubleWhole: return [2, 2];
				case Duration.Whole: return [0, 1];
				case Duration.Half: return [1, 0];
				case Duration.Quarter: return [3, 3];
				case Duration.Eighth: return [2, 2];
				case Duration.Sixteenth: return [2, 4];
				case Duration.ThirtySecond: return [4, 4];
				case Duration.SixtyFourth: return [4, 6];
				case Duration.OneHundredTwentyEighth: return [6, 6];
				case Duration.TwoHundredFiftySixth: return [6, 8];
			}
			return [0, 0];
		}
		checkBeat(beat) {
			if (beat.invertBeamDirection) this.invertBeamDirection = true;
			if (!this.voice) this.voice = beat.voice;
			let add = false;
			if (this.beats.length === 0) add = true;
			else switch (this.beats[this.beats.length - 1].beamingMode) {
				case BeatBeamingMode.Auto:
				case BeatBeamingMode.ForceSplitOnSecondaryToNext:
					add = this._canJoin(this.beats[this.beats.length - 1], beat);
					break;
				case BeatBeamingMode.ForceSplitToNext:
					add = false;
					break;
				case BeatBeamingMode.ForceMergeWithNext:
					add = true;
					break;
			}
			if (add) {
				if (this.preferredBeamDirection == null && beat.preferredBeamDirection !== null) this.preferredBeamDirection = beat.preferredBeamDirection;
				if (beat.hasTuplet) this.hasTuplet = true;
				if (beat.graceType !== GraceType.None) this.graceType = beat.graceType;
				if (!beat.isRest) {
					if (this.isRestBeamHelper) this.beats = [];
					this.beats.push(beat);
					this._checkNote(beat.minNote);
					this._checkNote(beat.maxNote);
					if (this.shortestDuration < beat.duration) this.shortestDuration = beat.duration;
				} else if (this.beats.length === 0) this.beats.push(beat);
				else this.restBeats.push(beat);
				if (beat.slashed) this.slashBeats.push(beat);
			}
			return add;
		}
		_checkNote(note) {
			if (!note) return;
			let lowestValueForNote;
			let highestValueForNote;
			if (this.voice && note.isPercussion) {
				lowestValueForNote = -AccidentalHelper.getPercussionSteps(note);
				highestValueForNote = lowestValueForNote;
			} else {
				lowestValueForNote = AccidentalHelper.getNoteValue(note);
				highestValueForNote = lowestValueForNote;
				if (note.harmonicType !== HarmonicType.None && note.harmonicType !== HarmonicType.Natural) highestValueForNote = note.realValue - this._staff.displayTranspositionPitch;
			}
			if (!this.lowestNoteInHelper || lowestValueForNote < this._lowestNoteCompareValueInHelper) {
				this.lowestNoteInHelper = note;
				this._lowestNoteCompareValueInHelper = lowestValueForNote;
			}
			if (!this.highestNoteInHelper || highestValueForNote > this._highestNoteCompareValueInHelper) {
				this.highestNoteInHelper = note;
				this._highestNoteCompareValueInHelper = highestValueForNote;
			}
		}
		_canJoin(b1, b2) {
			if (!b1 || !b2 || b1.graceType !== b2.graceType || b1.graceType === GraceType.BendGrace || b2.graceType === GraceType.BendGrace || b1.deadSlapped || b2.deadSlapped) return false;
			if (b1.graceType !== GraceType.None && b2.graceType !== GraceType.None) return true;
			if (b1.voice.bar !== b2.voice.bar) return false;
			const start1 = b1.playbackStart;
			const start2 = b2.playbackStart;
			if (!BeamingHelper._canJoinDuration(b1.duration) || !BeamingHelper._canJoinDuration(b2.duration)) return start1 === start2;
			if (b1.tupletGroup !== b2.tupletGroup) return false;
			if (b1.hasTuplet && b2.hasTuplet) {
				if (b1.tupletGroup === b2.tupletGroup && b1.tupletGroup.isFull) return true;
			}
			return this._beamingRuleLookup.calculateGroupIndex(start1) === this._beamingRuleLookup.calculateGroupIndex(start2);
		}
		static _canJoinDuration(d) {
			switch (d) {
				case Duration.Whole:
				case Duration.Half:
				case Duration.Quarter: return false;
				default: return true;
			}
		}
		static isFullBarJoin(a, b, barIndex) {
			return ModelUtils.getIndex(a.duration) - 2 - barIndex > 0 && ModelUtils.getIndex(b.duration) - 2 - barIndex > 0;
		}
		get beatOfLowestNote() {
			return this.lowestNoteInHelper.beat;
		}
		get beatOfHighestNote() {
			return this.highestNoteInHelper.beat;
		}
		drawingInfos = /* @__PURE__ */ new Map();
	};
	//#endregion
	//#region src/rendering/utils/BarCollisionHelper.ts
	/**
	* @internal
	*/
	var ReservedLayoutAreaSlot = class {
		topY = 0;
		bottomY = 0;
		constructor(topY, bottomY) {
			this.topY = topY;
			this.bottomY = bottomY;
		}
	};
	/**
	* @internal
	*/
	var ReservedLayoutArea = class {
		beat;
		topY = -1e3;
		bottomY = -1e3;
		slots = [];
		constructor(beat) {
			this.beat = beat;
		}
		addSlot(topY, bottomY) {
			this.slots.push(new ReservedLayoutAreaSlot(topY, bottomY));
			if (this.topY === -1e3) {
				this.topY = topY;
				this.bottomY = bottomY;
			} else {
				const min = Math.min(topY, bottomY);
				const max = Math.max(topY, bottomY);
				if (min < this.topY) this.topY = min;
				if (max > this.bottomY) this.bottomY = max;
			}
		}
	};
	/**
	* @internal
	*/
	var BarCollisionHelper = class {
		reservedLayoutAreasByDisplayTime = /* @__PURE__ */ new Map();
		restDurationsByDisplayTime = /* @__PURE__ */ new Map();
		getBeatMinMaxY() {
			let minY = -1e3;
			let maxY = -1e3;
			for (const v of this.reservedLayoutAreasByDisplayTime.values()) if (minY === -1e3) {
				minY = v.topY;
				maxY = v.bottomY;
			} else {
				if (minY > v.topY) minY = v.topY;
				if (maxY < v.bottomY) maxY = v.bottomY;
			}
			if (minY === -1e3) return [0, 0];
			return [minY, maxY];
		}
		reserveBeatSlot(beat, topY, bottomY) {
			if (topY === bottomY) return;
			if (!this.reservedLayoutAreasByDisplayTime.has(beat.displayStart)) this.reservedLayoutAreasByDisplayTime.set(beat.displayStart, new ReservedLayoutArea(beat));
			this.reservedLayoutAreasByDisplayTime.get(beat.displayStart).addSlot(topY, bottomY);
			if (beat.isRest) this.registerRest(beat);
		}
		registerRest(beat) {
			if (!this.restDurationsByDisplayTime.has(beat.displayStart)) this.restDurationsByDisplayTime.set(beat.displayStart, /* @__PURE__ */ new Map());
			if (!this.restDurationsByDisplayTime.get(beat.displayStart).has(beat.playbackDuration)) this.restDurationsByDisplayTime.get(beat.displayStart).set(beat.playbackDuration, beat.id);
		}
		applyRestCollisionOffset(beat, currentY, linesToPixel) {
			if (beat.voice.index > 0) {
				if (this.reservedLayoutAreasByDisplayTime.has(beat.playbackStart)) {
					const restSizes = BeamingHelper.computeLineHeightsForRest(beat.duration).map((i) => i * linesToPixel);
					const oldRestTopY = currentY - restSizes[0];
					const oldRestBottomY = currentY + restSizes[1];
					let newRestTopY = oldRestTopY;
					const reservedSlots = this.reservedLayoutAreasByDisplayTime.get(beat.playbackStart);
					let hasCollision = false;
					for (const slot of reservedSlots.slots) if (oldRestTopY >= slot.topY && oldRestTopY <= slot.bottomY || oldRestBottomY >= slot.topY && oldRestBottomY <= slot.bottomY) {
						hasCollision = true;
						break;
					}
					if (hasCollision) {
						if (beat.voice.index === 1) newRestTopY = reservedSlots.topY - restSizes[1] - restSizes[0];
						else newRestTopY = reservedSlots.bottomY;
						const newRestBottomY = newRestTopY + restSizes[0] + restSizes[1];
						const staveSpace = linesToPixel * 2;
						const distanceInLines = Math.ceil(Math.abs(newRestTopY - oldRestTopY) / staveSpace);
						reservedSlots.addSlot(newRestTopY, newRestBottomY);
						if (newRestTopY < oldRestTopY) return distanceInLines * -staveSpace;
						return distanceInLines * staveSpace;
					}
				}
			}
			return 0;
		}
	};
	//#endregion
	//#region src/rendering/utils/BeamingRuleLookup.ts
	/**
	* @internal
	*/
	var BeamingRuleLookup = class BeamingRuleLookup {
		_division = 0;
		_slots = [];
		_barDuration;
		constructor(barDuration, division, slots) {
			this._division = division;
			this._slots = slots;
			this._barDuration = barDuration;
		}
		calculateGroupIndex(beatStartTime) {
			if (this._slots.length === 0) return beatStartTime;
			beatStartTime = beatStartTime % this._barDuration;
			const slotIndex = Math.floor(beatStartTime / this._division);
			return this._slots[slotIndex];
		}
		static build(masterBar, ruleDuration, ruleGroups) {
			const totalDuration = masterBar.calculateDuration(false);
			const division = MidiUtils.toTicks(ruleDuration);
			const slotCount = totalDuration / division;
			if (slotCount < 0 || ruleGroups.length === 0) return new BeamingRuleLookup(0, 0, []);
			let groupIndex = 0;
			let remainingSlots = ruleGroups[groupIndex];
			const slots = [];
			for (let i = 0; i < slotCount; i++) if (groupIndex < ruleGroups.length) {
				slots.push(groupIndex);
				remainingSlots--;
				if (remainingSlots <= 0) {
					groupIndex++;
					if (groupIndex < ruleGroups.length) remainingSlots = ruleGroups[groupIndex];
				}
			} else {
				slots.push(groupIndex);
				groupIndex++;
			}
			return new BeamingRuleLookup(totalDuration, division, slots);
		}
	};
	//#endregion
	//#region src/rendering/utils/BarHelpers.ts
	/**
	* @internal
	*/
	var BarHelpers = class BarHelpers {
		_renderer;
		_beamHelperLookup = /* @__PURE__ */ new Map();
		beamHelpers = [];
		collisionHelper;
		preferredBeamDirection = null;
		constructor(renderer) {
			this._renderer = renderer;
			this.collisionHelper = new BarCollisionHelper();
		}
		initialize() {
			const barRenderer = this._renderer;
			const bar = this._renderer.bar;
			const masterBar = bar.masterBar;
			const beamingRules = masterBar.actualBeamingRules ?? BarHelpers._findOrBuildDefaultBeamingRules(masterBar);
			const rule = beamingRules.findRule(bar.shortestDuration);
			const key = `beaming_${beamingRules.uniqueId}_${rule[0]}`;
			let beamingRuleLookup = this._renderer.scoreRenderer.layout.beamingRuleLookups.has(key) ? this._renderer.scoreRenderer.layout.beamingRuleLookups.get(key) : void 0;
			if (!beamingRuleLookup) {
				beamingRuleLookup = BeamingRuleLookup.build(masterBar, rule[0], rule[1]);
				this._renderer.scoreRenderer.layout.beamingRuleLookups.set(key, beamingRuleLookup);
			}
			let currentBeamHelper = null;
			let currentGraceBeamHelper = null;
			for (let i = 0, j = bar.voices.length; i < j; i++) {
				const v = bar.voices[i];
				this.beamHelpers.push([]);
				for (let k = 0, l = v.beats.length; k < l; k++) {
					const b = v.beats[k];
					let helperForBeat;
					if (b.graceType !== GraceType.None) helperForBeat = currentGraceBeamHelper;
					else {
						helperForBeat = currentBeamHelper;
						if (currentGraceBeamHelper) currentGraceBeamHelper.finish();
						currentGraceBeamHelper = null;
					}
					if (!helperForBeat || !helperForBeat.checkBeat(b)) {
						if (helperForBeat) helperForBeat.finish();
						helperForBeat = new BeamingHelper(bar.staff, barRenderer, beamingRuleLookup);
						helperForBeat.preferredBeamDirection = this.preferredBeamDirection;
						helperForBeat.checkBeat(b);
						if (b.graceType !== GraceType.None) currentGraceBeamHelper = helperForBeat;
						else currentBeamHelper = helperForBeat;
						this.beamHelpers[v.index].push(helperForBeat);
					}
					this._beamHelperLookup.set(b.id, helperForBeat);
				}
				if (currentBeamHelper) currentBeamHelper.finish();
				if (currentGraceBeamHelper) currentGraceBeamHelper.finish();
				currentBeamHelper = null;
				currentGraceBeamHelper = null;
			}
		}
		static _defaultBeamingRules;
		static _findOrBuildDefaultBeamingRules(masterBar) {
			let defaultBeamingRules = BarHelpers._defaultBeamingRules;
			if (!defaultBeamingRules) {
				defaultBeamingRules = new Map([
					BeamingRules.createSimple(2, 16, Duration.Sixteenth, [1, 1]),
					BeamingRules.createSimple(1, 8, Duration.Eighth, [1]),
					BeamingRules.createSimple(1, 4, Duration.Quarter, [1]),
					BeamingRules.createSimple(3, 16, Duration.Sixteenth, [3]),
					BeamingRules.createSimple(4, 16, Duration.Sixteenth, [2, 2]),
					BeamingRules.createSimple(2, 8, Duration.Eighth, [1, 1]),
					BeamingRules.createSimple(5, 16, Duration.Sixteenth, [3, 2]),
					BeamingRules.createSimple(6, 16, Duration.Sixteenth, [3, 3]),
					BeamingRules.createSimple(3, 8, Duration.Eighth, [3]),
					BeamingRules.createSimple(4, 8, Duration.Eighth, [2, 2]),
					BeamingRules.createSimple(2, 4, Duration.Quarter, [1, 1]),
					BeamingRules.createSimple(9, 16, Duration.Sixteenth, [
						3,
						3,
						3
					]),
					BeamingRules.createSimple(5, 8, Duration.Eighth, [3, 2]),
					BeamingRules.createSimple(12, 16, Duration.Sixteenth, [
						3,
						3,
						3,
						3
					]),
					BeamingRules.createSimple(6, 8, Duration.Eighth, [
						3,
						3,
						3
					]),
					BeamingRules.createSimple(3, 4, Duration.Quarter, [
						1,
						1,
						1
					]),
					BeamingRules.createSimple(7, 8, Duration.Eighth, [4, 3]),
					BeamingRules.createSimple(8, 8, Duration.Eighth, [
						3,
						3,
						2
					]),
					BeamingRules.createSimple(4, 4, Duration.Quarter, [
						1,
						1,
						1,
						1
					]),
					BeamingRules.createSimple(9, 8, Duration.Eighth, [
						3,
						3,
						3
					]),
					BeamingRules.createSimple(10, 8, Duration.Eighth, [
						4,
						3,
						3
					]),
					BeamingRules.createSimple(5, 4, Duration.Quarter, [
						1,
						1,
						1,
						1,
						1
					]),
					BeamingRules.createSimple(12, 8, Duration.Eighth, [
						3,
						3,
						3,
						3
					]),
					BeamingRules.createSimple(6, 4, Duration.Quarter, [
						1,
						1,
						1,
						1,
						1,
						1
					]),
					BeamingRules.createSimple(15, 8, Duration.Eighth, [
						3,
						3,
						3,
						3,
						3,
						3
					]),
					BeamingRules.createSimple(8, 4, Duration.Quarter, [
						1,
						1,
						1,
						1,
						1,
						1,
						1,
						1
					]),
					BeamingRules.createSimple(18, 8, Duration.Eighth, [
						3,
						3,
						3,
						3,
						3,
						3
					])
				].map((r) => [`${r.timeSignatureNumerator}_${r.timeSignatureDenominator}`, r]));
				BarHelpers._defaultBeamingRules = defaultBeamingRules;
			}
			const key = `${masterBar.timeSignatureNumerator}_${masterBar.timeSignatureDenominator}`;
			if (defaultBeamingRules.has(key)) return defaultBeamingRules.get(key);
			let divisionLength = MidiUtils.QuarterTime;
			switch (masterBar.timeSignatureDenominator) {
				case 8:
					if (masterBar.timeSignatureNumerator % 3 === 0) divisionLength += MidiUtils.QuarterTime / 2 | 0;
					break;
			}
			const numberOfDivisions = Math.ceil(masterBar.calculateDuration(false) / divisionLength);
			const notesPerDivision = divisionLength / MidiUtils.QuarterTime * 2;
			const fallback = new BeamingRules();
			const groups = [];
			for (let i = 0; i < numberOfDivisions; i++) groups.push(notesPerDivision);
			fallback.groups.set(Duration.Eighth, groups);
			fallback.timeSignatureNumerator = masterBar.timeSignatureNumerator;
			fallback.timeSignatureDenominator = masterBar.timeSignatureDenominator;
			fallback.finish();
			defaultBeamingRules.set(key, fallback);
			return fallback;
		}
		getBeamingHelperForBeat(beat) {
			return this._beamHelperLookup.has(beat.id) ? this._beamHelperLookup.get(beat.id) : void 0;
		}
	};
	//#endregion
	//#region src/rendering/BarRendererBase.ts
	/**
	* Lists the different position modes for {@link BarRendererBase.getNoteY}
	* @internal
	*/
	var NoteYPosition = /* @__PURE__ */ function(NoteYPosition) {
		/**
		* Gets the note y-position on top of the note stem or tab number.
		*/
		NoteYPosition[NoteYPosition["TopWithStem"] = 0] = "TopWithStem";
		/**
		* Gets the note y-position on top of the note head or tab number.
		*/
		NoteYPosition[NoteYPosition["Top"] = 1] = "Top";
		/**
		* Gets the note y-position on the center of the note head or tab number.
		*/
		NoteYPosition[NoteYPosition["Center"] = 2] = "Center";
		/**
		* Gets the note y-position on the bottom of the note head or tab number.
		*/
		NoteYPosition[NoteYPosition["Bottom"] = 3] = "Bottom";
		/**
		* Gets the note y-position on the bottom of the note stem or tab number.
		*/
		NoteYPosition[NoteYPosition["BottomWithStem"] = 4] = "BottomWithStem";
		/**
		* The position where the upwards stem should be placed.
		*/
		NoteYPosition[NoteYPosition["StemUp"] = 5] = "StemUp";
		/**
		* The position where the downwards stem should be placed.
		*/
		NoteYPosition[NoteYPosition["StemDown"] = 6] = "StemDown";
		return NoteYPosition;
	}({});
	/**
	* Lists the different position modes for {@link BarRendererBase.getNoteX}
	* @internal
	*/
	var NoteXPosition = /* @__PURE__ */ function(NoteXPosition) {
		/**
		* Gets the note x-position on left of the note head or tab number.
		*/
		NoteXPosition[NoteXPosition["Left"] = 0] = "Left";
		/**
		* Gets the note x-position on the center of the note head or tab number.
		*/
		NoteXPosition[NoteXPosition["Center"] = 1] = "Center";
		/**
		* Gets the note x-position on the right of the note head or tab number.
		*/
		NoteXPosition[NoteXPosition["Right"] = 2] = "Right";
		return NoteXPosition;
	}({});
	/**
	* This is the base public class for creating blocks which can render bars.
	* @internal
	*/
	var BarRendererBase = class {
		_preBeatGlyphs = new LeftToRightLayoutingGlyphGroup();
		voiceContainer = new MultiVoiceContainerGlyph();
		_postBeatGlyphs = new LeftToRightLayoutingGlyphGroup();
		_ties = [];
		_multiSystemSlurs;
		topEffects;
		bottomEffects;
		get nextRenderer() {
			if (!this.bar || !this.bar.nextBar) return null;
			return this.scoreRenderer.layout.getRendererForBar(this.staff.staffId, this.bar.nextBar);
		}
		get previousRenderer() {
			if (!this.bar || !this.bar.previousBar) return null;
			return this.scoreRenderer.layout.getRendererForBar(this.staff.staffId, this.bar.previousBar);
		}
		scoreRenderer;
		staff;
		layoutingInfo;
		bar;
		additionalMultiRestBars = null;
		get lastBar() {
			if (this.additionalMultiRestBars) return this.additionalMultiRestBars[this.additionalMultiRestBars.length - 1];
			return this.bar;
		}
		x = 0;
		y = 0;
		width = 0;
		computedWidth = 0;
		height = 0;
		index = 0;
		_contentTopOverflow = 0;
		_contentBottomOverflow = 0;
		beatEffectsMinY = NaN;
		beatEffectsMaxY = NaN;
		get topOverflow() {
			return this._contentTopOverflow + this.topEffects.height;
		}
		get bottomOverflow() {
			return this._contentBottomOverflow + this.bottomEffects.height;
		}
		helpers;
		get collisionHelper() {
			return this.helpers.collisionHelper;
		}
		/**
		* Gets or sets whether this renderer is linked to the next one
		* by some glyphs like a vibrato effect
		*/
		isLinkedToPrevious = false;
		/**
		* Gets or sets whether this renderer can wrap to the next line
		* or it needs to stay connected to the previous one.
		* (e.g. when having double bar repeats we must not separate the 2 bars)
		*/
		canWrap = true;
		get showMultiBarRest() {
			return true;
		}
		constructor(renderer, bar) {
			this.scoreRenderer = renderer;
			this.bar = bar;
			this.helpers = new BarHelpers(this);
			this.topEffects = new EffectBandContainer(this, true);
			this.bottomEffects = new EffectBandContainer(this, false);
		}
		registerTie(tie) {
			this._ties.push(tie);
		}
		get middleYPosition() {
			return 0;
		}
		registerBeatEffectOverflows(beatEffectsMinY, beatEffectsMaxY) {
			const currentBeatEffectsMinY = this.beatEffectsMinY;
			if (Number.isNaN(currentBeatEffectsMinY) || beatEffectsMinY < currentBeatEffectsMinY) this.beatEffectsMinY = beatEffectsMinY;
			const currentBeatEffectsMaxY = this.beatEffectsMaxY;
			if (Number.isNaN(currentBeatEffectsMaxY) || beatEffectsMaxY > currentBeatEffectsMaxY) this.beatEffectsMaxY = beatEffectsMaxY;
		}
		registerOverflowTop(topOverflow) {
			topOverflow = Math.ceil(topOverflow);
			if (topOverflow > this._contentTopOverflow) {
				this._contentTopOverflow = topOverflow;
				return true;
			}
			return false;
		}
		registerOverflowBottom(bottomOverflow) {
			bottomOverflow = Math.ceil(bottomOverflow);
			if (bottomOverflow > this._contentBottomOverflow) {
				this._contentBottomOverflow = bottomOverflow;
				return true;
			}
			return false;
		}
		/**
		* The fixed-overhead width of this renderer: glyphs that do not stretch when
		* the bar is scaled (clef, key signature, time signature, barlines, courtesy
		* accidentals, etc). Treated as a fixed allocation by the system-level layout
		* before distributing remaining width across bars by {@link Bar.displayScale}.
		*/
		get fixedOverhead() {
			return this._preBeatGlyphs.width + this._postBeatGlyphs.width;
		}
		scaleToWidth(width) {
			const containerWidth = width - this._preBeatGlyphs.width - this._postBeatGlyphs.width;
			this.voiceContainer.scaleToWidth(containerWidth);
			for (const v of this.helpers.beamHelpers) for (const h of v) h.alignWithBeats();
			this._postBeatGlyphs.x = this._preBeatGlyphs.x + this._preBeatGlyphs.width + containerWidth;
			this.width = width;
			this.topEffects.alignGlyphs();
			this.bottomEffects.alignGlyphs();
		}
		get resources() {
			return this.settings.display.resources;
		}
		get smuflMetrics() {
			return this.resources.engravingSettings;
		}
		get settings() {
			return this.scoreRenderer.settings;
		}
		wasFirstOfStaff = false;
		get isFirstOfStaff() {
			return this.index === 0;
		}
		get isLastOfStaff() {
			return this.index === this.staff.barRenderers.length - 1;
		}
		get isLast() {
			return !this.bar || this.bar.index === this.scoreRenderer.layout.lastBarIndex;
		}
		_registerLayoutingInfo() {
			const info = this.layoutingInfo;
			const preSize = this._preBeatGlyphs.width;
			if (info.preBeatSize < preSize) info.preBeatSize = preSize;
			this.voiceContainer.registerLayoutingInfo(info);
			const postSize = this._postBeatGlyphs.width;
			if (info.postBeatSize < postSize) info.postBeatSize = postSize;
		}
		_appliedLayoutingInfo = 0;
		afterReverted() {
			this.staff = void 0;
			this.registerMultiSystemSlurs(void 0);
			this.isFinalized = false;
		}
		afterStaffBarReverted() {
			this.topEffects.afterStaffBarReverted();
			this.bottomEffects.afterStaffBarReverted();
			this._registerStaffOverflow();
		}
		applyLayoutingInfo() {
			if (this._appliedLayoutingInfo >= this.layoutingInfo.version) return false;
			this.topEffects.resetEffectBandSizingInfo();
			this.bottomEffects.resetEffectBandSizingInfo();
			this._appliedLayoutingInfo = this.layoutingInfo.version;
			this._preBeatGlyphs.width = this.layoutingInfo.preBeatSize;
			const container = this.voiceContainer;
			container.x = this._preBeatGlyphs.x + this._preBeatGlyphs.width;
			container.applyLayoutingInfo(this.layoutingInfo);
			this._postBeatGlyphs.x = Math.floor(container.x + container.width);
			this._postBeatGlyphs.width = this.layoutingInfo.postBeatSize;
			this.width = Math.ceil(this._postBeatGlyphs.x + this._postBeatGlyphs.width);
			this.computedWidth = this.width;
			this.topEffects.sizeAndAlignEffectBands();
			this.bottomEffects.sizeAndAlignEffectBands();
			this._registerStaffOverflow();
			return true;
		}
		isFinalized = false;
		registerMultiSystemSlurs(startedTies) {
			if (!startedTies) {
				this._multiSystemSlurs = void 0;
				return;
			}
			let ties = void 0;
			for (const g of startedTies) {
				const continuation = new ContinuationTieGlyph(g);
				continuation.renderer = this;
				continuation.tieDirection = g.tieDirection;
				if (!ties) ties = [];
				ties.push(continuation);
			}
			this._multiSystemSlurs = ties;
		}
		_finalizeTies(ties, barTop, barBottom) {
			let didChangeOverflows = false;
			for (const t of ties) {
				const tie = t;
				tie.doLayout();
				if (t.checkForOverflow) {
					const tieTop = tie.getBoundingBoxTop();
					const bottomOverflow = tie.getBoundingBoxBottom() - barBottom;
					if (bottomOverflow > 0) {
						if (this.registerOverflowBottom(bottomOverflow)) didChangeOverflows = true;
					}
					const topOverflow = tieTop - barTop;
					if (topOverflow < 0) {
						if (this.registerOverflowTop(topOverflow * -1)) didChangeOverflows = true;
					}
				}
			}
			return didChangeOverflows;
		}
		finalizeRenderer() {
			this.isFinalized = true;
			let didChangeOverflows = false;
			const barTop = this.y;
			const barBottom = this.y + this.height;
			if (this._finalizeTies(this._ties, barTop, barBottom)) didChangeOverflows = true;
			const multiSystemSlurs = this._multiSystemSlurs;
			if (multiSystemSlurs && this._finalizeTies(multiSystemSlurs, barTop, barBottom)) didChangeOverflows = true;
			const topHeightChanged = this.topEffects.finalizeEffects();
			const bottomHeightChanged = this.bottomEffects.finalizeEffects();
			if (topHeightChanged || bottomHeightChanged) didChangeOverflows = true;
			if (didChangeOverflows) {
				this.updateSizes();
				this._registerStaffOverflow();
			}
			return didChangeOverflows;
		}
		_registerStaffOverflow() {
			this.staff.registerOverflowTop(this.topOverflow);
			this.staff.registerOverflowBottom(this.bottomOverflow);
		}
		doLayout() {
			if (!this.bar) return;
			this.helpers.initialize();
			this._ties = [];
			this._preBeatGlyphs.renderer = this;
			this.voiceContainer.renderer = this;
			this._postBeatGlyphs.renderer = this;
			this.topEffects.doLayout();
			this.bottomEffects.doLayout();
			if (this.bar.simileMark === SimileMark.SecondOfDouble) this.canWrap = false;
			this.createPreBeatGlyphs();
			this.createBeatGlyphs();
			this.createPostBeatGlyphs();
			this._registerLayoutingInfo();
			this.topEffects.sizeAndAlignEffectBands(false);
			this.bottomEffects.sizeAndAlignEffectBands(false);
			this.updateSizes();
			for (const v of this.helpers.beamHelpers) for (const h of v) h.finish();
			this.computedWidth = this.width;
			this.calculateOverflows(0, this.height);
		}
		calculateOverflows(_rendererTop, rendererBottom) {
			const preBeatGlyphs = this._preBeatGlyphs.glyphs;
			if (preBeatGlyphs) for (const g of preBeatGlyphs) {
				const topY = g.getBoundingBoxTop();
				if (topY < 0) this.registerOverflowTop(topY * -1);
				const bottomY = g.getBoundingBoxBottom();
				if (bottomY > rendererBottom) this.registerOverflowBottom(bottomY - rendererBottom);
			}
			const postBeatGlyphs = this._postBeatGlyphs.glyphs;
			if (postBeatGlyphs) for (const g of postBeatGlyphs) {
				const topY = g.getBoundingBoxTop();
				if (topY < 0) this.registerOverflowTop(topY * -1);
				const bottomY = g.getBoundingBoxBottom();
				if (bottomY > rendererBottom) this.registerOverflowBottom(bottomY - rendererBottom);
			}
			const v = this.voiceContainer;
			const contentMinY = v.getBoundingBoxTop();
			if (contentMinY < 0) this.registerOverflowTop(contentMinY * -1);
			const contentMaxY = v.getBoundingBoxBottom();
			if (contentMaxY > rendererBottom) this.registerOverflowBottom(contentMaxY - rendererBottom);
			const beatEffectsMinY = this.beatEffectsMinY;
			if (!Number.isNaN(beatEffectsMinY) && beatEffectsMinY < 0) this.registerOverflowTop(beatEffectsMinY * -1);
			const beatEffectsMaxY = this.beatEffectsMaxY;
			if (!Number.isNaN(beatEffectsMaxY) && beatEffectsMaxY > rendererBottom) this.registerOverflowBottom(beatEffectsMaxY - rendererBottom);
		}
		updateSizes() {
			this.staff.registerStaffTop(0);
			this.voiceContainer.x = this._preBeatGlyphs.x + this._preBeatGlyphs.width;
			this._postBeatGlyphs.x = Math.floor(this.voiceContainer.x + this.voiceContainer.width);
			this.width = Math.ceil(this._postBeatGlyphs.x + this._postBeatGlyphs.width);
			const topHeightChanged = this.topEffects.updateEffectBandHeights();
			const bottomHeightChanged = this.bottomEffects.updateEffectBandHeights();
			if (topHeightChanged || bottomHeightChanged) this._registerStaffOverflow();
			this.height += this.layoutingInfo.height;
			this.height = Math.ceil(this.height);
			this.staff.registerStaffBottom(this.height);
		}
		addPreBeatGlyph(g) {
			g.renderer = this;
			this._preBeatGlyphs.addGlyph(g);
		}
		addBeatGlyph(g) {
			g.renderer = this;
			this.voiceContainer.addGlyph(g);
		}
		getBeatContainer(beat) {
			return this.voiceContainer.getBeatContainer(beat);
		}
		paint(cx, cy, canvas) {
			this.paintContent(cx, cy, canvas);
			const topEffectBandY = cy + this.y - this.staff.topOverflow;
			this.topEffects.paint(cx + this.x, topEffectBandY, canvas);
			const bottomEffectBandY = cy + this.y + this.height + this.staff.bottomOverflow - this.bottomEffects.height;
			this.bottomEffects.paint(cx + this.x, bottomEffectBandY, canvas);
		}
		paintContent(cx, cy, canvas) {
			this.paintBackground(cx, cy, canvas);
			canvas.color = this.resources.mainGlyphColor;
			this._preBeatGlyphs.paint(cx + this.x, cy + this.y, canvas);
			this.voiceContainer.paint(cx + this.x, cy + this.y, canvas);
			canvas.color = this.resources.mainGlyphColor;
			this._postBeatGlyphs.paint(cx + this.x, cy + this.y, canvas);
			this._paintMultiSystemSlurs(cx, cy, canvas);
		}
		_paintMultiSystemSlurs(cx, cy, canvas) {
			const multiSystemSlurs = this._multiSystemSlurs;
			if (!multiSystemSlurs) return;
			for (const slur of multiSystemSlurs) slur.paint(cx, cy, canvas);
		}
		paintBackground(cx, cy, canvas) {
			this.layoutingInfo.paint(cx + this.x + this._preBeatGlyphs.x + this._preBeatGlyphs.width, cy + this.y + this.height, canvas);
		}
		buildBoundingsLookup(masterBarBounds, cx, cy) {
			const barBounds = new BarBounds();
			barBounds.bar = this.bar;
			barBounds.visualBounds = new Bounds();
			barBounds.visualBounds.x = cx + this.x;
			barBounds.visualBounds.y = cy + this.y;
			barBounds.visualBounds.w = this.width;
			barBounds.visualBounds.h = this.height;
			barBounds.realBounds = new Bounds();
			barBounds.realBounds.x = cx + this.x;
			barBounds.realBounds.y = cy + this.y;
			barBounds.realBounds.w = this.width;
			barBounds.realBounds.h = this.height;
			masterBarBounds.addBar(barBounds);
			this.voiceContainer.buildBoundingsLookup(barBounds, cx + this.x, cy + this.y);
		}
		addPostBeatGlyph(g) {
			this._postBeatGlyphs.addGlyph(g);
		}
		createPreBeatGlyphs() {
			this.wasFirstOfStaff = this.isFirstOfStaff;
		}
		createBeatGlyphs() {
			if (this.additionalMultiRestBars) {
				const container = new MultiBarRestBeatContainerGlyph();
				this.addBeatGlyph(container);
			} else for (const index of this.bar.filledVoices) this.createVoiceGlyphs(this.bar.voices[index]);
			this.voiceContainer.doLayout();
			if (this.topEffects.isLinkedToPreviousRenderer || this.bottomEffects.isLinkedToPreviousRenderer) this.isLinkedToPrevious = true;
		}
		createVoiceGlyphs(voice) {
			this.topEffects.createVoiceGlyphs(voice);
			this.bottomEffects.createVoiceGlyphs(voice);
		}
		createPostBeatGlyphs() {}
		get beatGlyphsStart() {
			return this.voiceContainer.x;
		}
		get postBeatGlyphsStart() {
			return this._postBeatGlyphs.x;
		}
		getBeatX(beat, requestedPosition = BeatXPosition.PreNotes, useSharedSizes = false) {
			return this.beatGlyphsStart + this.voiceContainer.getBeatX(beat, requestedPosition, useSharedSizes);
		}
		getRatioPositionX(ratio) {
			const firstOnNoteX = this.bar.isEmpty ? this.beatGlyphsStart : this.getBeatX(this.bar.voices[0].beats[0], BeatXPosition.MiddleNotes);
			return firstOnNoteX + (this.postBeatGlyphsStart - firstOnNoteX) * ratio;
		}
		getNoteX(note, requestedPosition) {
			return this.beatGlyphsStart + this.voiceContainer.getNoteX(note, requestedPosition);
		}
		getNoteY(note, requestedPosition) {
			return this.voiceContainer.y + +this.voiceContainer.getNoteY(note, requestedPosition);
		}
		getRestY(beat, requestedPosition) {
			return this.voiceContainer.y + +this.voiceContainer.getRestY(beat, requestedPosition);
		}
		reLayout() {
			this.topEffects.reLayout();
			this.bottomEffects.reLayout();
			this.updateSizes();
			if (this.wasFirstOfStaff && !this.isFirstOfStaff || !this.wasFirstOfStaff && this.isFirstOfStaff) {
				this.recreatePreBeatGlyphs();
				this._postBeatGlyphs.doLayout();
			}
			this._registerLayoutingInfo();
			this.calculateOverflows(0, this.height);
		}
		recreatePreBeatGlyphs() {
			this._preBeatGlyphs = new LeftToRightLayoutingGlyphGroup();
			this._preBeatGlyphs.renderer = this;
			this.createPreBeatGlyphs();
		}
		paintSimileMark(cx, cy, canvas) {
			const _ = ElementStyleHelper.voice(canvas, VoiceSubElement.Glyphs, this.bar.voices[0], true);
			try {
				switch (this.bar.simileMark) {
					case SimileMark.Simple:
						canvas.beginGroup(BeatContainerGlyph.getGroupId(this.bar.voices[0].beats[0]));
						CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + this.width / 2, cy + this.y + this.height / 2, 1, MusicFontSymbol.Repeat1Bar, true);
						canvas.endGroup();
						break;
					case SimileMark.SecondOfDouble:
						canvas.beginGroup(BeatContainerGlyph.getGroupId(this.bar.voices[0].beats[0]));
						canvas.beginGroup(BeatContainerGlyph.getGroupId(this.bar.previousBar.voices[0].beats[0]));
						CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, cy + this.y + this.height / 2, 1, MusicFontSymbol.Repeat2Bars, true);
						canvas.endGroup();
						canvas.endGroup();
						break;
				}
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		completeBeamingHelper(_helper) {}
	};
	//#endregion
	//#region src/rendering/glyphs/NoteVibratoGlyph.ts
	/**
	* @internal
	*/
	var VibratoGlyphBase = class extends GroupedEffectGlyph {
		_type;
		_symbol = MusicFontSymbol.None;
		_repeatOffsetX = 0;
		_symbolOffsetY = 0;
		_partialWaves;
		constructor(x, y, type, partialWaves = false) {
			super(BeatXPosition.EndBeat);
			this._type = type;
			this.x = x;
			this.y = y;
			this._partialWaves = partialWaves;
		}
		doLayout() {
			super.doLayout();
			switch (this._type) {
				case VibratoType.Slight:
					this._symbol = this.slightVibratoGlyph;
					break;
				case VibratoType.Wide:
					this._symbol = this.wideVibratoGlyph;
					break;
			}
			this._repeatOffsetX = this.renderer.smuflMetrics.repeatOffsetX.get(this._symbol);
			this._symbolOffsetY = this.renderer.smuflMetrics.glyphTop.get(this._symbol);
			this.height = this.renderer.smuflMetrics.glyphHeights.get(this._symbol);
		}
		paintGrouped(cx, cy, endX, canvas) {
			let loops = (endX - (cx + this.x)) / this._repeatOffsetX;
			if (!this._partialWaves) loops = Math.floor(loops);
			if (loops < 1) loops = 1;
			const symbols = [];
			for (let i = 0; i < loops; i++) symbols.push(this._symbol);
			canvas.fillMusicFontSymbols(cx + this.x, cy + this.y + this._symbolOffsetY, 1, symbols, false);
		}
	};
	/**
	* @internal
	*/
	var NoteVibratoGlyph = class extends VibratoGlyphBase {
		get slightVibratoGlyph() {
			return MusicFontSymbol.GuitarVibratoStroke;
		}
		get wideVibratoGlyph() {
			return MusicFontSymbol.GuitarWideVibratoStroke;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabBendRenderPoint.ts
	/**
	* @internal
	*/
	var TabBendRenderPoint = class extends BendPoint {
		lineValue = 0;
		constructor(offset = 0, value = 0) {
			super(offset, value);
			this.lineValue = value;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabBendGlyph.ts
	/**
	* @internal
	*/
	var TabBendGlyph = class TabBendGlyph extends Glyph {
		_notes = [];
		_renderPoints = /* @__PURE__ */ new Map();
		_preBendMinValue = -1;
		_bendMiddleMinValue = -1;
		_bendEndMinValue = -1;
		_bendEndContinuedMinValue = -1;
		_releaseMinValue = -1;
		_releaseContinuedMinValue = -1;
		_maxBendValue = -1;
		checkForOverflow = false;
		constructor() {
			super(0, 0);
		}
		addBends(note) {
			this._notes.push(note);
			const renderPoints = this._createRenderingPoints(note);
			this._renderPoints.set(note.id, renderPoints);
			if (this._maxBendValue === -1 || this._maxBendValue < note.maxBendPoint.value) this._maxBendValue = note.maxBendPoint.value;
			let value = 0;
			switch (note.bendType) {
				case BendType.Bend:
					value = renderPoints[1].value;
					if (note.isTieOrigin) {
						if (this._bendEndContinuedMinValue === -1 || value < this._bendEndContinuedMinValue) this._bendEndContinuedMinValue = value;
					} else if (this._bendEndMinValue === -1 || value < this._bendEndMinValue) this._bendEndMinValue = value;
					break;
				case BendType.Release:
					value = renderPoints[1].value;
					if (note.isTieOrigin) {
						if (this._releaseContinuedMinValue === -1 || value < this._releaseContinuedMinValue) this._releaseContinuedMinValue = value;
					} else if (value > 0 && (this._releaseMinValue === -1 || value < this._releaseMinValue)) this._releaseMinValue = value;
					break;
				case BendType.BendRelease:
					value = renderPoints[1].value;
					if (this._bendMiddleMinValue === -1 || value < this._bendMiddleMinValue) this._bendMiddleMinValue = value;
					value = renderPoints[2].value;
					if (note.isTieOrigin) {
						if (this._releaseContinuedMinValue === -1 || value < this._releaseContinuedMinValue) this._releaseContinuedMinValue = value;
					} else if (value > 0 && (this._releaseMinValue === -1 || value < this._releaseMinValue)) this._releaseMinValue = value;
					break;
				case BendType.Prebend:
					value = renderPoints[0].value;
					if (this._preBendMinValue === -1 || value < this._preBendMinValue) this._preBendMinValue = value;
					break;
				case BendType.PrebendBend:
					value = renderPoints[0].value;
					if (this._preBendMinValue === -1 || value < this._preBendMinValue) this._preBendMinValue = value;
					value = renderPoints[1].value;
					if (note.isTieOrigin) {
						if (this._bendEndContinuedMinValue === -1 || value < this._bendEndContinuedMinValue) this._bendEndContinuedMinValue = value;
					} else if (this._bendEndMinValue === -1 || value < this._bendEndMinValue) this._bendEndMinValue = value;
					break;
				case BendType.PrebendRelease:
					value = renderPoints[0].value;
					if (this._preBendMinValue === -1 || value < this._preBendMinValue) this._preBendMinValue = value;
					value = renderPoints[1].value;
					if (note.isTieOrigin) {
						if (this._releaseContinuedMinValue === -1 || value < this._releaseContinuedMinValue) this._releaseContinuedMinValue = value;
					} else if (value > 0 && (this._releaseMinValue === -1 || value < this._releaseMinValue)) this._releaseMinValue = value;
					break;
			}
		}
		doLayout() {
			super.doLayout();
			this._calculateAndRegisterOverflow();
			let value = 0;
			for (const note of this._notes) {
				const renderPoints = this._renderPoints.get(note.id);
				switch (note.bendType) {
					case BendType.Bend:
						renderPoints[1].lineValue = note.isTieOrigin ? this._bendEndContinuedMinValue : this._bendEndMinValue;
						break;
					case BendType.Release:
						value = note.isTieOrigin ? this._releaseContinuedMinValue : this._releaseMinValue;
						if (value >= 0) renderPoints[1].lineValue = value;
						break;
					case BendType.BendRelease:
						renderPoints[1].lineValue = this._bendMiddleMinValue;
						value = note.isTieOrigin ? this._releaseContinuedMinValue : this._releaseMinValue;
						if (value >= 0) renderPoints[2].lineValue = value;
						break;
					case BendType.Prebend:
						renderPoints[0].lineValue = this._preBendMinValue;
						break;
					case BendType.PrebendBend:
						renderPoints[0].lineValue = this._preBendMinValue;
						renderPoints[1].lineValue = note.isTieOrigin ? this._bendEndContinuedMinValue : this._bendEndMinValue;
						break;
					case BendType.PrebendRelease:
						renderPoints[0].lineValue = this._preBendMinValue;
						value = note.isTieOrigin ? this._releaseContinuedMinValue : this._releaseMinValue;
						if (value >= 0) renderPoints[1].lineValue = value;
						break;
				}
			}
			this.width = 0;
			this._notes.sort((a, b) => {
				if (a.isStringed) return a.string - b.string;
				return a.realValue - b.realValue;
			});
		}
		_calculateAndRegisterOverflow() {
			const res = this.renderer.resources;
			const smufl = this.renderer.smuflMetrics;
			let bendHeight = this._maxBendValue * smufl.tabBendPerValueHeight;
			bendHeight += smufl.tabBendStaffPadding;
			const canvas = this.renderer.scoreRenderer.canvas;
			canvas.font = res.tablatureFont;
			const size = canvas.measureText("full");
			bendHeight += size.height + res.engravingSettings.tabBendLabelPadding;
			this.renderer.registerOverflowTop(bendHeight);
		}
		_createRenderingPoints(note) {
			const renderingPoints = [];
			switch (note.bendType) {
				case BendType.Custom:
					for (const bendPoint of note.bendPoints) renderingPoints.push(new TabBendRenderPoint(bendPoint.offset, bendPoint.value));
					break;
				case BendType.BendRelease:
					renderingPoints.push(new TabBendRenderPoint(0, note.bendPoints[0].value));
					renderingPoints.push(new TabBendRenderPoint(BendPoint.MaxPosition / 2 | 0, note.bendPoints[1].value));
					renderingPoints.push(new TabBendRenderPoint(BendPoint.MaxPosition, note.bendPoints[3].value));
					break;
				case BendType.Bend:
				case BendType.Hold:
				case BendType.Prebend:
				case BendType.PrebendBend:
				case BendType.PrebendRelease:
				case BendType.Release:
					renderingPoints.push(new TabBendRenderPoint(0, note.bendPoints[0].value));
					renderingPoints.push(new TabBendRenderPoint(BendPoint.MaxPosition, note.bendPoints[1].value));
					break;
			}
			return renderingPoints;
		}
		paint(cx, cy, canvas) {
			const color = canvas.color;
			if (this._notes.length > 1) canvas.color = this.renderer.resources.secondaryGlyphColor;
			for (const note of this._notes) {
				const startNoteRenderer = this.renderer;
				let endNote = note;
				let isMultiBeatBend = false;
				let endNoteRenderer = null;
				let endNoteHasBend = false;
				let endBeat = null;
				while (endNote.isTieOrigin) {
					const nextNote = endNote.tieDestination;
					endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, nextNote.beat.voice.bar);
					if (!endNoteRenderer || startNoteRenderer.staff !== endNoteRenderer.staff) break;
					endNote = nextNote;
					isMultiBeatBend = true;
					if (endNote.hasBend || !this.renderer.settings.notation.extendBendArrowsOnTiedNotes || endNote.vibrato !== VibratoType.None) {
						endNoteHasBend = true;
						break;
					}
				}
				endBeat = endNote.beat;
				endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, endBeat.voice.bar);
				if (endBeat.isLastOfVoice && !endNote.hasBend && this.renderer.settings.notation.extendBendArrowsOnTiedNotes) endBeat = null;
				const smufl = startNoteRenderer.smuflMetrics;
				const tabBendArrowSize = smufl.glyphWidths.get(MusicFontSymbol.ArrowheadBlackDown);
				const topY = cy + startNoteRenderer.y - smufl.tabBendStaffPadding;
				let startX = cx + startNoteRenderer.x;
				const renderPoints = this._renderPoints.get(note.id);
				if (renderPoints[0].value > 0 || note.isContinuedBend) startX += startNoteRenderer.getBeatX(note.beat, BeatXPosition.MiddleNotes);
				else startX += startNoteRenderer.getNoteX(note, NoteXPosition.Right);
				let endX = 0;
				if (!endBeat || endBeat.isLastOfVoice && !endNoteHasBend) {
					endX = cx + endNoteRenderer.x + endNoteRenderer.postBeatGlyphsStart;
					endX -= this.renderer.smuflMetrics.postNoteEffectPadding;
				} else if (endNoteHasBend || !endBeat.nextBeat) endX = cx + endNoteRenderer.x + endNoteRenderer.getBeatX(endBeat, BeatXPosition.MiddleNotes);
				else if (note.bendType === BendType.Hold) endX = cx + endNoteRenderer.x + endNoteRenderer.getBeatX(endBeat.nextBeat, BeatXPosition.OnNotes);
				else {
					endX = cx + endNoteRenderer.x + endNoteRenderer.getBeatX(endBeat.nextBeat, BeatXPosition.PreNotes);
					endX -= this.renderer.smuflMetrics.postNoteEffectPadding;
				}
				if (!isMultiBeatBend) endX -= tabBendArrowSize / 2;
				this._paintBendLines(canvas, startX, topY, endX, startNoteRenderer, note, renderPoints);
				this._paintBendVibrato(canvas, cx, endX + tabBendArrowSize / 2, topY - smufl.tabBendPerValueHeight * renderPoints[renderPoints.length - 1].lineValue, endNoteRenderer, endNote);
				canvas.color = color;
			}
		}
		_paintBendVibrato(canvas, cx, vibratoX, topY, endNoteRenderer, endNote) {
			if (endNote.isTieDestination && endNote.vibrato !== VibratoType.None && !endNote.hasBend) {
				const vibratoEndX = cx + endNoteRenderer.x;
				const vibrato = new NoteVibratoGlyph(vibratoX - vibratoEndX, 0, endNote.vibrato);
				vibrato.beat = endNote.beat;
				vibrato.renderer = endNoteRenderer;
				vibrato.doLayout();
				vibrato.paint(vibratoEndX, topY, canvas);
			}
		}
		_paintBendLines(canvas, cx, cy, endX, noteRenderer, note, renderPoints) {
			const l = canvas.lineWidth;
			const res = this.renderer.resources;
			const bl = canvas.textBaseline;
			canvas.textBaseline = TextBaseline.Alphabetic;
			canvas.lineWidth = res.engravingSettings.arrowShaftThickness;
			const dX = (endX - cx) / BendPoint.MaxPosition;
			for (let i = 0, j = renderPoints.length - 1; i < j; i++) {
				const firstPt = renderPoints[i];
				let secondPt = renderPoints[i + 1];
				if (i === 0 && firstPt.value !== 0 && !note.isTieDestination) this._paintBend(canvas, cx, cy, dX, noteRenderer, note, new TabBendRenderPoint(0, 0), firstPt);
				if (note.bendType !== BendType.Prebend) {
					if (i === 0) cx += this.renderer.smuflMetrics.postNoteEffectPadding;
					this._paintBend(canvas, cx, cy, dX, noteRenderer, note, firstPt, secondPt);
				} else if (note.isTieOrigin && note.tieDestination.hasBend) {
					secondPt = new TabBendRenderPoint(BendPoint.MaxPosition, firstPt.value);
					secondPt.lineValue = firstPt.lineValue;
					this._paintBend(canvas, cx, cy, dX, noteRenderer, note, firstPt, secondPt);
				}
			}
			canvas.lineWidth = l;
			canvas.textBaseline = bl;
		}
		_paintBendLine(canvas, x1, y1, x2, y2, firstPt, secondPt) {
			if (firstPt.value === secondPt.value) {
				if (firstPt.lineValue > 0) {
					let dashX = x2;
					const dashSize = this.renderer.smuflMetrics.tabBendDashSize;
					const end = x1 + dashSize;
					if ((dashX - x1) / (dashSize * 2) < 1) {
						canvas.moveTo(dashX, y1);
						canvas.lineTo(x1, y1);
					} else while (dashX > end) {
						canvas.moveTo(dashX, y1);
						canvas.lineTo(dashX - dashSize, y1);
						dashX -= dashSize * 2;
					}
					canvas.stroke();
				}
			} else if (x2 > x1) {
				const arrowOffset = secondPt.value > firstPt.value ? 3 : -3;
				canvas.moveTo(x1, y1);
				canvas.bezierCurveTo((x1 + x2) / 2, y1, x2, y1, x2, y2 + arrowOffset);
				canvas.stroke();
			} else {
				canvas.moveTo(x1, y1);
				canvas.lineTo(x2, y2);
				canvas.stroke();
			}
		}
		_paintBend(canvas, cx, cy, dX, noteRenderer, note, firstPt, secondPt) {
			const noteNumberAndLinePaddingY = noteRenderer.lineOffset / 2;
			const res = noteRenderer.resources;
			const smufl = res.engravingSettings;
			const x1 = cx + dX * firstPt.offset;
			let y1;
			if (firstPt.value === 0) {
				y1 = cy + smufl.tabBendStaffPadding;
				if (secondPt.offset === firstPt.offset) y1 += noteRenderer.getNoteY(note.beat.maxStringNote, NoteYPosition.Top) - noteNumberAndLinePaddingY;
				else y1 += noteRenderer.getNoteY(note, NoteYPosition.Center);
			} else y1 = cy - smufl.tabBendPerValueHeight * firstPt.lineValue;
			const x2 = cx + dX * secondPt.offset;
			let y2;
			if (secondPt.lineValue === 0) y2 = cy + smufl.tabBendStaffPadding + noteRenderer.getNoteY(note.beat.maxStringNote, NoteYPosition.Center);
			else y2 = cy - smufl.tabBendPerValueHeight * secondPt.lineValue;
			this._paintBendLine(canvas, x1, y1, x2, y2, firstPt, secondPt);
			const arrowSize = smufl.glyphWidths.get(MusicFontSymbol.ArrowheadBlackDown);
			if (firstPt.value !== secondPt.value) {
				const up = secondPt.value > firstPt.value;
				this._paintBendLineArrow(canvas, x2, y2, y1, arrowSize, up);
				this._paintBendLineSlurText(canvas, x1, y1, x2, y2, note, res.graceFont);
				this._paintBendLineValueText(canvas, y1, x2, y2 - smufl.tabBendLabelPadding, firstPt, secondPt, res.tablatureFont);
			}
		}
		_paintBendLineSlurText(canvas, x1, y1, x2, y2, note, font) {
			if (note.bendStyle === BendStyle.Gradual) {
				const slurText = "grad.";
				const size = canvas.measureText(slurText);
				canvas.font = font;
				let y = 0;
				let x = 0;
				if (y1 > y2) {
					const h = Math.abs(y1 - y2);
					y = h > size.height ? y1 - h / 2 : y1;
					x = (x1 + x2 - size.width) / 2;
				} else {
					y = y1;
					x = x2 - size.width;
				}
				canvas.fillText(slurText, x, y);
			}
		}
		_paintBendLineValueText(canvas, y1, x2, y2, firstPt, secondPt, font) {
			if (secondPt.value !== 0) {
				const up = secondPt.value > firstPt.value;
				let bendValue = secondPt.value;
				let bendValueText = "";
				if (bendValue === 4) {
					bendValueText = "full";
					bendValue -= 4;
				} else if (bendValue >= 4 || bendValue <= -4) {
					const steps = bendValue / 4 | 0;
					bendValueText += steps;
					bendValue -= steps * 4;
				}
				if (bendValue > 0) bendValueText += TabBendGlyph.getFractionSign(bendValue);
				if (bendValueText !== "") {
					const textY = up ? y2 : y1 + Math.abs(y2 - y1) * 1 / 3;
					canvas.font = font;
					const textX = x2 - canvas.measureText(bendValueText).width / 2;
					canvas.fillText(bendValueText, textX, textY);
				}
			}
		}
		_paintBendLineArrow(canvas, x2, y2, y1, arrowSize, up) {
			if (up) {
				if (y2 + arrowSize > y1) y2 = y1 - arrowSize;
				canvas.beginPath();
				canvas.moveTo(x2, y2);
				canvas.lineTo(x2 - arrowSize * .5, y2 + arrowSize);
				canvas.lineTo(x2 + arrowSize * .5, y2 + arrowSize);
				canvas.closePath();
				canvas.fill();
			} else {
				if (y2 < y1) y2 = y1 + arrowSize;
				canvas.beginPath();
				canvas.moveTo(x2, y2);
				canvas.lineTo(x2 - arrowSize * .5, y2 - arrowSize);
				canvas.lineTo(x2 + arrowSize * .5, y2 - arrowSize);
				canvas.closePath();
				canvas.fill();
			}
		}
		static getFractionSign(steps) {
			switch (steps) {
				case 1: return "¼";
				case 2: return "½";
				case 3: return "¾";
				default: return `${steps}/ 4`;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabWhammyBarGlyph.ts
	/**
	* @internal
	*/
	var TabWhammyBarGlyph = class extends EffectGlyph {
		_beat;
		_renderPoints;
		_isSimpleDip = false;
		originalTopOffset = 0;
		originalBottomOffset = 0;
		topOffset = 0;
		bottomOffset = 0;
		constructor(beat) {
			super(0, 0);
			this._beat = beat;
			this._renderPoints = this._createRenderingPoints(beat);
		}
		_createRenderingPoints(beat) {
			if (beat.whammyBarType === WhammyType.Custom) return beat.whammyBarPoints;
			const renderingPoints = [];
			switch (beat.whammyBarType) {
				case WhammyType.Dive:
				case WhammyType.Hold:
				case WhammyType.PrediveDive:
				case WhammyType.Predive:
					renderingPoints.push(new BendPoint(0, beat.whammyBarPoints[0].value));
					renderingPoints.push(new BendPoint(BendPoint.MaxPosition, beat.whammyBarPoints[1].value));
					break;
				case WhammyType.Dip:
					renderingPoints.push(new BendPoint(0, beat.whammyBarPoints[0].value));
					renderingPoints.push(new BendPoint(BendPoint.MaxPosition / 2 | 0, beat.whammyBarPoints[1].value));
					renderingPoints.push(new BendPoint(BendPoint.MaxPosition, beat.whammyBarPoints[beat.whammyBarPoints.length - 1].value));
					break;
			}
			return renderingPoints;
		}
		doLayout() {
			super.doLayout();
			if (this._beat.whammyBarType === WhammyType.Custom) return;
			this._isSimpleDip = this.renderer.settings.notation.notationMode === NotationMode.SongBook && this._beat.whammyBarType === WhammyType.Dip;
			const minValue = this._beat.minWhammyPoint;
			const maxValue = this._beat.maxWhammyPoint;
			let topY = maxValue.value > 0 ? -this._getOffset(maxValue.value) : 0;
			let bottomY = minValue.value < 0 ? -this._getOffset(minValue.value) : 0;
			const c = this.renderer.scoreRenderer.canvas;
			c.font = this.renderer.resources.tablatureFont;
			const labelSize = c.measureText("-1").height + this.renderer.smuflMetrics.tabWhammyTextPadding;
			if (topY !== 0 || this._beat.whammyBarPoints[0].value !== 0 || this.renderer.settings.notation.isNotationElementVisible(NotationElement.ZerosOnDiveWhammys)) topY -= labelSize;
			if (bottomY !== 0) if (this._isSimpleDip) topY -= labelSize;
			else {
				const bottomYWithLabel = bottomY - labelSize;
				if (bottomYWithLabel < topY) topY = bottomYWithLabel;
			}
			topY = Math.abs(topY);
			bottomY = Math.abs(bottomY);
			this.topOffset = topY;
			this.bottomOffset = bottomY;
			this.originalTopOffset = topY;
			this.originalBottomOffset = bottomY;
			this.height = topY + bottomY;
			this.width = 0;
		}
		_getOffset(value) {
			if (value === 0) return 0;
			let offset = this.renderer.smuflMetrics.tabWhammyPerHalfHeight + Math.log2(Math.abs(value) / 2) * this.renderer.smuflMetrics.tabWhammyPerHalfHeight;
			if (value < 0) offset = -offset;
			return offset;
		}
		paint(cx, cy, canvas) {
			const _ = ElementStyleHelper.beat(canvas, BeatSubElement.StandardNotationEffects, this._beat);
			try {
				const startNoteRenderer = this.renderer;
				let endBeat = this._beat.nextBeat;
				let endNoteRenderer = null;
				let endXPositionType = BeatXPosition.PreNotes;
				if (endBeat) {
					endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, endBeat.voice.bar);
					if (!endNoteRenderer || endNoteRenderer.staff !== startNoteRenderer.staff) {
						endBeat = null;
						endNoteRenderer = null;
					} else if (endNoteRenderer !== startNoteRenderer && !endBeat.hasWhammyBar) {
						endBeat = null;
						endNoteRenderer = null;
					} else endXPositionType = endBeat.hasWhammyBar && (startNoteRenderer.settings.notation.notationMode !== NotationMode.SongBook || endBeat.whammyBarType !== WhammyType.Dip) ? BeatXPosition.MiddleNotes : BeatXPosition.PreNotes;
				}
				let startX = 0;
				let endX = 0;
				if (this._isSimpleDip) {
					startX = cx + startNoteRenderer.getBeatX(this._beat, BeatXPosition.OnNotes, true);
					endX = cx + startNoteRenderer.getBeatX(this._beat, BeatXPosition.PostNotes, true);
				} else {
					startX = cx + startNoteRenderer.getBeatX(this._beat, BeatXPosition.MiddleNotes, true);
					if (endNoteRenderer) endX = cx - startNoteRenderer.x + endNoteRenderer.x + endNoteRenderer.getBeatX(endBeat, endXPositionType, true);
					else endX = cx + startNoteRenderer.getBeatX(this._beat, BeatXPosition.EndBeat) - startNoteRenderer.smuflMetrics.postNoteEffectPadding;
				}
				const oldAlign = canvas.textAlign;
				const oldBaseLine = canvas.textBaseline;
				canvas.textAlign = TextAlign.Center;
				canvas.textBaseline = TextBaseline.Alphabetic;
				canvas.font = this.renderer.resources.tablatureFont;
				if (this._renderPoints.length >= 2) {
					const dx = (endX - startX) / BendPoint.MaxPosition;
					canvas.beginPath();
					const zeroY = cy + this.topOffset;
					let slurText = this._beat.whammyStyle === BendStyle.Gradual ? "grad." : "";
					for (let i = 0, j = this._renderPoints.length - 1; i < j; i++) {
						const firstPt = this._renderPoints[i];
						const secondPt = this._renderPoints[i + 1];
						let isFirst = i === 0;
						if (i === 0 && firstPt.value !== 0 && !this._beat.isContinuedWhammy) {
							this._paintWhammy(false, new BendPoint(0, 0), firstPt, startX, zeroY, dx, canvas);
							isFirst = false;
						}
						this._paintWhammy(isFirst, firstPt, secondPt, startX, zeroY, dx, canvas, slurText);
						slurText = "";
					}
					canvas.stroke();
				}
				canvas.textAlign = oldAlign;
				canvas.textBaseline = oldBaseLine;
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		_paintWhammy(isFirst, firstPt, secondPt, cx, cy, dx, canvas, slurText) {
			const x1 = cx + dx * firstPt.offset;
			const x2 = cx + dx * secondPt.offset;
			const y1 = cy - this._getOffset(firstPt.value);
			const y2 = cy - this._getOffset(secondPt.value);
			if (firstPt.offset === secondPt.offset) {
				const dashSize = this.renderer.smuflMetrics.tabWhammyDashSize;
				if (Math.abs(y2 - y1) / (dashSize * 2) < 1) {
					canvas.moveTo(x1, y1);
					canvas.lineTo(x2, y2);
				} else {
					const dashEndY = Math.max(y1, y2);
					let dashStartY = Math.min(y1, y2);
					while (dashEndY > dashStartY) {
						canvas.moveTo(x1, dashStartY);
						canvas.lineTo(x1, dashStartY + dashSize);
						dashStartY += dashSize * 2;
					}
				}
				canvas.stroke();
			} else if (firstPt.value === secondPt.value) {
				const dashSize = this.renderer.smuflMetrics.tabWhammyDashSize;
				if (Math.abs(x2 - x1) / (dashSize * 2) < 1) {
					canvas.moveTo(x1, y1);
					canvas.lineTo(x2, y2);
				} else {
					let dashEndX = Math.max(x1, x2);
					const dashStartX = Math.min(x1, x2);
					while (dashEndX > dashStartX) {
						canvas.moveTo(dashEndX, y1);
						canvas.lineTo(dashEndX - dashSize, y1);
						dashEndX -= dashSize * 2;
					}
				}
				canvas.stroke();
			} else {
				canvas.moveTo(x1, y1);
				canvas.lineTo(x2, y2);
			}
			const textOffset = this.renderer.smuflMetrics.tabWhammyTextPadding;
			if (isFirst && !this._beat.isContinuedWhammy && !this._isSimpleDip) {
				if (this.renderer.settings.notation.isNotationElementVisible(NotationElement.ZerosOnDiveWhammys)) canvas.fillText("0", x1, y1 - textOffset);
				if (slurText) canvas.fillText(slurText, x1, y1 - textOffset);
			}
			let dV = Math.abs(secondPt.value);
			if ((dV !== 0 || this.renderer.settings.notation.isNotationElementVisible(NotationElement.ZerosOnDiveWhammys) && !this._isSimpleDip) && firstPt.value !== secondPt.value) {
				let s = "";
				if (secondPt.value < 0) s += "-";
				if (dV >= 4) {
					const steps = dV / 4 | 0;
					s += steps;
					dV -= steps * 4;
				} else if (dV === 0) s += "0";
				if (dV > 0) s += TabBendGlyph.getFractionSign(dV);
				let y = 0;
				if (this._isSimpleDip) y = Math.min(y1, y2);
				else y = firstPt.offset === secondPt.offset ? Math.min(y1, y2) : y2;
				const x = x2;
				canvas.fillText(s, x, y - textOffset);
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/SimpleDipWhammyBarEffectInfo.ts
	/**
	* @internal
	*/
	var SimpleDipWhammyBarEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectWhammyBar;
		}
		get effectId() {
			return `${super.effectId}.simpledip`;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(settings, beat) {
			return settings.notation.notationMode === NotationMode.SongBook && beat.hasWhammyBar && beat.whammyBarType === WhammyType.Dip;
		}
		createNewGlyph(_renderer, beat) {
			return new TabWhammyBarGlyph(beat);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BeatVibratoGlyph.ts
	/**
	* @internal
	*/
	var BeatVibratoGlyph = class extends VibratoGlyphBase {
		get slightVibratoGlyph() {
			return MusicFontSymbol.WiggleSawtoothNarrow;
		}
		get wideVibratoGlyph() {
			return MusicFontSymbol.WiggleSawtooth;
		}
	};
	//#endregion
	//#region src/rendering/effects/SlightBeatVibratoEffectInfo.ts
	/**
	* @internal
	*/
	var SlightBeatVibratoEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectSlightBeatVibrato;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeatToEnd;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.vibrato === VibratoType.Slight;
		}
		createNewGlyph(_renderer, _beat) {
			return new BeatVibratoGlyph(0, 0, VibratoType.Slight);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/SlightNoteVibratoEffectInfo.ts
	/**
	* @internal
	*/
	var SlightNoteVibratoEffectInfo = class extends NoteEffectInfoBase {
		_hideOnTiedBend;
		get notationElement() {
			return NotationElement.EffectSlightNoteVibrato;
		}
		shouldCreateGlyphForNote(note) {
			let hasVibrato = note.vibrato === VibratoType.Slight || note.isTieDestination && note.tieOrigin.vibrato === VibratoType.Slight;
			if (this._hideOnTiedBend && hasVibrato && note.isTieDestination && note.tieOrigin.hasBend) hasVibrato = false;
			return hasVibrato;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeatToEnd;
		}
		createNewGlyph(_renderer, _beat) {
			return new NoteVibratoGlyph(0, 0, VibratoType.Slight);
		}
		constructor(hideOnTiedBend) {
			super();
			this._hideOnTiedBend = hideOnTiedBend;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/SustainPedalGlyph.ts
	/**
	* @internal
	*/
	var SustainPedalGlyph = class extends EffectGlyph {
		constructor() {
			super(0, 0);
		}
		doLayout() {
			super.doLayout();
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.KeyboardPedalPed);
		}
		paint(cx, cy, canvas) {
			const renderer = this.renderer;
			const y = cy + this.y;
			const h = this.height;
			const markers = renderer.bar.sustainPedals;
			const textWidth = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.KeyboardPedalPed);
			const starSize = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.KeyboardPedalUp);
			let markerIndex = 0;
			while (markerIndex < markers.length) {
				let marker = markers[markerIndex];
				while (marker != null) {
					const markerX = cx + this.renderer.getRatioPositionX(marker.ratioPosition);
					let linePadding = 0;
					if (marker.pedalType === SustainPedalMarkerType.Down) {
						CanvasHelper.fillMusicFontSymbolSafe(canvas, markerX, y + h, 1, MusicFontSymbol.KeyboardPedalPed, true);
						linePadding = textWidth / 2 + this.renderer.smuflMetrics.sustainPedalLinePadding;
					} else if (marker.pedalType === SustainPedalMarkerType.Up) {
						CanvasHelper.fillMusicFontSymbolSafe(canvas, markerX, y + h, 1, MusicFontSymbol.KeyboardPedalUp, true);
						linePadding = starSize / 2 + this.renderer.smuflMetrics.sustainPedalLinePadding;
					}
					if (marker.nextPedalMarker) if (marker.nextPedalMarker.bar === marker.bar) {
						let nextX = cx + this.renderer.getRatioPositionX(marker.nextPedalMarker.ratioPosition);
						switch (marker.nextPedalMarker.pedalType) {
							case SustainPedalMarkerType.Down:
								nextX -= textWidth / 2;
								break;
							case SustainPedalMarkerType.Hold: break;
							case SustainPedalMarkerType.Up:
								nextX -= starSize / 2;
								break;
						}
						const startX = markerX + linePadding;
						if (nextX > startX) canvas.fillRect(startX, y + h - this.renderer.smuflMetrics.pedalLineThickness, nextX - startX, this.renderer.smuflMetrics.pedalLineThickness);
					} else {
						const nextX = cx + this.x + this.width;
						const startX = markerX + linePadding;
						canvas.fillRect(startX, y + h - this.renderer.smuflMetrics.pedalLineThickness, nextX - startX, this.renderer.smuflMetrics.pedalLineThickness);
					}
					if (markerIndex === 0 && marker.previousPedalMarker) {
						const startX = cx + this.x;
						const endX = markerX - linePadding;
						canvas.fillRect(startX, y + h - this.renderer.smuflMetrics.pedalLineThickness, endX - startX, this.renderer.smuflMetrics.pedalLineThickness);
					}
					markerIndex++;
					if (marker.nextPedalMarker != null && marker.nextPedalMarker.bar !== marker.bar) {
						marker = null;
						markerIndex = markers.length;
					} else marker = marker.nextPedalMarker;
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/SustainPedalEffectInfo.ts
	/**
	* @internal
	*/
	var SustainPedalEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectSustainPedal;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.FullBar;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.voice.index === 0 && beat.index === 0 && beat.voice.bar.sustainPedals.length > 0;
		}
		createNewGlyph(_renderer, _beat) {
			return new SustainPedalGlyph();
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/TabWhammyEffectInfo.ts
	/**
	* @internal
	*/
	var TabWhammyEffectInfo = class TabWhammyEffectInfo extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectWhammyBarLine;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeatToEnd;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.hasWhammyBar;
		}
		createNewGlyph(_renderer, beat) {
			return new TabWhammyBarGlyph(beat);
		}
		canExpand(_from, to) {
			return to.hasWhammyBar;
		}
		static offsetSharedDataKey = "tab.whammy.offset";
		onAlignGlyphs(band) {
			const info = band.renderer.staff.getSharedLayoutData(TabWhammyEffectInfo.offsetSharedDataKey, [0, 0]);
			band.renderer.staff.setSharedLayoutData(TabWhammyEffectInfo.offsetSharedDataKey, info);
			for (const g of band.iterateAllGlyphs()) {
				const tb = g;
				if (tb.originalTopOffset > info[0]) info[0] = tb.originalTopOffset;
				if (tb.originalBottomOffset > info[1]) info[1] = tb.originalBottomOffset;
			}
		}
		finalizeBand(band) {
			const info = band.renderer.staff.getSharedLayoutData(TabWhammyEffectInfo.offsetSharedDataKey, [0, 0]);
			const top = info[0];
			const bottom = info[1];
			for (const g of band.iterateAllGlyphs()) {
				const tb = g;
				tb.topOffset = top;
				tb.bottomOffset = bottom;
				tb.height = top + bottom;
			}
			band.slot.shared.height = top + bottom;
			band.height = top + bottom;
		}
	};
	//#endregion
	//#region src/rendering/effects/TapEffectInfo.ts
	/**
	* @internal
	*/
	var TapEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectTap;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.slap || beat.pop || beat.tap;
		}
		createNewGlyph(renderer, beat) {
			const res = renderer.resources;
			if (beat.slap) return new TextGlyph(0, 0, "S", res.elementFonts.get(NotationElement.EffectTap), TextAlign.Center);
			if (beat.pop) return new TextGlyph(0, 0, "P", res.elementFonts.get(NotationElement.EffectTap), TextAlign.Center);
			return new TextGlyph(0, 0, "T", res.elementFonts.get(NotationElement.EffectTap), TextAlign.Center);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BarTempoGlyph.ts
	/**
	* This glyph renders tempo annotations for tempo automations
	* where the drawing position is determined more dynamically while rendering.
	* @internal
	*/
	var BarTempoGlyph = class extends EffectGlyph {
		_tempoAutomations;
		constructor(tempoAutomations) {
			super(0, 0);
			this._tempoAutomations = tempoAutomations;
		}
		doLayout() {
			super.doLayout();
			const res = this.renderer.resources;
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.MetNoteQuarterUp) * res.engravingSettings.tempoNoteScale;
		}
		paint(cx, cy, canvas) {
			for (const automation of this._tempoAutomations) {
				let x = cx + this.renderer.getRatioPositionX(automation.ratioPosition);
				const res = this.renderer.resources;
				canvas.font = res.elementFonts.get(NotationElement.EffectMarker);
				const notePosY = cy + this.y + this.height + this.renderer.smuflMetrics.glyphBottom.get(MusicFontSymbol.MetNoteQuarterUp) * res.engravingSettings.tempoNoteScale;
				const b = canvas.textBaseline;
				canvas.textBaseline = TextBaseline.Alphabetic;
				if (automation.text) {
					const text = `${automation.text} `;
					const size = canvas.measureText(text);
					canvas.fillText(text, x, notePosY);
					x += size.width;
				} else x -= res.engravingSettings.glyphWidths.get(MusicFontSymbol.MetNoteQuarterUp) / 2;
				CanvasHelper.fillMusicFontSymbolSafe(canvas, x, notePosY, res.engravingSettings.tempoNoteScale, MusicFontSymbol.MetNoteQuarterUp);
				x += this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.MetNoteQuarterUp) * res.engravingSettings.tempoNoteScale;
				canvas.fillText(` = ${automation.value.toString()}`, x, notePosY);
				canvas.textBaseline = b;
				x += canvas.measureText(` = ${automation.value.toString()}`).width;
			}
		}
	};
	//#endregion
	//#region src/rendering/effects/TempoEffectInfo.ts
	/**
	* @internal
	*/
	var TempoEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectTempo;
		}
		get hideOnMultiTrack() {
			return true;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SinglePreBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.voice.bar.staff.index === 0 && beat.voice.index === 0 && beat.index === 0 && beat.voice.bar.masterBar.tempoAutomations.some((t) => t.isVisible);
		}
		createNewGlyph(_renderer, beat) {
			return new BarTempoGlyph(beat.voice.bar.masterBar.tempoAutomations.filter((a) => a.isVisible));
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/TextEffectInfo.ts
	/**
	* @internal
	*/
	var TextEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectText;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return !!beat.text;
		}
		createNewGlyph(renderer, beat) {
			return new TextGlyph(0, 0, beat.text, renderer.resources.elementFonts.get(NotationElement.EffectText), TextAlign.Left);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TrillGlyph.ts
	/**
	* @internal
	*/
	var TrillGlyph = class extends GroupedEffectGlyph {
		constructor(x, y) {
			super(BeatXPosition.EndBeat);
			this.x = x;
			this.y = y;
		}
		doLayout() {
			super.doLayout();
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.OrnamentTrill);
		}
		paintGrouped(cx, cy, endX, canvas) {
			const trillSize = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.OrnamentTrill);
			const lineStart = cx + this.x + trillSize;
			const step = this.renderer.smuflMetrics.repeatOffsetX.get(MusicFontSymbol.WiggleTrill);
			const loops = Math.ceil((endX - lineStart) / step);
			const symbols = [MusicFontSymbol.OrnamentTrill];
			for (let i = 0; i < loops; i++) symbols.push(MusicFontSymbol.WiggleTrill);
			canvas.fillMusicFontSymbols(cx + this.x - trillSize / 2, cy + this.y + this.height, 1, symbols, false);
		}
	};
	//#endregion
	//#region src/rendering/effects/TrillEffectInfo.ts
	/**
	* @internal
	*/
	var TrillEffectInfo = class extends NoteEffectInfoBase {
		get notationElement() {
			return NotationElement.EffectTrill;
		}
		shouldCreateGlyphForNote(note) {
			return note.isTrill;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeatToEnd;
		}
		createNewGlyph(_renderer, _beat) {
			return new TrillGlyph(0, 0);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TripletFeelGlyph.ts
	/**
	* @internal
	*/
	var TripletFeelGlyph = class extends EffectGlyph {
		_tripletFeel;
		_tupletHeight = 0;
		_tupletPadding = 0;
		constructor(tripletFeel) {
			super(0, 0);
			this._tripletFeel = tripletFeel;
		}
		doLayout() {
			super.doLayout();
			const noteScale = this.renderer.smuflMetrics.tempoNoteScale;
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.MetNoteQuarterUp) * noteScale;
			this._tupletHeight = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tuplet3) * noteScale;
			this._tupletPadding = this.renderer.smuflMetrics.tripletFeelBracketPadding;
			this.height += this._tupletHeight;
		}
		paint(cx, cy, canvas) {
			cx += this.x;
			cy += this.y;
			let leftNotes = 0;
			let rightNotes = 0;
			switch (this._tripletFeel) {
				case TripletFeel.NoTripletFeel:
					leftNotes = 0;
					rightNotes = 0;
					break;
				case TripletFeel.Triplet8th:
					leftNotes = 0;
					rightNotes = 2;
					break;
				case TripletFeel.Triplet16th:
					leftNotes = 1;
					rightNotes = 3;
					break;
				case TripletFeel.Dotted8th:
					leftNotes = 0;
					rightNotes = 4;
					break;
				case TripletFeel.Dotted16th:
					leftNotes = 1;
					rightNotes = 5;
					break;
				case TripletFeel.Scottish8th:
					leftNotes = 0;
					rightNotes = 6;
					break;
				case TripletFeel.Scottish16th:
					leftNotes = 1;
					rightNotes = 7;
					break;
			}
			const noteScale = this.renderer.smuflMetrics.tempoNoteScale;
			const noteY = cy + this.renderer.smuflMetrics.glyphTop.get(MusicFontSymbol.MetNoteQuarterUp) * noteScale;
			const textY = cy + this.height;
			const b = canvas.textBaseline;
			canvas.textBaseline = TextBaseline.Bottom;
			canvas.font = this.renderer.resources.elementFonts.get(NotationElement.EffectTripletFeel);
			canvas.fillText("(", cx, textY);
			cx += canvas.measureText("( ").width;
			cx = this._drawGroup(cx, noteY + this._tupletHeight, canvas, leftNotes);
			canvas.fillText(" = ", cx, textY);
			cx += canvas.measureText(" = ").width;
			cx = this._drawGroup(cx, noteY + this._tupletHeight, canvas, rightNotes);
			canvas.fillText(" )", cx, textY);
			canvas.textBaseline = b;
		}
		_drawGroup(cx, cy, canvas, group) {
			const noteScale = this.renderer.smuflMetrics.tempoNoteScale;
			let leftNote = [];
			let rightNote = [];
			const beams = [];
			let tuplet = MusicFontSymbol.None;
			switch (group) {
				case 0:
					beams.push(TextAlign.Center);
					leftNote = [MusicFontSymbol.MetNoteQuarterUp];
					rightNote = [MusicFontSymbol.MetNoteQuarterUp];
					break;
				case 1:
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Center);
					leftNote = [MusicFontSymbol.MetNoteQuarterUp];
					rightNote = [MusicFontSymbol.MetNoteQuarterUp];
					break;
				case 2:
					leftNote = [MusicFontSymbol.MetNoteQuarterUp];
					rightNote = [MusicFontSymbol.MetNote8thUp];
					tuplet = MusicFontSymbol.Tuplet3;
					break;
				case 3:
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Right);
					leftNote = [MusicFontSymbol.MetNoteQuarterUp];
					rightNote = [MusicFontSymbol.MetNoteQuarterUp];
					tuplet = MusicFontSymbol.Tuplet3;
					break;
				case 4:
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Right);
					leftNote = [
						MusicFontSymbol.MetNoteQuarterUp,
						MusicFontSymbol.Space,
						MusicFontSymbol.MetAugmentationDot
					];
					rightNote = [MusicFontSymbol.MetNoteQuarterUp];
					break;
				case 5:
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Right);
					leftNote = [
						MusicFontSymbol.MetNoteQuarterUp,
						MusicFontSymbol.Space,
						MusicFontSymbol.MetAugmentationDot
					];
					rightNote = [MusicFontSymbol.MetNoteQuarterUp];
					break;
				case 6:
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Left);
					leftNote = [MusicFontSymbol.MetNoteQuarterUp];
					rightNote = [
						MusicFontSymbol.MetNoteQuarterUp,
						MusicFontSymbol.Space,
						MusicFontSymbol.MetAugmentationDot
					];
					break;
				case 7:
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Center);
					beams.push(TextAlign.Left);
					leftNote = [MusicFontSymbol.MetNoteQuarterUp];
					rightNote = [
						MusicFontSymbol.MetNoteQuarterUp,
						MusicFontSymbol.Space,
						MusicFontSymbol.MetAugmentationDot
					];
					break;
			}
			const noteSpacing = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.MetNoteQuarterUp) * noteScale;
			const beamStartX = cx + noteSpacing - this.renderer.smuflMetrics.stemThickness * noteScale;
			const beamEndX = beamStartX + noteSpacing * 2 + this.renderer.smuflMetrics.stemThickness * noteScale;
			const beamHeight = this.renderer.smuflMetrics.tempoNoteScale * this.renderer.smuflMetrics.beamThickness;
			const beamSpacing = this.renderer.smuflMetrics.tempoNoteScale * this.renderer.smuflMetrics.beamSpacing;
			const brokenBeamWidth = this.renderer.smuflMetrics.brokenBeamWidth * noteScale;
			let beamY = cy - this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.MetNoteQuarterUp) * noteScale + beamHeight;
			if (tuplet !== MusicFontSymbol.None) {
				const tupletCenterX = (cx + beamEndX) / 2;
				const tupletY = beamY - this._tupletHeight - this._tupletPadding;
				const tupletTop = this.renderer.smuflMetrics.glyphTop.get(tuplet) * noteScale;
				const tupletWidth = this.renderer.smuflMetrics.glyphWidths.get(tuplet) * noteScale;
				CanvasHelper.fillMusicFontSymbolSafe(canvas, tupletCenterX, tupletY + tupletTop, noteScale, tuplet, true);
				const numberLeftX = tupletCenterX - tupletWidth / 2 - this._tupletPadding;
				const numberRightX = tupletCenterX + tupletWidth / 2 + this._tupletPadding;
				const halfTuplet = this._tupletHeight / 2;
				const l = canvas.lineWidth;
				canvas.beginPath();
				canvas.moveTo(cx, tupletY + halfTuplet + halfTuplet);
				canvas.lineTo(cx, tupletY + halfTuplet);
				canvas.lineTo(numberLeftX, tupletY + halfTuplet);
				canvas.moveTo(numberRightX, tupletY + halfTuplet);
				canvas.lineTo(beamEndX, tupletY + halfTuplet);
				canvas.lineTo(beamEndX, tupletY + halfTuplet + halfTuplet);
				canvas.lineWidth = this.renderer.smuflMetrics.tupletBracketThickness * noteScale;
				canvas.stroke();
				canvas.lineWidth = l;
			}
			canvas.fillMusicFontSymbols(cx, cy, noteScale, leftNote, false);
			cx += noteSpacing;
			cx += noteSpacing;
			canvas.fillMusicFontSymbols(cx, cy, noteScale, rightNote, false);
			cx += noteSpacing;
			if (rightNote[rightNote.length - 1] === MusicFontSymbol.MetAugmentationDot || rightNote[0] === MusicFontSymbol.MetNote8thUp) cx += noteSpacing;
			for (const b of beams) {
				switch (b) {
					case TextAlign.Left:
						canvas.fillRect(beamStartX, beamY, brokenBeamWidth, beamHeight);
						break;
					case TextAlign.Center:
						canvas.fillRect(beamStartX, beamY, beamEndX - beamStartX, beamHeight);
						break;
					case TextAlign.Right:
						canvas.fillRect(beamEndX - brokenBeamWidth, beamY, brokenBeamWidth, beamHeight);
						break;
				}
				beamY += beamHeight + beamSpacing;
			}
			return cx;
		}
	};
	//#endregion
	//#region src/rendering/effects/TripletFeelEffectInfo.ts
	/**
	* @internal
	*/
	var TripletFeelEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectTripletFeel;
		}
		get hideOnMultiTrack() {
			return true;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SinglePreBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.index === 0 && (beat.voice.bar.masterBar.index === 0 && beat.voice.bar.masterBar.tripletFeel !== TripletFeel.NoTripletFeel || beat.voice.bar.masterBar.index > 0 && beat.voice.bar.masterBar.tripletFeel !== beat.voice.bar.masterBar.previousMasterBar.tripletFeel);
		}
		createNewGlyph(_renderer, beat) {
			return new TripletFeelGlyph(beat.voice.bar.masterBar.tripletFeel);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/WahPedalGlyph.ts
	/**
	* @internal
	*/
	var WahPedalGlyph = class WahPedalGlyph extends MusicFontGlyph {
		constructor(wahPedal) {
			super(0, 0, 1, WahPedalGlyph._getSymbol(wahPedal));
			this.center = true;
		}
		static _getSymbol(wahPedal) {
			switch (wahPedal) {
				case WahPedal.Open: return MusicFontSymbol.GuitarOpenPedal;
				case WahPedal.Closed: return MusicFontSymbol.GuitarClosePedal;
			}
			return MusicFontSymbol.None;
		}
		paint(cx, cy, canvas) {
			super.paint(cx, cy + this.height, canvas);
		}
	};
	//#endregion
	//#region src/rendering/effects/WahPedalEffectInfo.ts
	/**
	* @internal
	*/
	var WahPedalEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectWahPedal;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.SingleOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.wahPedal !== WahPedal.None;
		}
		createNewGlyph(_renderer, beat) {
			return new WahPedalGlyph(beat.wahPedal);
		}
		canExpand(_from, _to) {
			return false;
		}
	};
	//#endregion
	//#region src/rendering/effects/WhammyBarEffectInfo.ts
	/**
	* @internal
	*/
	var WhammyBarEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectWhammyBar;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return false;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeat;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.hasWhammyBar;
		}
		createNewGlyph(_renderer, _beat) {
			return new LineRangedGlyph("w/bar", NotationElement.EffectWhammyBar);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/WideBeatVibratoEffectInfo.ts
	/**
	* @internal
	*/
	var WideBeatVibratoEffectInfo = class extends EffectInfo {
		get notationElement() {
			return NotationElement.EffectWideBeatVibrato;
		}
		get hideOnMultiTrack() {
			return false;
		}
		get canShareBand() {
			return true;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeatToEnd;
		}
		shouldCreateGlyph(_settings, beat) {
			return beat.vibrato === VibratoType.Wide;
		}
		createNewGlyph(_renderer, _beat) {
			return new BeatVibratoGlyph(0, 0, VibratoType.Wide);
		}
		canExpand(_from, _to) {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/effects/WideNoteVibratoEffectInfo.ts
	/**
	* @internal
	*/
	var WideNoteVibratoEffectInfo = class extends NoteEffectInfoBase {
		get notationElement() {
			return NotationElement.EffectWideNoteVibrato;
		}
		shouldCreateGlyphForNote(note) {
			return note.vibrato === VibratoType.Wide || note.isTieDestination && note.tieOrigin.vibrato === VibratoType.Wide;
		}
		get sizingMode() {
			return EffectBarGlyphSizing.GroupedOnBeatToEnd;
		}
		createNewGlyph(_renderer, _beat) {
			return new NoteVibratoGlyph(0, 0, VibratoType.Wide);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/RowGlyphContainer.ts
	/**
	* @internal
	*/
	var RowGlyphContainer = class extends GlyphGroup {
		_glyphWidth = 0;
		_align;
		constructor(x, y, align = TextAlign.Center) {
			super(x, y);
			this.glyphs = [];
			this._align = align;
		}
		doLayout() {
			const padding = this.renderer.smuflMetrics.rowContainerGap;
			const glyphWidth = this._glyphWidth - padding;
			let x = 0;
			switch (this._align) {
				case TextAlign.Left:
					x = 0;
					break;
				case TextAlign.Center:
					x = (this.width - glyphWidth) / 2;
					break;
				case TextAlign.Right:
					x = this.width - glyphWidth;
					break;
			}
			for (const glyph of this.glyphs) {
				glyph.x = x;
				x += glyph.width + padding;
			}
		}
		addGlyphToRow(glyph) {
			this.glyphs.push(glyph);
			this._glyphWidth += glyph.width + this.renderer.smuflMetrics.rowContainerGap;
			if (glyph.height > this.height) this.height = glyph.height;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/RowContainerGlyph.ts
	/**
	* @internal
	*/
	var RowContainerGlyph = class extends GlyphGroup {
		_rows = [];
		_align;
		constructor(x, y, align = TextAlign.Center) {
			super(x, y);
			this.height = 0;
			this.glyphs = [];
			this._align = align;
		}
		doLayout() {
			let x = 0;
			let y = 0;
			const gap = this.renderer.smuflMetrics.rowContainerGap;
			this._rows = [];
			let row = new RowGlyphContainer(x, y, this._align);
			row.renderer = this.renderer;
			row.width = this.width;
			for (const g of this.glyphs) {
				const endX = x + g.width + gap;
				if (endX < this.width) {
					row.addGlyphToRow(g);
					x = Math.ceil(endX);
				} else {
					if (!row.isEmpty) {
						row.doLayout();
						this._rows.push(row);
						y += row.height + gap;
					}
					x = 0;
					row = new RowGlyphContainer(x, y, this._align);
					row.renderer = this.renderer;
					row.width = this.width;
					row.addGlyphToRow(g);
					x += Math.ceil(g.width + gap);
				}
			}
			if (!row.isEmpty) {
				row.doLayout();
				this._rows.push(row);
				y += Math.ceil(row.height + this.renderer.smuflMetrics.rowContainerPadding);
			}
			this.height = y;
		}
		paint(cx, cy, canvas) {
			for (const row of this._rows) row.paint(cx + this.x, cy + this.y, canvas);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ChordDiagramContainerGlyph.ts
	/**
	* @internal
	*/
	var ChordDiagramContainerGlyph = class extends RowContainerGlyph {
		addChord(chord) {
			if (chord.strings.length > 0) {
				const chordDiagram = new ChordDiagramGlyph(0, 0, chord, NotationElement.ChordDiagrams);
				chordDiagram.renderer = this.renderer;
				chordDiagram.doLayout();
				this.glyphs.push(chordDiagram);
			}
		}
		paint(cx, cy, canvas) {
			if (this.glyphs.length > 0) {
				const _ = ElementStyleHelper.score(canvas, ScoreSubElement.ChordDiagramList, this.renderer.scoreRenderer.score);
				try {
					super.paint(cx, cy, canvas);
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TuningContainerGlyph.ts
	/**
	* @internal
	*/
	var TuningContainerGlyph = class extends RowContainerGlyph {
		constructor(x, y) {
			super(x, y, TextAlign.Left);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TuningGlyph.ts
	/**
	* @internal
	*/
	var TuningGlyph = class extends GlyphGroup {
		_tuning;
		_trackLabel;
		colorOverride;
		constructor(x, y, tuning, trackLabel) {
			super(x, y);
			this._tuning = tuning;
			this._trackLabel = trackLabel;
			this.glyphs = [];
		}
		doLayout() {
			if (this.glyphs.length > 0) return;
			this._createGlyphs(this._tuning);
			for (const g of this.glyphs) {
				g.renderer = this.renderer;
				g.doLayout();
			}
		}
		paint(cx, cy, canvas) {
			const c = canvas.color;
			if (this.colorOverride) canvas.color = this.colorOverride;
			super.paint(cx, cy, canvas);
			canvas.color = c;
		}
		_createGlyphs(tuning) {
			const res = this.renderer.resources;
			this.height = 0;
			if (this._trackLabel.length > 0) {
				const trackName = new TextGlyph(0, this.height, this._trackLabel, res.elementFonts.get(NotationElement.GuitarTuning), TextAlign.Left);
				trackName.renderer = this.renderer;
				trackName.doLayout();
				this.height += trackName.height;
				this.addGlyph(trackName);
			}
			if (tuning.name.length > 0) {
				const tuningName = new TextGlyph(0, this.height, tuning.name, res.elementFonts.get(NotationElement.GuitarTuning), TextAlign.Left);
				tuningName.renderer = this.renderer;
				tuningName.doLayout();
				this.height += tuningName.height;
				this.addGlyph(tuningName);
			}
			const circleScale = this.renderer.smuflMetrics.tuningGlyphCircleNumberScale;
			const circleHeight = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.GuitarString0) * circleScale;
			this.renderer.scoreRenderer.canvas.font = res.elementFonts.get(NotationElement.GuitarTuning);
			const stringColumnWidth = (circleHeight + this.renderer.scoreRenderer.canvas.measureText(" = Gb").width) * res.engravingSettings.tuningGlyphStringColumnScale;
			this.width = Math.max(this.renderer.scoreRenderer.canvas.measureText(this._trackLabel).width, Math.max(this.renderer.scoreRenderer.canvas.measureText(tuning.name).width, 2 * stringColumnWidth));
			if (!tuning.isStandard) {
				const stringsPerColumn = Math.ceil(tuning.tunings.length / 2) | 0;
				let currentX = 0;
				const topY = this.height + this.renderer.smuflMetrics.tuningGlyphStringRowPadding;
				let currentY = topY;
				for (let i = 0, j = tuning.tunings.length; i < j; i++) {
					const symbol = MusicFontSymbol.GuitarString0 + (i + 1);
					this.addGlyph(new MusicFontGlyph(currentX, currentY + circleHeight, circleScale, symbol));
					const str = ` = ${Tuning.getTextForTuning(tuning.tunings[i], false)}`;
					this.addGlyph(new TextGlyph(currentX + circleHeight, currentY + circleHeight / 2, str, res.elementFonts.get(NotationElement.GuitarTuning), TextAlign.Left, TextBaseline.Middle));
					currentY += circleHeight + this.renderer.smuflMetrics.tuningGlyphStringRowPadding;
					const bottomY = currentY;
					if (this.height < bottomY) this.height = bottomY;
					if (i === stringsPerColumn - 1) {
						currentY = topY;
						currentX += stringColumnWidth;
					}
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/layout/SlurRegistry.ts
	/**
	* This registry keeps track of which slurs and ties were started and needs completion.
	* Slurs might span multiple systems, and in such cases we need to create additional
	* slur/ties in the intermediate and end system.
	*
	* @internal
	*
	*/
	var SlurRegistry = class SlurRegistry {
		_staffLookup = /* @__PURE__ */ new Map();
		clear() {
			this._staffLookup.clear();
		}
		startMultiSystemSlur(startGlyph) {
			const staffId = SlurRegistry._staffId(startGlyph.renderer.staff);
			let container;
			if (!this._staffLookup.has(staffId)) {
				container = { startedSlurs: /* @__PURE__ */ new Map() };
				this._staffLookup.set(staffId, container);
			} else container = this._staffLookup.get(staffId);
			container.startedSlurs.set(startGlyph.slurEffectId, { startGlyph });
		}
		static _staffId(staff) {
			return `${staff.modelStaff.index}.${staff.modelStaff.track.index}.${staff.staffId}`;
		}
		completeMultiSystemSlur(endGlyph) {
			const staffId = SlurRegistry._staffId(endGlyph.renderer.staff);
			if (!this._staffLookup.has(staffId)) return;
			const container = this._staffLookup.get(staffId);
			if (container.startedSlurs.has(endGlyph.slurEffectId)) {
				const info = container.startedSlurs.get(endGlyph.slurEffectId);
				info.endGlyph = endGlyph;
				return info.startGlyph;
			}
		}
		*getAllContinuations(renderer) {
			const staffId = SlurRegistry._staffId(renderer.staff);
			if (!this._staffLookup.has(staffId) || renderer.index > 0) return;
			const container = this._staffLookup.get(staffId);
			for (const g of container.startedSlurs.values()) if (g.startGlyph.shouldCreateMultiSystemSlur(renderer)) yield g.startGlyph;
		}
	};
	//#endregion
	//#region src/rendering/staves/RenderStaff.ts
	/**
	* A Staff represents a single line within a StaffSystem.
	* It stores BarRenderer instances created from a given factory.
	* @internal
	*/
	var RenderStaff = class {
		_factory;
		_sharedLayoutData = /* @__PURE__ */ new Map();
		staffTrackGroup;
		system;
		barRenderers = [];
		x = 0;
		y = 0;
		height = 0;
		index = 0;
		staffIndex = 0;
		isVisible = false;
		_emptyBarCount = 0;
		get isFirstInSystem() {
			return this.system.firstVisibleStaff === this;
		}
		topEffectInfos = [];
		bottomEffectInfos = [];
		/**
		* This is the index of the track being rendered. This is not the index of the track within the model,
		* but the n-th track being rendered. It is the index of the {@link ScoreRenderer.tracks} array defining
		* which tracks should be rendered.
		* For single-track rendering this will always be zero.
		*/
		trackIndex = 0;
		modelStaff;
		get staffId() {
			return this._factory.staffId;
		}
		/**
		* This is the visual offset from top where the
		* Staff contents actually start. Used for grouping
		* using a accolade
		*/
		staffTop = 0;
		topPadding = 0;
		bottomPadding = 0;
		/**
		* This is the visual offset from top where the
		* Staff contents actually ends. Used for grouping
		* using a accolade
		*/
		staffBottom = 0;
		get contentTop() {
			return this.y + this.staffTop + this.topPadding + this.topOverflow;
		}
		get contentBottom() {
			return this.y + this.topPadding + this.topOverflow + this.staffBottom;
		}
		constructor(system, trackIndex, staff, factory) {
			this._factory = factory;
			this.trackIndex = trackIndex;
			this.modelStaff = staff;
			this.system = system;
			for (const b of factory.effectBands) {
				if (b.shouldCreate && !b.shouldCreate(staff)) continue;
				switch (b.mode) {
					case EffectBandMode.OwnedTop:
					case EffectBandMode.SharedTop:
						this.topEffectInfos.push(b);
						break;
					case EffectBandMode.OwnedBottom:
					case EffectBandMode.SharedBottom:
						this.bottomEffectInfos.push(b);
						break;
				}
			}
			this._updateVisibility();
		}
		getSharedLayoutData(key, def) {
			if (this._sharedLayoutData.has(key)) return this._sharedLayoutData.get(key);
			return def;
		}
		setSharedLayoutData(key, def) {
			this._sharedLayoutData.set(key, def);
		}
		registerStaffTop(offset) {
			if (offset > this.staffTop) this.staffTop = offset;
		}
		registerStaffBottom(offset) {
			if (offset > this.staffBottom) this.staffBottom = offset;
		}
		addBarRenderer(renderer) {
			renderer.staff = this;
			renderer.index = this.barRenderers.length;
			renderer.reLayout();
			this.barRenderers.push(renderer);
			this.system.layout.registerBarRenderer(this.staffId, renderer);
			if (renderer.bar.isEmpty || renderer.bar.isRestOnly) this._emptyBarCount++;
			this._updateVisibility();
		}
		_updateVisibility() {
			const stylesheet = this.modelStaff.track.score.stylesheet;
			if (stylesheet.hideEmptyStaves && (stylesheet.hideEmptyStavesInFirstSystem || this.system.index > 0)) this.isVisible = this._emptyBarCount < this.barRenderers.length;
			else this.isVisible = true;
		}
		addBar(bar, layoutingInfo, additionalMultiBarsRestBars) {
			const renderer = this._factory.create(this.system.layout.renderer, bar);
			renderer.topEffects.infos = this.topEffectInfos;
			renderer.bottomEffects.infos = this.bottomEffectInfos;
			renderer.additionalMultiRestBars = additionalMultiBarsRestBars;
			renderer.staff = this;
			renderer.index = this.barRenderers.length;
			renderer.layoutingInfo = layoutingInfo;
			renderer.doLayout();
			this.barRenderers.push(renderer);
			this.system.layout.registerBarRenderer(this.staffId, renderer);
			if (bar.isEmpty || bar.isRestOnly) this._emptyBarCount++;
			this._updateVisibility();
		}
		revertLastBar() {
			this.resetSharedLayoutData();
			const lastBar = this.barRenderers[this.barRenderers.length - 1];
			this.barRenderers.splice(this.barRenderers.length - 1, 1);
			this.topOverflow = 0;
			this.bottomOverflow = 0;
			for (const r of this.barRenderers) r.afterStaffBarReverted();
			if (lastBar.bar.isEmpty || lastBar.bar.isRestOnly) this._emptyBarCount--;
			this._updateVisibility();
			return lastBar;
		}
		resetSharedLayoutData() {
			this._sharedLayoutData.clear();
		}
		topOverflow = 0;
		registerOverflowTop(overflow) {
			if (overflow > this.topOverflow) this.topOverflow = overflow;
		}
		bottomOverflow = 0;
		registerOverflowBottom(overflow) {
			if (overflow > this.bottomOverflow) this.bottomOverflow = overflow;
		}
		/**
		* Performs an early calculation of the expected staff height for the size calculation in the
		* accolade (e.g. for braces). This typically happens after the first bar renderers were created
		* and we can do an early placement of the render staffs.
		*/
		calculateHeightForAccolade() {
			this._applyStaffPaddings();
			this.height = this.barRenderers.length > 0 ? this.barRenderers[0].height : 0;
			if (this.height > 0) this.height += Math.ceil(this.topPadding + this.topOverflow + this.bottomOverflow + this.bottomPadding);
		}
		_applyStaffPaddings() {
			const isFirst = this.index === 0;
			const isLast = this.index === this.system.staves.length - 1;
			const settings = this.system.layout.renderer.settings.display;
			this.topPadding = isFirst ? settings.firstNotationStaffPaddingTop : settings.notationStaffPaddingTop;
			this.bottomPadding = isLast ? settings.lastNotationStaffPaddingBottom : settings.notationStaffPaddingBottom;
		}
		finalizeStaff() {
			this._applyStaffPaddings();
			this.height = 0;
			let needsSecondPass = false;
			let topOverflow = this.topOverflow;
			for (const renderer of this.barRenderers) {
				renderer.registerMultiSystemSlurs(this.system.layout.slurRegistry.getAllContinuations(renderer));
				if (renderer.finalizeRenderer()) needsSecondPass = true;
				this.height = Math.max(this.height, renderer.height);
			}
			if (needsSecondPass) {
				topOverflow = this.topOverflow;
				for (const renderer of this.barRenderers) renderer.y = this.topPadding + topOverflow;
				for (const renderer of this.barRenderers) renderer.finalizeRenderer();
			}
			if (this.height > 0) this.height += this.topPadding + topOverflow + this.bottomOverflow + this.bottomPadding;
			this.height = Math.ceil(this.height);
			this._updateVisibility();
		}
		paint(cx, cy, canvas, startIndex, count) {
			if (this.height === 0 || count === 0) return;
			for (let i = startIndex, j = Math.min(startIndex + count, this.barRenderers.length); i < j; i++) this.barRenderers[i].paint(cx + this.x, cy + this.y, canvas);
		}
	};
	//#endregion
	//#region src/rendering/staves/Spring.ts
	/**
	* @internal
	*/
	var Spring = class {
		timePosition = 0;
		longestDuration = 0;
		smallestDuration = 0;
		force = 0;
		springConstant = 0;
		get springWidth() {
			return this.preSpringWidth + this.postSpringWidth;
		}
		preBeatWidth = 0;
		graceBeatWidth = 0;
		postSpringWidth = 0;
		get preSpringWidth() {
			return this.preBeatWidth + this.graceBeatWidth;
		}
		allDurations = /* @__PURE__ */ new Set();
	};
	//#endregion
	//#region src/rendering/staves/BarLayoutingInfo.ts
	/**
	* This public class stores size information about a stave.
	* It is used by the layout engine to collect the sizes of score parts
	* to align the parts across multiple staves.
	* @internal
	*/
	var BarLayoutingInfo = class BarLayoutingInfo {
		static _defaultMinDuration = 30;
		static _defaultMinDurationWidth = 7;
		_timeSortedSprings = [];
		_minTime = -1;
		_onTimePositionsForce = 0;
		_onTimePositions = /* @__PURE__ */ new Map();
		_incompleteGraceRodsWidth = 0;
		_beatSizes = /* @__PURE__ */ new Map();
		_minDuration = BarLayoutingInfo._defaultMinDuration;
		/**
		* an internal version number that increments whenever a change was made.
		*/
		version = 0;
		preBeatSize = 0;
		postBeatSize = 0;
		minStretchForce = 0;
		totalSpringConstant = 0;
		/**
		* The smallest note duration encountered within this bar's springs, used as the reference in
		* the Gourlay stretch formula. Read by the owning {@link StaffSystem} so that the system can
		* aggregate a shared minimum across all bars and trigger a reconcile if an added bar introduces
		* a shorter duration than previously seen.
		*/
		get localMinDuration() {
			return this._minDuration;
		}
		/**
		* The minimum-duration reference against which the spring constants currently held by this info
		* were computed. Set by {@link finish} and {@link recomputeSpringConstants}. The owning
		* StaffSystem compares this against its system-wide minimum to decide whether spring constants
		* need re-derivation.
		*/
		computedWithMinDuration = 0;
		_updateMinStretchForce(force) {
			if (this.minStretchForce < force) this.minStretchForce = force;
		}
		getBeatSizes(beat) {
			const key = beat.absoluteDisplayStart;
			if (this._beatSizes.has(key)) return this._beatSizes.get(key);
		}
		setBeatSizes(beat, sizes) {
			const key = beat.absoluteDisplayStart;
			if (this._beatSizes.has(key)) {
				const current = this._beatSizes.get(key);
				if (current.onBeatSize < sizes.onBeatSize) current.onBeatSize = sizes.onBeatSize;
				if (current.preBeatSize < sizes.preBeatSize) current.preBeatSize = sizes.preBeatSize;
			} else this._beatSizes.set(key, sizes);
		}
		getPreBeatSize(beat) {
			if (beat.graceType !== GraceType.None) {
				const groupId = beat.graceGroup.id;
				return this.allGraceRods.get(groupId)[beat.graceIndex].preBeatWidth;
			}
			const start = beat.absoluteDisplayStart;
			if (!this.springs.has(start)) return 0;
			return this.springs.get(start).preBeatWidth;
		}
		getPostBeatSize(beat) {
			if (beat.graceType !== GraceType.None) {
				const groupId = beat.graceGroup.id;
				return this.allGraceRods.get(groupId)[beat.graceIndex].postSpringWidth;
			}
			const start = beat.absoluteDisplayStart;
			if (!this.springs.has(start)) return 0;
			return this.springs.get(start).postSpringWidth;
		}
		incompleteGraceRods = /* @__PURE__ */ new Map();
		allGraceRods = /* @__PURE__ */ new Map();
		springs = /* @__PURE__ */ new Map();
		addSpring(start, duration, graceBeatWidth, preBeatWidth, postSpringSize) {
			this.version++;
			let spring;
			if (!this.springs.has(start)) {
				spring = new Spring();
				spring.timePosition = start;
				spring.allDurations.add(duration);
				if (this._timeSortedSprings.length > 0) {
					let smallestDuration = duration;
					const previousSpring = this._timeSortedSprings[this._timeSortedSprings.length - 1];
					for (const prevDuration of previousSpring.allDurations) if (previousSpring.timePosition + prevDuration >= start && prevDuration < smallestDuration) smallestDuration = prevDuration;
					if (duration < this._minDuration) this._minDuration = duration;
				}
				spring.longestDuration = duration;
				spring.postSpringWidth = postSpringSize;
				spring.graceBeatWidth = graceBeatWidth;
				spring.preBeatWidth = preBeatWidth;
				this.springs.set(start, spring);
				const timeSorted = this._timeSortedSprings;
				let insertPos = timeSorted.length - 1;
				while (insertPos > 0 && timeSorted[insertPos].timePosition > start) insertPos--;
				this._timeSortedSprings.splice(insertPos + 1, 0, spring);
			} else {
				spring = this.springs.get(start);
				if (spring.postSpringWidth < postSpringSize) spring.postSpringWidth = postSpringSize;
				if (spring.graceBeatWidth < graceBeatWidth) spring.graceBeatWidth = graceBeatWidth;
				if (spring.preBeatWidth < preBeatWidth) spring.preBeatWidth = preBeatWidth;
				if (duration < spring.smallestDuration) spring.smallestDuration = duration;
				if (duration > spring.longestDuration) spring.longestDuration = duration;
				spring.allDurations.add(duration);
			}
			if (this._minTime === -1 || this._minTime > start) this._minTime = start;
			return spring;
		}
		addBeatSpring(beat, preBeatSize, postBeatSize) {
			const start = beat.absoluteDisplayStart;
			if (beat.graceType !== GraceType.None) {
				const groupId = beat.graceGroup.id;
				if (!this.allGraceRods.has(groupId)) this.allGraceRods.set(groupId, new Array(beat.graceGroup.beats.length));
				if (!beat.graceGroup.isComplete && !this.incompleteGraceRods.has(groupId)) this.incompleteGraceRods.set(groupId, new Array(beat.graceGroup.beats.length));
				const existingSpring = this.allGraceRods.get(groupId)[beat.graceIndex];
				if (existingSpring) {
					if (existingSpring.postSpringWidth < postBeatSize) existingSpring.postSpringWidth = postBeatSize;
					if (existingSpring.preBeatWidth < preBeatSize) existingSpring.preBeatWidth = preBeatSize;
				} else {
					const graceSpring = new Spring();
					graceSpring.timePosition = start;
					graceSpring.postSpringWidth = postBeatSize;
					graceSpring.preBeatWidth = preBeatSize;
					if (!beat.graceGroup.isComplete) this.incompleteGraceRods.get(groupId)[beat.graceIndex] = graceSpring;
					this.allGraceRods.get(groupId)[beat.graceIndex] = graceSpring;
				}
			} else {
				let graceBeatSize = 0;
				if (beat.graceGroup && this.allGraceRods.has(beat.graceGroup.id)) for (const graceBeat of this.allGraceRods.get(beat.graceGroup.id)) graceBeatSize += graceBeat.springWidth;
				this.addSpring(start, beat.displayDuration, graceBeatSize, preBeatSize, postBeatSize);
			}
		}
		finish() {
			for (const [_, s] of this.allGraceRods) {
				let x = 0;
				for (const sp of s) {
					x += sp.preBeatWidth;
					sp.graceBeatWidth = x;
					x += sp.postSpringWidth;
				}
			}
			this._incompleteGraceRodsWidth = 0;
			for (const s of this.incompleteGraceRods.values()) for (const sp of s) this._incompleteGraceRodsWidth += sp.preBeatWidth + sp.postSpringWidth;
			this._calculateSpringConstants(this._minDuration);
			this.computedWithMinDuration = this._minDuration;
			this.version++;
		}
		/**
		* Re-derives the spring constants (and {@link minStretchForce} / {@link totalSpringConstant})
		* using a caller-supplied minimum-duration reference rather than this bar's local minimum.
		*
		* Called by {@link StaffSystem.reconcileMinDurationIfDirty} when a bar added later to the
		* system introduced a shorter note than previously seen, invalidating this bar's spring
		* constants. Grace-rod data is not recomputed — it is independent of the minimum-duration
		* reference. The internal {@link version} is bumped so downstream consumers (e.g.
		* {@link BarRendererBase.applyLayoutingInfo}) pick up the refreshed positions.
		*/
		recomputeSpringConstants(minDuration) {
			this._calculateSpringConstants(minDuration);
			this.computedWithMinDuration = minDuration;
			this.version++;
		}
		_calculateSpringConstants(minDuration) {
			let totalSpringConstant = 0;
			const sortedSprings = this._timeSortedSprings;
			if (sortedSprings.length === 0) {
				this.totalSpringConstant = -1;
				this.minStretchForce = -1;
				return;
			}
			for (let i = 0; i < sortedSprings.length; i++) {
				const currentSpring = sortedSprings[i];
				let duration = 0;
				if (i === sortedSprings.length - 1) duration = currentSpring.longestDuration;
				else {
					const nextSpring = sortedSprings[i + 1];
					duration = Math.abs(nextSpring.timePosition - currentSpring.timePosition);
				}
				currentSpring.springConstant = this._calculateSpringConstant(currentSpring, duration, minDuration);
				totalSpringConstant += 1 / currentSpring.springConstant;
			}
			this.totalSpringConstant = 1 / totalSpringConstant;
			this.minStretchForce = 0;
			for (let i = 0; i < sortedSprings.length; i++) {
				const currentSpring = sortedSprings[i];
				let requiredSpace = 0;
				if (i === sortedSprings.length - 1) requiredSpace = currentSpring.postSpringWidth;
				else {
					const nextSpring = sortedSprings[i + 1];
					requiredSpace = currentSpring.postSpringWidth + nextSpring.preSpringWidth;
				}
				if (i === 0) requiredSpace += currentSpring.preSpringWidth;
				const requiredSpaceForce = requiredSpace * currentSpring.springConstant;
				this._updateMinStretchForce(requiredSpaceForce);
			}
		}
		height = 0;
		paint(_cx, _cy, _canvas) {}
		_calculateSpringConstant(spring, duration, minDuration) {
			if (duration <= 0) duration = MidiUtils.toTicks(Duration.TwoHundredFiftySixth);
			if (spring.smallestDuration === 0) spring.smallestDuration = duration;
			const smallestDuration = spring.smallestDuration;
			const minDurationWidth = BarLayoutingInfo._defaultMinDurationWidth;
			const phi = 1 + .85 * Math.log2(duration / minDuration);
			return smallestDuration / duration * (1 / (phi * minDurationWidth));
		}
		spaceToForce(space) {
			if (this.totalSpringConstant !== -1) {
				if (this._timeSortedSprings.length > 0) space -= this._timeSortedSprings[0].preSpringWidth;
				space -= this._incompleteGraceRodsWidth;
				return Math.max(space, 0) * this.totalSpringConstant;
			}
			return -1;
		}
		calculateVoiceWidth(force) {
			let width = 0;
			if (this.totalSpringConstant !== -1) width = this._calculateWidth(force, this.totalSpringConstant);
			if (this._timeSortedSprings.length > 0) width += this._timeSortedSprings[0].preSpringWidth;
			width += this._incompleteGraceRodsWidth;
			return width;
		}
		_calculateWidth(force, springConstant) {
			return force / springConstant;
		}
		buildOnTimePositions(force) {
			if (this.totalSpringConstant === -1) return /* @__PURE__ */ new Map();
			if (ModelUtils.isAlmostEqualTo(this._onTimePositionsForce, force) && this._onTimePositions) return this._onTimePositions;
			this._onTimePositionsForce = force;
			const positions = /* @__PURE__ */ new Map();
			this._onTimePositions = positions;
			const sortedSprings = this._timeSortedSprings;
			if (sortedSprings.length === 0) return positions;
			let springX = sortedSprings[0].preSpringWidth;
			for (let i = 0; i < sortedSprings.length; i++) {
				positions.set(sortedSprings[i].timePosition, springX);
				springX += this._calculateWidth(force, sortedSprings[i].springConstant);
			}
			return positions;
		}
	};
	//#endregion
	//#region src/rendering/staves/MasterBarsRenderers.ts
	/**
	* This container represents a single column of bar renderers independent from any staves.
	* This container can be used to reorganize renderers into a new staves.
	* @internal
	*/
	var MasterBarsRenderers = class {
		width = 0;
		isLinkedToPrevious = false;
		canWrap = true;
		masterBar;
		additionalMultiBarRestIndexes = null;
		/**
		* Max fixed overhead (prefix + postfix glyph width) across all staves of this bar.
		* Used by the layout-mode horizontal scaling pass to carve out the fixed-overhead bucket
		* before distributing staff width across bars.
		*/
		maxFixedOverhead = 0;
		/**
		* Max natural content width (computedWidth - fixedOverhead) across all staves of this bar.
		* Used as the bar weight when the layout ignores {@link MasterBar.displayScale} (e.g.
		* Page layout with `SystemsLayoutMode.Automatic`).
		*/
		maxContentWidth = 0;
		get lastMasterBarIndex() {
			if (this.additionalMultiBarRestIndexes) return this.additionalMultiBarRestIndexes[this.additionalMultiBarRestIndexes.length - 1];
			return this.masterBar.index;
		}
		renderers = [];
		layoutingInfo;
	};
	//#endregion
	//#region src/rendering/staves/StaffTrackGroup.ts
	/**
	* Represents the group of rendered staves belonging to an individual track.
	* This includes staves like effects, notation representations (numbered, tabs,..) and multiple
	* staffs (grand staff).
	* @internal
	*/
	var StaffTrackGroup = class {
		track;
		staffSystem;
		staves = [];
		firstVisibleStaff;
		lastVisibleStaff;
		bracket = null;
		constructor(staffSystem, track) {
			this.staffSystem = staffSystem;
			this.track = track;
		}
		addStaff(staff) {
			this.staves.push(staff);
		}
	};
	//#endregion
	//#region src/rendering/staves/StaffSystem.ts
	/**
	* @internal
	*/
	var SystemBracket = class {
		_system;
		firstStaffInBracket;
		lastStaffInBracket;
		firstVisibleStaffInBracket;
		lastVisibleStaffInBracket;
		drawAsBrace = false;
		braceScale = 1;
		width = 0;
		index = 0;
		canPaint = false;
		constructor(system) {
			this._system = system;
		}
		updateCanPaint() {
			let firstVisibleStaff = void 0;
			let lastVisibleStaff = void 0;
			for (let i = this.firstStaffInBracket.index; i <= this.lastStaffInBracket.index; i++) {
				const staff = this._system.allStaves[i];
				if (staff.isVisible) {
					if (!firstVisibleStaff) firstVisibleStaff = staff;
					lastVisibleStaff = staff;
				}
			}
			this.firstVisibleStaffInBracket = firstVisibleStaff;
			this.lastVisibleStaffInBracket = lastVisibleStaff;
			if (!firstVisibleStaff || !lastVisibleStaff) {
				this.canPaint = false;
				return;
			}
			if (!this._system.layout.renderer.score.stylesheet.showSingleStaffBrackets && firstVisibleStaff === lastVisibleStaff) {
				this.canPaint = false;
				return;
			}
			this.canPaint = true;
		}
		finalizeBracket(smuflMetrics) {
			if (!this.canPaint) {
				this.width = 0;
				return;
			}
			const bravuraBraceHeightAtMusicFontSize = smuflMetrics.glyphHeights.get(MusicFontSymbol.Brace);
			const bravuraBraceWidthAtMusicFontSize = smuflMetrics.glyphWidths.get(MusicFontSymbol.Brace);
			if (this.drawAsBrace) this.width = bravuraBraceWidthAtMusicFontSize;
			else this.width = smuflMetrics.bracketThickness;
			if (!this.drawAsBrace) return;
			const firstStart = this.firstVisibleStaffInBracket.contentTop;
			const requiredScaleForBracket = (this.lastVisibleStaffInBracket.contentBottom - firstStart) / bravuraBraceHeightAtMusicFontSize;
			this.braceScale = requiredScaleForBracket;
			this.width = bravuraBraceWidthAtMusicFontSize * this.braceScale;
		}
	};
	/**
	* @internal
	*/
	var SingleTrackSystemBracket = class SingleTrackSystemBracket extends SystemBracket {
		track;
		constructor(system, track) {
			super(system);
			this.track = track;
			this.drawAsBrace = SingleTrackSystemBracket.isTrackDrawAsBrace(track);
		}
		includesStaff(r) {
			return r.modelStaff.track === this.track;
		}
		static isTrackDrawAsBrace(track) {
			return track.staves.filter((s) => s.showStandardNotation).length > 1;
		}
	};
	/**
	* @internal
	*/
	var SimilarInstrumentSystemBracket = class extends SingleTrackSystemBracket {
		includesStaff(r) {
			if (r.modelStaff.track === this.track) return true;
			if (this.drawAsBrace) return false;
			return this.track.playbackInfo.program === r.modelStaff.track.playbackInfo.program;
		}
	};
	/**
	* A StaffSystem consists of a list of different staves and groups
	* them using an accolade.
	* @internal
	*/
	var StaffSystem = class {
		_accoladeSpacingCalculated = false;
		_brackets = [];
		_staffToBracket = /* @__PURE__ */ new Map();
		_contentHeight = 0;
		_hasSystemSeparator = false;
		x = 0;
		y = 0;
		index = 0;
		/**
		* The width of the whole accolade inclusive text and bar.
		*/
		accoladeWidth = 0;
		/**
		* Indicates whether this line is full or not. If the line is full the
		* bars can be aligned to the maximum width. If the line is not full
		* the bars will not get stretched.
		*/
		isFull = false;
		/**
		* The current width of the system to which the content is scaled.
		* Includes accolade (tracknames, brackets etc) and the content.
		*
		* Used to determine the final size needed for rendering.
		*/
		width = 0;
		/**
		* The minimum/default width to which the system was sized
		* when performing the layout. This is the size of the system if no
		* fitting/resizing is performed.
		*
		* Includes accolade (tracknames, brackets etc) and the content.
		*
		* Used to perform a resizing/refitting of the system.
		*/
		computedWidth = 0;
		/**
		* This is the simple sum of all display scales of the bars in this system.
		* This value is mainly used in the parchment style layout for correct scaling of the bars.
		*/
		totalBarDisplayScale = 0;
		/**
		* Sum of per-bar {@link MasterBarsRenderers.maxFixedOverhead} across the system. The layout-mode
		* horizontal scaling pass subtracts this from the available staff width before distributing the
		* remainder across bars.
		*/
		totalFixedOverhead = 0;
		/**
		* Sum of per-bar {@link MasterBarsRenderers.maxContentWidth} across the system. Used as the
		* denominator when distributing staff width in modes that weight bars by natural content width
		* (Page layout with `SystemsLayoutMode.Automatic`).
		*/
		totalContentWidth = 0;
		/**
		* Shortest note duration (in ticks) across every bar that has been added to this system, used
		* as the common reference in the Gourlay stretch formula so that rhythmically-equivalent beats
		* in different bars of the same system align column-wise.
		*
		* `-1` means "no bar added yet". The value only moves downward during system assembly; when a
		* new bar introduces a shorter minimum, {@link isMinDurationDirty} is set so that
		* {@link reconcileMinDurationIfDirty} can re-derive spring constants on the previously-added
		* bars before layout distribution runs.
		*/
		minDuration = -1;
		/**
		* Set when a bar added to this system introduced a shorter {@link minDuration} than previously
		* seen, leaving earlier bars' spring constants stale. Consumed by
		* {@link reconcileMinDurationIfDirty} which is called from `VerticalLayoutBase._fitSystem`
		* once the system is fully assembled.
		*/
		isMinDurationDirty = false;
		/**
		* Whether this system coordinates a shared minimum-duration reference across its bars for the
		* Gourlay stretch formula. Defaults to `true` for page-style and parchment layouts where bars
		* of a system fight for a common staff width. Set to `false` for horizontal layouts where each
		* bar is sized independently (by `bar.displayWidth` or its intrinsic width) and there is no
		* column-alignment concern - each bar keeps its local minimum so pre-existing rendering is
		* preserved.
		*/
		shareMinDurationAcrossBars = true;
		isLast = false;
		masterBarsRenderers = [];
		staves = [];
		layout;
		topPadding;
		bottomPadding;
		allStaves = [];
		firstVisibleStaff;
		constructor(layout) {
			this.layout = layout;
			this.topPadding = layout.renderer.settings.display.systemPaddingTop;
			this.bottomPadding = layout.renderer.settings.display.systemPaddingBottom;
		}
		get firstBarIndex() {
			return this.masterBarsRenderers[0].masterBar.index;
		}
		get lastBarIndex() {
			return this.masterBarsRenderers[this.masterBarsRenderers.length - 1].lastMasterBarIndex;
		}
		addMasterBarRenderers(tracks, renderers) {
			if (tracks.length === 0) return null;
			this.masterBarsRenderers.push(renderers);
			renderers.layoutingInfo.preBeatSize = 0;
			let src = 0;
			let firstVisibleStaff = void 0;
			let anyStaffVisible = false;
			for (const g of this.staves) {
				let firstVisibleStaffInGroup = void 0;
				let lastVisibleStaffInGroup = void 0;
				for (const s of g.staves) {
					const renderer = renderers.renderers[src++];
					s.addBarRenderer(renderer);
					if (s.isVisible) {
						anyStaffVisible = true;
						if (!firstVisibleStaffInGroup) firstVisibleStaffInGroup = s;
						if (!firstVisibleStaff) firstVisibleStaff = s;
						lastVisibleStaffInGroup = s;
					}
				}
				g.firstVisibleStaff = firstVisibleStaffInGroup;
				g.lastVisibleStaff = lastVisibleStaffInGroup;
				if (!firstVisibleStaff) firstVisibleStaff = firstVisibleStaffInGroup;
			}
			if (!anyStaffVisible) {
				const group = this.staves[0];
				const firstStaff = group.staves[0];
				firstStaff.isVisible = true;
				group.firstVisibleStaff = firstStaff;
				group.lastVisibleStaff = firstStaff;
				firstVisibleStaff = firstStaff;
			}
			this.firstVisibleStaff = firstVisibleStaff;
			this._calculateAccoladeSpacing(tracks);
			this._trackSystemMinDuration(renderers.layoutingInfo);
			this._applyLayoutAndUpdateWidth();
			return renderers;
		}
		addBars(tracks, barIndex, additionalMultiBarRestIndexes) {
			const result = new MasterBarsRenderers();
			result.additionalMultiBarRestIndexes = additionalMultiBarRestIndexes;
			result.layoutingInfo = new BarLayoutingInfo();
			result.masterBar = tracks[0].score.masterBars[barIndex];
			this.masterBarsRenderers.push(result);
			let firstVisibleStaff = void 0;
			let anyStaffVisible = false;
			const barLayoutingInfo = result.layoutingInfo;
			for (const g of this.staves) {
				let firstVisibleStaffInGroup = void 0;
				let lastVisibleStaffInGroup = void 0;
				for (const s of g.staves) {
					const bar = g.track.staves[s.modelStaff.index].bars[barIndex];
					const additionalMultiBarsRestBars = additionalMultiBarRestIndexes == null ? null : additionalMultiBarRestIndexes.map((b) => g.track.staves[s.modelStaff.index].bars[b]);
					s.addBar(bar, barLayoutingInfo, additionalMultiBarsRestBars);
					if (s.isVisible) {
						anyStaffVisible = true;
						if (!firstVisibleStaffInGroup) firstVisibleStaffInGroup = s;
						lastVisibleStaffInGroup = s;
					}
					const renderer = s.barRenderers[s.barRenderers.length - 1];
					result.renderers.push(renderer);
					if (renderer.isLinkedToPrevious) result.isLinkedToPrevious = true;
					if (!renderer.canWrap) result.canWrap = false;
				}
				g.firstVisibleStaff = firstVisibleStaffInGroup;
				g.lastVisibleStaff = lastVisibleStaffInGroup;
				if (!firstVisibleStaff) firstVisibleStaff = firstVisibleStaffInGroup;
			}
			if (!anyStaffVisible) {
				const group = this.staves[0];
				const firstStaff = group.staves[0];
				firstStaff.isVisible = true;
				group.firstVisibleStaff = firstStaff;
				group.lastVisibleStaff = firstStaff;
				firstVisibleStaff = firstStaff;
			}
			this.firstVisibleStaff = firstVisibleStaff;
			this._calculateAccoladeSpacing(tracks);
			barLayoutingInfo.finish();
			this._trackSystemMinDuration(barLayoutingInfo);
			result.width = this._applyLayoutAndUpdateWidth();
			return result;
		}
		/**
		* Updates {@link minDuration} and {@link isMinDurationDirty} when a bar is added, and brings
		* the just-added bar's {@link BarLayoutingInfo} in line with the current system minimum if the
		* system already saw a shorter reference. The bulk reconcile over previously-added bars is
		* deferred to {@link reconcileMinDurationIfDirty} (called from `_fitSystem`) to avoid
		* re-iterating the system every time a bar is appended.
		*/
		_trackSystemMinDuration(info) {
			if (!this.shareMinDurationAcrossBars) return;
			const localMin = info.localMinDuration;
			if (this.minDuration === -1 || localMin < this.minDuration) {
				if (this.masterBarsRenderers.length > 1 && localMin !== this.minDuration) this.isMinDurationDirty = true;
				this.minDuration = localMin;
			}
			if (info.computedWithMinDuration > this.minDuration) info.recomputeSpringConstants(this.minDuration);
		}
		/**
		* Re-derives spring constants on bars whose {@link BarLayoutingInfo.computedWithMinDuration}
		* is out of sync with the current {@link minDuration}, and rebuilds the cached system totals
		* (widths, {@link totalFixedOverhead}, {@link totalContentWidth}) from the refreshed bar
		* widths. Called from `VerticalLayoutBase._fitSystem` after the system is fully assembled and
		* before distribution runs. No-op when {@link isMinDurationDirty} is false.
		*/
		reconcileMinDurationIfDirty() {
			if (!this.isMinDurationDirty) return;
			let systemWidth = this.accoladeWidth;
			let totalFixedOverhead = 0;
			let totalContentWidth = 0;
			for (const mb of this.masterBarsRenderers) {
				if (mb.layoutingInfo.computedWithMinDuration > this.minDuration) mb.layoutingInfo.recomputeSpringConstants(this.minDuration);
				let maxPrefix = 0;
				let maxContent = 0;
				let realWidth = 0;
				for (const r of mb.renderers) {
					r.applyLayoutingInfo();
					if (r.computedWidth > realWidth) realWidth = r.computedWidth;
					const overhead = r.fixedOverhead;
					if (overhead > maxPrefix) maxPrefix = overhead;
					const content = Math.max(0, r.computedWidth - overhead);
					if (content > maxContent) maxContent = content;
				}
				mb.maxFixedOverhead = maxPrefix;
				mb.maxContentWidth = maxContent;
				mb.width = realWidth;
				systemWidth += realWidth;
				totalFixedOverhead += maxPrefix;
				totalContentWidth += maxContent;
			}
			this.width = systemWidth;
			this.computedWidth = systemWidth;
			this.totalFixedOverhead = totalFixedOverhead;
			this.totalContentWidth = totalContentWidth;
			this.isMinDurationDirty = false;
		}
		getBarDisplayScale(renderer) {
			return this.staves.length > 1 ? renderer.bar.masterBar.displayScale : renderer.bar.displayScale;
		}
		revertLastBar() {
			if (this.masterBarsRenderers.length > 1) {
				const toRemove = this.masterBarsRenderers[this.masterBarsRenderers.length - 1];
				this.masterBarsRenderers.splice(this.masterBarsRenderers.length - 1, 1);
				let width = 0;
				let barDisplayScale = 0;
				let firstVisibleStaff = void 0;
				for (const g of this.staves) {
					let firstVisibleStaffInGroup = void 0;
					let lastVisibleStaffInGroup = void 0;
					for (const s of g.staves) {
						const lastBar = s.revertLastBar();
						const computedWidth = lastBar.computedWidth;
						if (computedWidth > width) width = computedWidth;
						lastBar.afterReverted();
						barDisplayScale = this.getBarDisplayScale(lastBar);
						if (s.isVisible) {
							if (!firstVisibleStaffInGroup) firstVisibleStaffInGroup = s;
							lastVisibleStaffInGroup = s;
						}
					}
					g.firstVisibleStaff = firstVisibleStaffInGroup;
					g.lastVisibleStaff = lastVisibleStaffInGroup;
					if (!firstVisibleStaff) firstVisibleStaff = firstVisibleStaffInGroup;
				}
				this.firstVisibleStaff = firstVisibleStaff;
				this.width -= width;
				this.computedWidth -= width;
				this.totalBarDisplayScale -= barDisplayScale;
				this.totalFixedOverhead -= toRemove.maxFixedOverhead;
				this.totalContentWidth -= toRemove.maxContentWidth;
				return toRemove;
			}
			return null;
		}
		_applyLayoutAndUpdateWidth() {
			let realWidth = 0;
			let maxFixedOverhead = 0;
			let maxContentWidth = 0;
			let barDisplayScale = 0;
			for (const s of this.allStaves) {
				const last = s.barRenderers[s.barRenderers.length - 1];
				last.applyLayoutingInfo();
				barDisplayScale = this.getBarDisplayScale(last);
				if (last.computedWidth > realWidth) realWidth = last.computedWidth;
				const overhead = last.fixedOverhead;
				if (overhead > maxFixedOverhead) maxFixedOverhead = overhead;
				const content = Math.max(0, last.computedWidth - overhead);
				if (content > maxContentWidth) maxContentWidth = content;
			}
			const renderers = this.masterBarsRenderers[this.masterBarsRenderers.length - 1];
			renderers.maxFixedOverhead = maxFixedOverhead;
			renderers.maxContentWidth = maxContentWidth;
			this.totalBarDisplayScale += barDisplayScale;
			this.totalFixedOverhead += maxFixedOverhead;
			this.totalContentWidth += maxContentWidth;
			this.width += realWidth;
			this.computedWidth += realWidth;
			return realWidth;
		}
		_calculateAccoladeSpacing(tracks) {
			const settings = this.layout.renderer.settings;
			if (!this._accoladeSpacingCalculated) {
				this._accoladeSpacingCalculated = true;
				this.accoladeWidth = 0;
				const stylesheet = this.layout.renderer.score.stylesheet;
				if (this.layout.renderer.settings.notation.isNotationElementVisible(NotationElement.TrackNames)) {
					const trackNamePolicy = this.layout.renderer.tracks.length === 1 ? stylesheet.singleTrackTrackNamePolicy : stylesheet.multiTrackTrackNamePolicy;
					const trackNameMode = this.index === 0 ? stylesheet.firstSystemTrackNameMode : stylesheet.otherSystemsTrackNameMode;
					const trackNameOrientation = this.index === 0 ? stylesheet.firstSystemTrackNameOrientation : stylesheet.otherSystemsTrackNameOrientation;
					let shouldRender = false;
					switch (trackNamePolicy) {
						case TrackNamePolicy.Hidden: break;
						case TrackNamePolicy.FirstSystem:
							shouldRender = this.index === 0;
							break;
						case TrackNamePolicy.AllSystems:
							shouldRender = true;
							break;
					}
					let hasAnyTrackName = false;
					if (shouldRender) {
						const canvas = this.layout.renderer.canvas;
						canvas.font = settings.display.resources.elementFonts.get(NotationElement.TrackNames);
						for (const t of tracks) {
							let trackNameText = "";
							switch (trackNameMode) {
								case TrackNameMode.FullName:
									trackNameText = t.name;
									break;
								case TrackNameMode.ShortName:
									trackNameText = t.shortName;
									break;
							}
							if (trackNameText.length > 0) {
								hasAnyTrackName = true;
								const size = canvas.measureText(trackNameText);
								switch (trackNameOrientation) {
									case TrackNameOrientation.Horizontal:
										this.accoladeWidth = Math.ceil(Math.max(this.accoladeWidth, size.width));
										break;
									case TrackNameOrientation.Vertical:
										this.accoladeWidth = Math.ceil(Math.max(this.accoladeWidth, size.height));
										break;
								}
							}
						}
						this.accoladeWidth += settings.display.systemLabelPaddingLeft;
						if (hasAnyTrackName) this.accoladeWidth += settings.display.systemLabelPaddingRight;
					}
				}
				let currentY = 0;
				for (const staff of this.allStaves) {
					staff.y = currentY;
					staff.calculateHeightForAccolade();
					currentY += staff.height;
				}
				let braceWidth = 0;
				for (const b of this._brackets) {
					b.updateCanPaint();
					b.finalizeBracket(settings.display.resources.engravingSettings);
					braceWidth = Math.max(braceWidth, b.width);
				}
				this.accoladeWidth += braceWidth;
				this.width += this.accoladeWidth;
				this.computedWidth += this.accoladeWidth;
			} else for (const b of this._brackets) {
				b.updateCanPaint();
				b.finalizeBracket(settings.display.resources.engravingSettings);
			}
		}
		_getStaffTrackGroup(track) {
			for (let i = 0, j = this.staves.length; i < j; i++) {
				const g = this.staves[i];
				if (g.track === track) return g;
			}
			return null;
		}
		addStaff(staff) {
			const track = staff.modelStaff.track;
			let group = this._getStaffTrackGroup(track);
			if (!group) {
				group = new StaffTrackGroup(this, track);
				this.staves.push(group);
			}
			staff.staffTrackGroup = group;
			staff.system = this;
			staff.index = this.allStaves.length;
			this.allStaves.push(staff);
			group.addStaff(staff);
			let bracket = this._brackets.find((b) => b.includesStaff(staff));
			if (!bracket) switch (track.score.stylesheet.bracketExtendMode) {
				case BracketExtendMode.NoBrackets: break;
				case BracketExtendMode.GroupStaves:
					bracket = new SingleTrackSystemBracket(this, track);
					bracket.index = this._brackets.length;
					this._brackets.push(bracket);
					break;
				case BracketExtendMode.GroupSimilarInstruments:
					bracket = new SimilarInstrumentSystemBracket(this, track);
					bracket.index = this._brackets.length;
					this._brackets.push(bracket);
					break;
			}
			if (bracket) {
				if (!bracket.firstStaffInBracket) bracket.firstStaffInBracket = staff;
				bracket.lastStaffInBracket = staff;
				group.bracket = bracket;
				this._staffToBracket.set(staff, bracket);
			}
		}
		get height() {
			return Math.ceil(this._contentHeight + this.topPadding + this.bottomPadding);
		}
		paint(cx, cy, canvas) {
			this.paintPartial(cx + this.x, cy + this.y + this.topPadding, canvas, 0, this.masterBarsRenderers.length);
			if (this._hasSystemSeparator) {
				const _ = ElementStyleHelper.track(canvas, TrackSubElement.SystemSeparator, this.allStaves[0].modelStaff.track);
				try {
					const smuflMetrics = this.layout.renderer.settings.display.resources.engravingSettings;
					const overlap = Math.min(0, smuflMetrics.glyphBottom.get(MusicFontSymbol.SystemDivider) ?? 0);
					CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, cy + this.y + this.height + overlap, 1, MusicFontSymbol.SystemDivider, false);
					CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + this.width - smuflMetrics.glyphWidths.get(MusicFontSymbol.SystemDivider), cy + this.y + this.height + overlap, 1, MusicFontSymbol.SystemDivider, false);
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
		paintPartial(cx, cy, canvas, startIndex, count) {
			for (const s of this.allStaves) if (s.isVisible) s.paint(cx, cy, canvas, startIndex, count);
			const res = this.layout.renderer.settings.display.resources;
			if (this.staves.length > 0 && startIndex === 0) {
				canvas.color = res.barSeparatorColor;
				const settings = this.layout.renderer.settings;
				const hasTrackName = this.layout.renderer.settings.notation.isNotationElementVisible(NotationElement.TrackNames);
				canvas.font = res.elementFonts.get(NotationElement.TrackNames);
				if (hasTrackName) {
					const stylesheet = this.layout.renderer.score.stylesheet;
					const trackNamePolicy = this.layout.renderer.tracks.length === 1 ? stylesheet.singleTrackTrackNamePolicy : stylesheet.multiTrackTrackNamePolicy;
					const trackNameMode = this.index === 0 ? stylesheet.firstSystemTrackNameMode : stylesheet.otherSystemsTrackNameMode;
					const trackNameOrientation = this.index === 0 ? stylesheet.firstSystemTrackNameOrientation : stylesheet.otherSystemsTrackNameOrientation;
					let shouldRender = false;
					switch (trackNamePolicy) {
						case TrackNamePolicy.Hidden: break;
						case TrackNamePolicy.FirstSystem:
							shouldRender = this.index === 0;
							break;
						case TrackNamePolicy.AllSystems:
							shouldRender = true;
							break;
					}
					if (shouldRender) {
						const oldBaseLine = canvas.textBaseline;
						const oldTextAlign = canvas.textAlign;
						for (const g of this.staves) if (g.firstVisibleStaff) {
							const firstStart = cy + g.firstVisibleStaff.contentTop;
							const lastEnd = cy + g.lastVisibleStaff.contentBottom;
							let trackNameText = "";
							switch (trackNameMode) {
								case TrackNameMode.FullName:
									trackNameText = g.track.name;
									break;
								case TrackNameMode.ShortName:
									trackNameText = g.track.shortName;
									break;
							}
							const _trackNameStyle = ElementStyleHelper.track(canvas, TrackSubElement.TrackName, g.track);
							try {
								if (trackNameText.length > 0) {
									const textEndX = cx + g.staves[0].x - settings.display.accoladeBarPaddingRight - (g.bracket?.width ?? 0) - settings.display.systemLabelPaddingRight;
									switch (trackNameOrientation) {
										case TrackNameOrientation.Horizontal:
											canvas.textBaseline = TextBaseline.Middle;
											canvas.textAlign = TextAlign.Right;
											canvas.fillText(trackNameText, textEndX, (firstStart + lastEnd) / 2);
											break;
										case TrackNameOrientation.Vertical:
											canvas.textBaseline = TextBaseline.Bottom;
											canvas.textAlign = TextAlign.Center;
											canvas.beginRotate(textEndX, (firstStart + lastEnd) / 2, -90.1);
											canvas.fillText(trackNameText, 0, 0);
											canvas.endRotate();
											break;
									}
								}
							} finally {
								_trackNameStyle?.[Symbol.dispose]?.();
							}
						}
						canvas.textBaseline = oldBaseLine;
						canvas.textAlign = oldTextAlign;
					}
				}
				const needsSystemBarLine = !this.layout.renderer.score.stylesheet.extendBarLines;
				if (this.allStaves.length > 0 && needsSystemBarLine) {
					let previousStaffInBracket = null;
					for (const s of this.allStaves) {
						if (!s.isVisible) continue;
						if (previousStaffInBracket !== null) {
							const previousBottom = previousStaffInBracket.contentBottom;
							const thisTop = s.contentTop;
							const accoladeX = cx + previousStaffInBracket.x;
							const firstLineBarRenderer = previousStaffInBracket.barRenderers[0];
							const _ = ElementStyleHelper.bar(canvas, firstLineBarRenderer.staffLineBarSubElement, firstLineBarRenderer.bar);
							try {
								const h = Math.ceil(thisTop - previousBottom);
								canvas.fillRect(accoladeX, cy + previousBottom, res.engravingSettings.thinBarlineThickness, h);
							} finally {
								_?.[Symbol.dispose]?.();
							}
						}
						previousStaffInBracket = s;
					}
				}
				this._paintBrackets(cx, cy, canvas);
			}
		}
		_paintBrackets(cx, cy, canvas) {
			const settings = this.layout.renderer.settings;
			for (const bracket of this._brackets) if (bracket.canPaint) {
				const barStartX = cx + bracket.firstVisibleStaffInBracket.x;
				const barSize = bracket.width;
				const barOffset = settings.display.accoladeBarPaddingRight;
				const firstStart = cy + bracket.firstVisibleStaffInBracket.contentTop;
				const lastEnd = cy + bracket.lastVisibleStaffInBracket.contentBottom;
				let accoladeStart = firstStart;
				let accoladeEnd = lastEnd;
				if (bracket.drawAsBrace) CanvasHelper.fillMusicFontSymbolSafe(canvas, barStartX - barOffset - barSize, accoladeEnd, bracket.braceScale, MusicFontSymbol.Brace);
				else if (bracket.firstVisibleStaffInBracket !== bracket.lastVisibleStaffInBracket) {
					const bracketOverflow = settings.display.resources.engravingSettings.oneStaffSpace * .25;
					accoladeStart -= bracketOverflow;
					accoladeEnd += bracketOverflow;
					const barShift = 3;
					canvas.fillRect(barStartX - barOffset - barSize, accoladeStart - barShift, barSize, Math.ceil(accoladeEnd - accoladeStart + barShift * 2));
					const spikeX = barStartX - barOffset - barSize;
					CanvasHelper.fillMusicFontSymbolSafe(canvas, spikeX, accoladeStart, 1, MusicFontSymbol.BracketTop);
					CanvasHelper.fillMusicFontSymbolSafe(canvas, spikeX, Math.floor(accoladeEnd), 1, MusicFontSymbol.BracketBottom);
				}
			}
		}
		finalizeSystem() {
			const settings = this.layout.renderer.settings;
			if (this.index === 0) this.topPadding = settings.display.firstSystemPaddingTop;
			if (this.isLast) this.bottomPadding = settings.display.lastSystemPaddingBottom;
			else if (this.layout.renderer.score.stylesheet.useSystemSignSeparator && this.layout.renderer.tracks.length > 1) {
				const neededHeight = settings.display.resources.engravingSettings.glyphHeights.get(MusicFontSymbol.SystemDivider);
				this.bottomPadding = Math.max(this.bottomPadding, neededHeight);
				this._hasSystemSeparator = true;
			}
			if (!this._finalizeTrackGroups()) {
				const firstStaff = this.staves[0].staves[0];
				firstStaff.isVisible = true;
				this._finalizeTrackGroups(true);
			}
			for (const b of this._brackets) b.finalizeBracket(settings.display.resources.engravingSettings);
		}
		_finalizeTrackGroups(onlyFirstGroup = false) {
			let currentY = 0;
			const settings = this.layout.renderer.settings;
			const smufl = settings.display.resources.engravingSettings;
			const topBracketSpikeHeight = smufl.glyphHeights.get(MusicFontSymbol.BracketTop);
			const bottomBracketSpikeHeight = smufl.glyphHeights.get(MusicFontSymbol.BracketBottom);
			let previousStaff = void 0;
			let endSpikeOverflow = 0;
			let anyStaffVisible = false;
			for (const group of this.staves) {
				let firstVisibleStaffInGroup = void 0;
				let lastVisibleStaffInGroup = void 0;
				for (const staff of group.staves) {
					if (previousStaff !== void 0 && previousStaff.trackIndex !== staff.trackIndex) currentY += settings.display.trackStaffPaddingBetween;
					const bracket = this._staffToBracket.has(staff) ? this._staffToBracket.get(staff) : void 0;
					const hasBracket = bracket && !bracket.drawAsBrace && bracket.canPaint;
					if (hasBracket && bracket.firstStaffInBracket === staff) {
						const spikeOverflow = topBracketSpikeHeight - staff.topOverflow;
						if (spikeOverflow > 0) currentY += spikeOverflow;
					}
					staff.x = this.accoladeWidth;
					staff.y = currentY;
					if (!onlyFirstGroup) staff.finalizeStaff();
					if (staff.isVisible) {
						currentY += staff.height;
						anyStaffVisible = true;
						previousStaff = staff;
						if (!firstVisibleStaffInGroup) firstVisibleStaffInGroup = staff;
						lastVisibleStaffInGroup = staff;
					}
					endSpikeOverflow = 0;
					if (hasBracket && bracket.lastStaffInBracket === staff) {
						const spikeOverflow = bottomBracketSpikeHeight - staff.bottomOverflow;
						if (spikeOverflow > 0) if (staff.isVisible) currentY += spikeOverflow;
						else endSpikeOverflow = spikeOverflow;
					}
				}
				group.firstVisibleStaff = firstVisibleStaffInGroup;
				group.lastVisibleStaff = lastVisibleStaffInGroup;
				if (!this.firstVisibleStaff) this.firstVisibleStaff = firstVisibleStaffInGroup;
				if (onlyFirstGroup) break;
			}
			if (endSpikeOverflow) currentY += endSpikeOverflow;
			this._contentHeight = currentY;
			return anyStaffVisible;
		}
		buildBoundingsLookup(cx, cy) {
			if (this.layout.renderer.boundsLookup.isFinished) return;
			const firstStaff = this.allStaves[0];
			const lastStaff = this.allStaves[this.allStaves.length - 1];
			cy += this.topPadding;
			const visualTop = cy + this.y + firstStaff.y;
			const visualHeight = cy + this.y + lastStaff.y + lastStaff.height - visualTop;
			const realTop = cy + this.y;
			const realHeight = cy + this.y + this.height - realTop;
			const lineTop = cy + this.y + firstStaff.y + firstStaff.topPadding + firstStaff.topOverflow;
			const lineHeight = cy + this.y + lastStaff.y + lastStaff.height - lastStaff.bottomPadding - lastStaff.bottomOverflow - lineTop;
			const x = this.x + firstStaff.x;
			const staffSystemBounds = new StaffSystemBounds();
			staffSystemBounds.visualBounds = new Bounds();
			staffSystemBounds.visualBounds.x = cx + this.x;
			staffSystemBounds.visualBounds.y = cy + this.y;
			staffSystemBounds.visualBounds.w = this.width;
			staffSystemBounds.visualBounds.h = this.height - this.topPadding - this.bottomPadding;
			staffSystemBounds.realBounds = new Bounds();
			staffSystemBounds.realBounds.x = cx + this.x;
			staffSystemBounds.realBounds.y = cy + this.y;
			staffSystemBounds.realBounds.w = this.width;
			staffSystemBounds.realBounds.h = this.height;
			this.layout.renderer.boundsLookup.addStaffSystem(staffSystemBounds);
			const masterBarBoundsLookup = /* @__PURE__ */ new Map();
			for (let i = 0; i < this.staves.length; i++) for (const staff of this.staves[i].staves) {
				if (!staff.isVisible) continue;
				for (const renderer of staff.barRenderers) {
					let masterBarBounds;
					if (!masterBarBoundsLookup.has(renderer.bar.masterBar.index)) {
						masterBarBounds = new MasterBarBounds();
						masterBarBounds.index = renderer.bar.masterBar.index;
						masterBarBounds.isFirstOfLine = renderer.isFirstOfStaff;
						masterBarBounds.realBounds = new Bounds();
						masterBarBounds.realBounds.x = x + renderer.x;
						masterBarBounds.realBounds.y = realTop;
						masterBarBounds.realBounds.w = renderer.width;
						masterBarBounds.realBounds.h = realHeight;
						masterBarBounds.visualBounds = new Bounds();
						masterBarBounds.visualBounds.x = x + renderer.x;
						masterBarBounds.visualBounds.y = visualTop;
						masterBarBounds.visualBounds.w = renderer.width;
						masterBarBounds.visualBounds.h = visualHeight;
						masterBarBounds.lineAlignedBounds = new Bounds();
						masterBarBounds.lineAlignedBounds.x = x + renderer.x;
						masterBarBounds.lineAlignedBounds.y = lineTop;
						masterBarBounds.lineAlignedBounds.w = renderer.width;
						masterBarBounds.lineAlignedBounds.h = lineHeight;
						this.layout.renderer.boundsLookup.addMasterBar(masterBarBounds);
						masterBarBoundsLookup.set(masterBarBounds.index, masterBarBounds);
					} else masterBarBounds = masterBarBoundsLookup.get(renderer.bar.masterBar.index);
					renderer.buildBoundingsLookup(masterBarBounds, x, cy + this.y + staff.y);
				}
			}
		}
		getBarX(index) {
			if (this.allStaves.length === 0 || this.layout.renderer.tracks.length === 0) return 0;
			const bar = this.layout.renderer.tracks[0].staves[0].bars[index];
			return this.layout.getRendererForBar(this.allStaves[0].staffId, bar).x;
		}
	};
	//#endregion
	//#region src/rendering/layout/ScoreLayout.ts
	/**
	* This is the base class for creating new layouting engines for the score renderer.
	* @internal
	*/
	var ScoreLayout = class ScoreLayout {
		_barRendererLookup = /* @__PURE__ */ new Map();
		pagePadding = null;
		profile = /* @__PURE__ */ new Set();
		renderer;
		width = 0;
		height = 0;
		multiBarRestInfo = null;
		get scaledWidth() {
			return Math.round(this.width / this.renderer.settings.display.scale);
		}
		headerGlyphs = /* @__PURE__ */ new Map();
		footerGlyphs = /* @__PURE__ */ new Map();
		chordDiagrams = null;
		tuningGlyph = null;
		constructor(renderer) {
			this.renderer = renderer;
		}
		slurRegistry = new SlurRegistry();
		beamingRuleLookups = /* @__PURE__ */ new Map();
		resize() {
			this._lazyPartials.clear();
			this.slurRegistry.clear();
			this.doResize();
		}
		layoutAndRender(renderHints) {
			this.slurRegistry.clear();
			const score = this.renderer.score;
			this.firstBarIndex = ModelUtils.computeFirstDisplayedBarIndex(score, this.renderer.settings);
			this.lastBarIndex = ModelUtils.computeLastDisplayedBarIndex(score, this.renderer.settings, this.firstBarIndex);
			this.multiBarRestInfo = ModelUtils.buildMultiBarRestInfo(this.renderer.tracks, this.firstBarIndex, this.lastBarIndex);
			if (renderHints?.firstChangedMasterBar !== void 0) {
				if (this.doUpdateForBars(renderHints)) return;
			}
			this._lazyPartials.clear();
			this.beamingRuleLookups.clear();
			this._barRendererLookup.clear();
			this.profile = Environment.staveProfiles.get(this.renderer.settings.display.staveProfile);
			this.pagePadding = this.renderer.settings.display.padding.map((p) => p / this.renderer.settings.display.scale);
			if (!this.pagePadding) this.pagePadding = [
				0,
				0,
				0,
				0
			];
			if (this.pagePadding.length === 1) this.pagePadding = [
				this.pagePadding[0],
				this.pagePadding[0],
				this.pagePadding[0],
				this.pagePadding[0]
			];
			else if (this.pagePadding.length === 2) this.pagePadding = [
				this.pagePadding[0],
				this.pagePadding[1],
				this.pagePadding[0],
				this.pagePadding[1]
			];
			this._createScoreInfoGlyphs();
			this.doLayoutAndRender(renderHints);
		}
		_lazyPartials = /* @__PURE__ */ new Map();
		getExistingPartialArgs(id) {
			return this._lazyPartials.has(id) ? this._lazyPartials.get(id).args : void 0;
		}
		registerPartial(args, callback) {
			if (args.height === 0) return;
			const scale = this.renderer.settings.display.scale;
			args.x *= scale;
			args.y *= scale;
			args.width *= scale;
			args.height *= scale;
			args.totalWidth *= scale;
			args.totalHeight *= scale;
			if (!this.renderer.settings.core.enableLazyLoading) {
				this.renderer.partialLayoutFinished.trigger(args);
				this._internalRenderLazyPartial(args, callback);
			} else {
				const partial = {
					args,
					renderCallback: callback
				};
				this._lazyPartials.set(args.id, partial);
				this.renderer.partialLayoutFinished.trigger(args);
			}
		}
		_internalRenderLazyPartial(args, callback) {
			const canvas = this.renderer.canvas;
			canvas.beginRender(args.width, args.height);
			callback(canvas);
			args.renderResult = canvas.endRender();
			this.renderer.partialRenderFinished.trigger(args);
		}
		renderLazyPartial(resultId) {
			if (this._lazyPartials.has(resultId)) {
				const lazyPartial = this._lazyPartials.get(resultId);
				this._internalRenderLazyPartial(lazyPartial.args, lazyPartial.renderCallback);
			}
		}
		static headerElements = new Lazy(() => new Map([
			[ScoreSubElement.Title, NotationElement.ScoreTitle],
			[ScoreSubElement.SubTitle, NotationElement.ScoreSubTitle],
			[ScoreSubElement.Artist, NotationElement.ScoreArtist],
			[ScoreSubElement.Album, NotationElement.ScoreAlbum],
			[ScoreSubElement.Words, NotationElement.ScoreWords],
			[ScoreSubElement.Music, NotationElement.ScoreMusic],
			[ScoreSubElement.WordsAndMusic, NotationElement.ScoreWordsAndMusic],
			[ScoreSubElement.Transcriber, void 0]
		]));
		static footerElements = new Lazy(() => new Map([[ScoreSubElement.Copyright, NotationElement.ScoreCopyright], [ScoreSubElement.CopyrightSecondLine, void 0]]));
		_createHeaderFooterGlyph(settings, score, element, notationElement) {
			switch (element) {
				case ScoreSubElement.WordsAndMusic:
					if (score.words !== score.music) return;
					break;
				case ScoreSubElement.Words:
				case ScoreSubElement.Music:
					if (score.words === score.music) return;
					break;
				case ScoreSubElement.CopyrightSecondLine:
					if (!this.footerGlyphs.has(ScoreSubElement.Copyright)) return;
					break;
			}
			const res = settings.display.resources;
			const notation = settings.notation;
			const style = score.style && score.style.headerAndFooter.has(element) ? score.style.headerAndFooter.get(element) : ScoreStyle.defaultHeaderAndFooter.get(element);
			let isVisible = style.isVisible !== void 0 ? style.isVisible : true;
			if (notationElement !== void 0) isVisible = notation.isNotationElementVisible(notationElement);
			if (!isVisible) return;
			const text = style.buildText(score);
			if (!text) return;
			return new TextGlyph(0, 0, text, res.getFontForElement(element), style.textAlign, void 0, ElementStyleHelper.scoreColor(res, element, score));
		}
		_createScoreInfoGlyphs() {
			Logger.debug("ScoreLayout", "Creating score info glyphs");
			const settings = this.renderer.settings;
			const score = this.renderer.score;
			this.headerGlyphs = /* @__PURE__ */ new Map();
			this.footerGlyphs = /* @__PURE__ */ new Map();
			const fakeBarRenderer = new BarRendererBase(this.renderer, this.renderer.tracks[0].staves[0].bars[0]);
			for (const [scoreElement, notationElement] of ScoreLayout.headerElements.value) {
				const glyph = this._createHeaderFooterGlyph(settings, score, scoreElement, notationElement);
				if (glyph) {
					glyph.renderer = fakeBarRenderer;
					glyph.doLayout();
					this.headerGlyphs.set(scoreElement, glyph);
				}
			}
			for (const [scoreElement, notationElement] of ScoreLayout.footerElements.value) {
				const glyph = this._createHeaderFooterGlyph(settings, score, scoreElement, notationElement);
				if (glyph) {
					glyph.renderer = fakeBarRenderer;
					glyph.doLayout();
					this.footerGlyphs.set(scoreElement, glyph);
				}
			}
			const notation = settings.notation;
			const res = settings.display.resources;
			if (notation.isNotationElementVisible(NotationElement.GuitarTuning)) {
				const stavesWithTuning = [];
				for (const track of this.renderer.tracks) for (const staff of track.staves) {
					let showTuning = !staff.isPercussion && staff.isStringed && staff.tuning.length > 0 && staff.showTablature;
					if (score.stylesheet.perTrackDisplayTuning && score.stylesheet.perTrackDisplayTuning.has(track.index) && score.stylesheet.perTrackDisplayTuning.get(track.index) === false) showTuning = false;
					if (showTuning) {
						stavesWithTuning.push(staff);
						break;
					}
				}
				if (stavesWithTuning.length > 0 && score.stylesheet.globalDisplayTuning) {
					this.tuningGlyph = new TuningContainerGlyph(0, 0);
					this.tuningGlyph.renderer = fakeBarRenderer;
					for (const staff of stavesWithTuning) if (staff.stringTuning.tunings.length > 0) {
						const trackLabel = stavesWithTuning.length > 1 ? staff.track.name : "";
						const item = new TuningGlyph(0, 0, staff.stringTuning, trackLabel);
						item.colorOverride = ElementStyleHelper.trackColor(res, TrackSubElement.StringTuning, staff.track);
						item.renderer = fakeBarRenderer;
						item.doLayout();
						this.tuningGlyph.addGlyph(item);
					}
				} else this.tuningGlyph = null;
			}
			if (notation.isNotationElementVisible(NotationElement.ChordDiagrams)) {
				this.chordDiagrams = new ChordDiagramContainerGlyph(0, 0);
				this.chordDiagrams.renderer = fakeBarRenderer;
				const chordIds = /* @__PURE__ */ new Set();
				for (const track of this.renderer.tracks) {
					if (!(score.stylesheet.globalDisplayChordDiagramsOnTop && (score.stylesheet.perTrackChordDiagramsOnTop == null || !score.stylesheet.perTrackChordDiagramsOnTop.has(track.index) || score.stylesheet.perTrackChordDiagramsOnTop.get(track.index)))) continue;
					for (const staff of track.staves) {
						const sc = staff.chords;
						if (sc) {
							for (const [, chord] of sc) if (!chordIds.has(chord.uniqueId)) {
								if (chord.showDiagram) {
									chordIds.add(chord.uniqueId);
									this.chordDiagrams.addChord(chord);
								}
							}
						}
					}
				}
				if (this.chordDiagrams.isEmpty) this.chordDiagrams = null;
			} else this.chordDiagrams = null;
		}
		firstBarIndex = 0;
		lastBarIndex = 0;
		createEmptyStaffSystem(index) {
			const system = new StaffSystem(this);
			system.index = index;
			const allFactories = Environment.defaultRenderers;
			const renderStaves = [];
			for (let trackIndex = 0; trackIndex < this.renderer.tracks.length; trackIndex++) {
				const track = this.renderer.tracks[trackIndex];
				for (let staffIndex = 0; staffIndex < track.staves.length; staffIndex++) {
					const staff = track.staves[staffIndex];
					let sharedTopEffects = [];
					let sharedBottomEffects = [];
					let previousStaff = void 0;
					for (const factory of allFactories) if (this.profile.has(factory.staffId) && factory.canCreate(track, staff)) {
						const renderStaff = new RenderStaff(system, trackIndex, staff, factory);
						renderStaff.topEffectInfos.splice(0, 0, ...sharedTopEffects);
						renderStaff.bottomEffectInfos.push(...sharedBottomEffects);
						previousStaff = renderStaff;
						renderStaves.push(renderStaff);
						sharedTopEffects = [];
						sharedBottomEffects = [];
					} else for (const e of factory.effectBands) switch (e.mode) {
						case EffectBandMode.SharedTop:
							sharedTopEffects.push(e);
							break;
						case EffectBandMode.SharedBottom:
							sharedBottomEffects.push(e);
							break;
					}
					if (previousStaff) {
						if (sharedTopEffects.length > 0) previousStaff.bottomEffectInfos.push(...sharedTopEffects);
						if (sharedBottomEffects.length > 0) previousStaff.bottomEffectInfos.push(...sharedBottomEffects);
					}
				}
			}
			for (const staff of renderStaves) system.addStaff(staff);
			return system;
		}
		registerBarRenderer(key, renderer) {
			if (!this._barRendererLookup.has(key)) this._barRendererLookup.set(key, /* @__PURE__ */ new Map());
			this._barRendererLookup.get(key).set(renderer.bar.id, renderer);
			if (renderer.additionalMultiRestBars) for (const b of renderer.additionalMultiRestBars) this._barRendererLookup.get(key).set(b.id, renderer);
		}
		getRendererForBar(key, bar) {
			const barRendererId = bar.id;
			if (this._barRendererLookup.has(key) && this._barRendererLookup.get(key).has(barRendererId)) return this._barRendererLookup.get(key).get(barRendererId);
			return null;
		}
		layoutAndRenderBottomScoreInfo(y) {
			y = Math.round(y);
			const e = new RenderFinishedEventArgs();
			e.x = 0;
			e.y = y;
			let infoHeight = 0;
			const res = this.renderer.settings.display.resources;
			const scoreInfoGlyphs = [];
			let width = 0;
			for (const [scoreElement, _notationElement] of ScoreLayout.footerElements.value) if (this.footerGlyphs.has(scoreElement)) {
				const glyph = this.footerGlyphs.get(scoreElement);
				glyph.y = infoHeight;
				this.alignScoreInfoGlyph(glyph);
				infoHeight += glyph.height;
				scoreInfoGlyphs.push(glyph);
				width = Math.max(width, Math.round(glyph.x + glyph.width));
			}
			infoHeight = Math.round(infoHeight);
			if (scoreInfoGlyphs.length > 0) {
				e.width = width;
				e.height = infoHeight;
				e.totalWidth = this.scaledWidth;
				e.totalHeight = y + e.height;
				this.registerPartial(e, (canvas) => {
					canvas.color = res.scoreInfoColor;
					canvas.textAlign = TextAlign.Left;
					canvas.textBaseline = TextBaseline.Top;
					for (const g of scoreInfoGlyphs) g.paint(0, 0, canvas);
				});
			}
			return y + infoHeight;
		}
		alignScoreInfoGlyph(glyph) {
			if (Environment.getLayoutEngineFactory(this.renderer.settings.display.layoutMode).vertical) switch (glyph.textAlign) {
				case TextAlign.Left:
					glyph.x = this.pagePadding[0];
					break;
				case TextAlign.Center:
					glyph.x = this.scaledWidth / 2;
					break;
				case TextAlign.Right:
					glyph.x = this.scaledWidth - this.pagePadding[2];
					break;
			}
			else {
				glyph.x = this.firstBarX;
				glyph.textAlign = TextAlign.Left;
			}
		}
		_layoutAndRenderAnnotation(y) {
			const msg = "rendered by alphaTab";
			const resources = this.renderer.settings.display.resources;
			const size = 12;
			const fontFamilies = resources.elementFonts.has(NotationElement.ScoreCopyright) ? resources.elementFonts.get(NotationElement.ScoreCopyright).families : resources.tablatureFont.families;
			const font = Font.withFamilyList(fontFamilies, size, FontStyle.Plain, FontWeight.Bold);
			const fakeBarRenderer = new BarRendererBase(this.renderer, this.renderer.tracks[0].staves[0].bars[0]);
			const glyph = new TextGlyph(0, 0, msg, font, TextAlign.Center, void 0, resources.mainGlyphColor);
			glyph.renderer = fakeBarRenderer;
			glyph.doLayout();
			this.alignScoreInfoGlyph(glyph);
			const e = new RenderFinishedEventArgs();
			e.width = glyph.x + glyph.width;
			e.x = 0;
			e.height = size;
			e.y = y;
			e.totalWidth = this.scaledWidth;
			e.totalHeight = y + size;
			e.firstMasterBarIndex = -1;
			e.lastMasterBarIndex = -1;
			this.registerPartial(e, (canvas) => {
				canvas.color = resources.mainGlyphColor;
				canvas.font = font;
				canvas.textAlign = TextAlign.Left;
				canvas.textBaseline = TextBaseline.Top;
				glyph.paint(0, 0, canvas);
			});
			return y + size;
		}
	};
	//#endregion
	//#region src/rendering/layout/HorizontalScreenLayout.ts
	/**
	* @internal
	*/
	var HorizontalScreenLayoutPartialInfo = class {
		x = 0;
		width = 0;
		masterBars = [];
		results = [];
	};
	/**
	* This layout arranges the bars all horizontally
	* @internal
	*/
	var HorizontalScreenLayout = class extends ScoreLayout {
		_system = null;
		get name() {
			return "HorizontalScreen";
		}
		get supportsResize() {
			return false;
		}
		get firstBarX() {
			let x = this.pagePadding[0];
			if (this._system) x += this._system.accoladeWidth;
			return x;
		}
		doResize() {}
		doUpdateForBars(_renderHints) {
			return false;
		}
		doLayoutAndRender(renderHints) {
			const score = this.renderer.score;
			let startIndex = this.renderer.settings.display.startBar;
			startIndex--;
			startIndex = Math.min(score.masterBars.length - 1, Math.max(0, startIndex));
			let currentBarIndex = startIndex;
			let endBarIndex = this.renderer.settings.display.barCount;
			if (endBarIndex <= 0) endBarIndex = score.masterBars.length;
			endBarIndex = startIndex + endBarIndex - 1;
			endBarIndex = Math.min(score.masterBars.length - 1, Math.max(0, endBarIndex));
			this._system = this.createEmptyStaffSystem(0);
			this._system.shareMinDurationAcrossBars = false;
			this._system.isLast = true;
			this._system.x = this.pagePadding[0];
			this._system.y = this.pagePadding[1];
			const countPerPartial = this.renderer.settings.display.barCountPerPartial;
			const partials = [];
			let currentPartial = new HorizontalScreenLayoutPartialInfo();
			while (currentBarIndex <= endBarIndex) {
				const multiBarRestInfo = this.multiBarRestInfo;
				const additionalMultiBarsRestBarIndices = multiBarRestInfo !== null && multiBarRestInfo.has(currentBarIndex) ? multiBarRestInfo.get(currentBarIndex) : null;
				const result = this._system.addBars(this.renderer.tracks, currentBarIndex, additionalMultiBarsRestBarIndices);
				if (currentPartial.masterBars.length >= countPerPartial && !result.isLinkedToPrevious) currentPartial = this._completePartial(partials, currentPartial);
				this._scaleBars(result);
				currentPartial.results.push(result);
				currentPartial.masterBars.push(score.masterBars[currentBarIndex]);
				currentPartial.width += result.width;
				currentBarIndex++;
			}
			if (currentPartial.masterBars.length > 0) this._completePartial(partials, currentPartial);
			this._finalizeStaffSystem();
			this.height = Math.floor(this._system.y + this._system.height);
			this.width = this._system.x + this._system.width + this.pagePadding[2];
			currentBarIndex = 0;
			let x = 0;
			for (let i = 0; i < partials.length; i++) {
				const partial = partials[i];
				const e = new RenderFinishedEventArgs();
				e.reuseViewport = renderHints?.reuseViewport ?? false;
				e.x = x;
				e.y = 0;
				e.totalWidth = this.width;
				e.totalHeight = this.height;
				e.width = partial.width;
				e.height = this.height;
				e.firstMasterBarIndex = partial.masterBars[0].index;
				e.lastMasterBarIndex = partial.masterBars[partial.masterBars.length - 1].index;
				x += partial.width;
				const partialBarIndex = currentBarIndex;
				const partialIndex = i;
				this._system.buildBoundingsLookup(0, 0);
				this.registerPartial(e, (canvas) => {
					let renderX = this._system.getBarX(partial.masterBars[0].index) + this._system.accoladeWidth;
					if (partialIndex === 0) renderX -= this._system.x + this._system.accoladeWidth;
					canvas.color = this.renderer.settings.display.resources.mainGlyphColor;
					canvas.textAlign = TextAlign.Left;
					Logger.debug(this.name, `Rendering partial from bar ${partial.masterBars[0].index} to ${partial.masterBars[partial.masterBars.length - 1].index}`, null);
					this._system.paintPartial(-renderX, this._system.y, canvas, partialBarIndex, partial.masterBars.length);
				});
				currentBarIndex += partial.masterBars.length;
			}
			this.height = this.layoutAndRenderBottomScoreInfo(this.height);
			this.height = this._layoutAndRenderAnnotation(this.height);
			this.height += this.pagePadding[3];
			this.height *= this.renderer.settings.display.scale;
		}
		_scaleBars(result) {
			result.width = 0;
			this._system.width -= result.width;
			for (const r of result.renderers) {
				const barDisplayWidth = r.staff.system.staves.length > 1 ? r.bar.masterBar.displayWidth : r.bar.displayWidth;
				if (barDisplayWidth > 0) r.scaleToWidth(barDisplayWidth);
				const w = r.x + r.width;
				if (w > result.width) result.width = w;
			}
			this._system.width += result.width;
		}
		_completePartial(partials, currentPartial) {
			if (partials.length === 0) currentPartial.width += this._system.accoladeWidth + this.pagePadding[0];
			partials.push(currentPartial);
			Logger.debug(this.name, `Finished partial from bar ${currentPartial.masterBars[0].index} to ${currentPartial.masterBars[currentPartial.masterBars.length - 1].index}`, null);
			const newPartial = new HorizontalScreenLayoutPartialInfo();
			newPartial.x = currentPartial.x + currentPartial.width;
			return newPartial;
		}
		_finalizeStaffSystem() {
			this._alignRenderers();
			this._system.finalizeSystem();
		}
		_alignRenderers() {
			this.width = 0;
			const system = this._system;
			for (const s of system.allStaves) {
				s.resetSharedLayoutData();
				let w = 0;
				for (const renderer of s.barRenderers) {
					renderer.x = w;
					renderer.y = s.topPadding + s.topOverflow;
					renderer.scaleToWidth(renderer.width);
					w += renderer.width;
				}
				if (w > this.width) system.width = w;
			}
			system.width += system.accoladeWidth;
		}
	};
	//#endregion
	//#region src/rendering/layout/VerticalLayoutBase.ts
	/**
	* Base layout for page and parchment style layouts where we have an endless
	* vertical page with fitted systems.
	* @internal
	*/
	var VerticalLayoutBase = class extends ScoreLayout {
		_systems = [];
		_allMasterBarRenderers = [];
		_barsFromPreviousSystem = [];
		_reuseViewPort = false;
		_preSystemPartialIds = [];
		_systemPartialIds = [];
		doLayoutAndRender(renderHints) {
			let y = this.pagePadding[1];
			this.width = this.renderer.width;
			this._allMasterBarRenderers = [];
			this._preSystemPartialIds = [];
			this._systemPartialIds = [];
			this._reuseViewPort = renderHints?.reuseViewport ?? false;
			this._systems = [];
			y = this._layoutAndRenderScoreInfo(y, -1);
			y = this._layoutAndRenderTunings(y, -1);
			y = this._layoutAndRenderChordDiagrams(y, -1);
			y = this._layoutAndRenderScore(y, this.firstBarIndex);
			y = this.layoutAndRenderBottomScoreInfo(y);
			y = this._layoutAndRenderAnnotation(y);
			this.height = (y + this.pagePadding[3]) * this.renderer.settings.display.scale;
		}
		registerPartial(args, callback) {
			args.reuseViewport = this._reuseViewPort;
			super.registerPartial(args, callback);
		}
		reregisterPartial(id) {
			const args = this.getExistingPartialArgs(id);
			if (!args) return;
			args.reuseViewport = this._reuseViewPort;
			this.renderer.partialLayoutFinished.trigger(args);
		}
		get supportsResize() {
			return true;
		}
		get firstBarX() {
			let x = this.pagePadding[0];
			if (this._systems.length > 0) x += this._systems[0].accoladeWidth;
			return x;
		}
		doUpdateForBars(renderHints) {
			this._reuseViewPort = renderHints.reuseViewport ?? false;
			const firstModifiedMasterBar = renderHints.firstChangedMasterBar;
			const systemIndex = this._systems.findIndex((s) => {
				const first = s.masterBarsRenderers[0].masterBar.index;
				const last = s.masterBarsRenderers[s.masterBarsRenderers.length - 1].masterBar.index;
				return first <= firstModifiedMasterBar && firstModifiedMasterBar <= last;
			});
			if (systemIndex === -1 || !this.renderer.settings.core.enableLazyLoading) return false;
			const firstRebuiltBarIndex = this._systems[systemIndex].masterBarsRenderers[0].masterBar.index;
			this.renderer.boundsLookup.clearFromMasterBar(firstRebuiltBarIndex);
			const removeSystems = this._systems.splice(systemIndex, this._systems.length - systemIndex);
			this._systemPartialIds.splice(systemIndex, this._systemPartialIds.length - systemIndex);
			const system = removeSystems[0];
			let y = system.y;
			const firstBarIndex = system.masterBarsRenderers[0].masterBar.index;
			for (const preSystemPartial of this._preSystemPartialIds) this.reregisterPartial(preSystemPartial);
			for (let i = 0; i < systemIndex; i++) this.reregisterPartial(this._systemPartialIds[i]);
			y = this._layoutAndRenderScore(y, firstBarIndex);
			y = this.layoutAndRenderBottomScoreInfo(y);
			y = this._layoutAndRenderAnnotation(y);
			this.height = (y + this.pagePadding[3]) * this.renderer.settings.display.scale;
			return true;
		}
		doResize() {
			let y = this.pagePadding[1];
			this.width = this.renderer.width;
			const oldHeight = this.height;
			this._reuseViewPort = true;
			y = this._layoutAndRenderScoreInfo(y, oldHeight);
			y = this._layoutAndRenderTunings(y, oldHeight);
			y = this._layoutAndRenderChordDiagrams(y, oldHeight);
			y = this._resizeAndRenderScore(y, oldHeight);
			y = this.layoutAndRenderBottomScoreInfo(y);
			y = this._layoutAndRenderAnnotation(y);
			this.height = (y + this.pagePadding[3]) * this.renderer.settings.display.scale;
		}
		_layoutAndRenderTunings(y, totalHeight = -1) {
			if (!this.tuningGlyph) return y;
			const res = this.renderer.settings.display.resources;
			this.tuningGlyph.x = this.pagePadding[0];
			this.tuningGlyph.width = this.scaledWidth - this.pagePadding[0] - this.pagePadding[2];
			this.tuningGlyph.doLayout();
			const tuningHeight = Math.round(this.tuningGlyph.height);
			const e = new RenderFinishedEventArgs();
			e.x = 0;
			e.y = y;
			e.width = this.scaledWidth;
			e.height = tuningHeight;
			e.totalWidth = this.scaledWidth;
			e.totalHeight = totalHeight < 0 ? y + e.height : totalHeight;
			this.registerPartial(e, (canvas) => {
				canvas.color = res.scoreInfoColor;
				canvas.textAlign = TextAlign.Center;
				this.tuningGlyph.paint(0, 0, canvas);
			});
			this._preSystemPartialIds.push(e.id);
			return y + tuningHeight;
		}
		_layoutAndRenderChordDiagrams(y, totalHeight = -1) {
			if (!this.chordDiagrams) return y;
			const res = this.renderer.settings.display.resources;
			this.chordDiagrams.x = this.pagePadding[0];
			this.chordDiagrams.width = this.scaledWidth - this.pagePadding[0] - this.pagePadding[2];
			this.chordDiagrams.doLayout();
			const diagramHeight = Math.round(this.chordDiagrams.height);
			const e = new RenderFinishedEventArgs();
			e.x = 0;
			e.y = y;
			e.width = this.scaledWidth;
			e.height = diagramHeight;
			e.totalWidth = this.scaledWidth;
			e.totalHeight = totalHeight < 0 ? y + diagramHeight : totalHeight;
			this.registerPartial(e, (canvas) => {
				canvas.color = res.scoreInfoColor;
				canvas.textAlign = TextAlign.Center;
				this.chordDiagrams.paint(0, 0, canvas);
			});
			this._preSystemPartialIds.push(e.id);
			return y + diagramHeight;
		}
		_layoutAndRenderScoreInfo(y, totalHeight = -1) {
			Logger.debug(this.name, "Layouting score info");
			const e = new RenderFinishedEventArgs();
			e.x = 0;
			e.y = y;
			let infoHeight = 0;
			const res = this.renderer.settings.display.resources;
			const scoreInfoGlyphs = [];
			for (const [scoreElement, _notationElement] of ScoreLayout.headerElements.value) if (this.headerGlyphs.has(scoreElement)) {
				const glyph = this.headerGlyphs.get(scoreElement);
				glyph.y = infoHeight;
				this.alignScoreInfoGlyph(glyph);
				let lineHeight = glyph.font.size;
				if (scoreElement === ScoreSubElement.Words) {
					if (this.headerGlyphs.has(ScoreSubElement.Music)) {
						if (this.headerGlyphs.get(ScoreSubElement.Music).textAlign !== glyph.textAlign) lineHeight = 0;
					}
				}
				infoHeight += lineHeight;
				scoreInfoGlyphs.push(glyph);
			}
			if (scoreInfoGlyphs.length > 0) {
				infoHeight = Math.floor(infoHeight + 17);
				e.width = this.scaledWidth;
				e.height = infoHeight;
				e.totalWidth = this.scaledWidth;
				e.totalHeight = totalHeight < 0 ? y + e.height : totalHeight;
				this.registerPartial(e, (canvas) => {
					canvas.color = res.scoreInfoColor;
					canvas.textAlign = TextAlign.Center;
					for (const g of scoreInfoGlyphs) g.paint(0, 0, canvas);
				});
				this._preSystemPartialIds.push(e.id);
			}
			return y + infoHeight;
		}
		_resizeAndRenderScore(y, oldHeight) {
			const barsPerRowActive = this.getBarsPerSystem(0) > 0;
			this._systemPartialIds = [];
			if (barsPerRowActive) for (let i = 0; i < this._systems.length; i++) {
				const system = this._systems[i];
				system.width = system.computedWidth;
				this._fitSystem(system);
				y += this._paintSystem(system, oldHeight);
			}
			else {
				for (const r of this._allMasterBarRenderers) for (const b of r.renderers) b.afterReverted();
				this._systems = [];
				let currentIndex = 0;
				const maxWidth = this._maxWidth;
				let system = this.createEmptyStaffSystem(this._systems.length);
				system.x = this.pagePadding[0];
				system.y = y;
				while (currentIndex < this._allMasterBarRenderers.length) {
					let renderers = this._allMasterBarRenderers[currentIndex];
					if (system.width + renderers.width <= maxWidth || system.masterBarsRenderers.length === 0) {
						system.addMasterBarRenderers(this.renderer.tracks, renderers);
						currentIndex++;
						if (this._needsLineBreak(currentIndex)) system.isFull = true;
					} else {
						while (renderers && !renderers.canWrap && system.masterBarsRenderers.length > 1) {
							renderers = system.revertLastBar();
							currentIndex--;
						}
						system.isFull = true;
					}
					if (system.isFull) {
						system.isLast = this.lastBarIndex === system.lastBarIndex;
						this._systems.push(system);
						this._fitSystem(system);
						y += this._paintSystem(system, oldHeight);
						system = this.createEmptyStaffSystem(this._systems.length);
						system.x = this.pagePadding[0];
						system.y = y;
					}
				}
				system.isLast = this.lastBarIndex === system.lastBarIndex;
				this._fitSystem(system);
				y += this._paintSystem(system, oldHeight);
			}
			return y;
		}
		_layoutAndRenderScore(y, startIndex) {
			let currentBarIndex = startIndex;
			const endBarIndex = this.lastBarIndex;
			while (currentBarIndex <= endBarIndex) {
				const system = this._createStaffSystem(currentBarIndex, endBarIndex);
				this._systems.push(system);
				system.x = this.pagePadding[0];
				system.y = y;
				currentBarIndex = system.lastBarIndex + 1;
				this._fitSystem(system);
				Logger.debug(this.name, `Rendering partial from bar ${system.firstBarIndex} to ${system.lastBarIndex}`, null);
				y += this._paintSystem(system, y);
			}
			return y;
		}
		_paintSystem(system, totalHeight) {
			const height = Math.floor(system.height);
			const args = new RenderFinishedEventArgs();
			args.x = 0;
			args.y = system.y;
			args.totalWidth = this.scaledWidth;
			args.totalHeight = totalHeight;
			args.width = this.scaledWidth;
			args.height = height;
			args.firstMasterBarIndex = system.firstBarIndex;
			args.lastMasterBarIndex = system.lastBarIndex;
			system.buildBoundingsLookup(0, 0);
			this.registerPartial(args, (canvas) => {
				this.renderer.canvas.color = this.renderer.settings.display.resources.mainGlyphColor;
				this.renderer.canvas.textAlign = TextAlign.Left;
				system.paint(0, -(args.y / this.renderer.settings.display.scale), canvas);
			});
			this._systemPartialIds.push(args.id);
			return height;
		}
		/**
		* Realignes the bars in this line according to the available space
		*/
		_fitSystem(system) {
			system.reconcileMinDurationIfDirty();
			if (system.isFull || system.width > this._maxWidth || this.renderer.settings.display.justifyLastSystem) this._scaleToWidth(system, this._maxWidth);
			else this._scaleToWidth(system, system.width);
			system.finalizeSystem();
		}
		_scaleToWidth(system, width) {
			const staffWidth = width - system.accoladeWidth;
			const shouldApplyBarScale = this.shouldApplyBarScale;
			const weightTotal = shouldApplyBarScale ? system.totalBarDisplayScale : system.totalContentWidth;
			const distributable = Math.max(0, staffWidth - system.totalFixedOverhead);
			const contentShare = weightTotal > 0 ? distributable / weightTotal : 0;
			for (const s of system.allStaves) {
				s.resetSharedLayoutData();
				let w = 0;
				for (let i = 0; i < s.barRenderers.length; i++) {
					const renderer = s.barRenderers[i];
					const mb = system.masterBarsRenderers[i];
					renderer.x = w;
					renderer.y = s.topPadding + s.topOverflow;
					const weight = shouldApplyBarScale ? system.getBarDisplayScale(renderer) : mb.maxContentWidth;
					const actualBarWidth = mb.maxFixedOverhead + weight * contentShare;
					renderer.scaleToWidth(actualBarWidth);
					w += renderer.width;
				}
			}
			system.width = width;
		}
		_createStaffSystem(currentBarIndex, endIndex) {
			const system = this.createEmptyStaffSystem(this._systems.length);
			const barsPerRow = this.getBarsPerSystem(system.index);
			const maxWidth = this._maxWidth;
			const end = endIndex + 1;
			let barIndex = currentBarIndex;
			while (barIndex < end) {
				if (this._barsFromPreviousSystem.length > 0) for (const renderer of this._barsFromPreviousSystem) {
					system.addMasterBarRenderers(this.renderer.tracks, renderer);
					barIndex = renderer.lastMasterBarIndex;
				}
				else {
					const multiBarRestInfo = this.multiBarRestInfo;
					const additionalMultiBarsRestBarIndices = multiBarRestInfo !== null && multiBarRestInfo.has(barIndex) ? multiBarRestInfo.get(barIndex) : null;
					const renderers = system.addBars(this.renderer.tracks, barIndex, additionalMultiBarsRestBarIndices);
					this._allMasterBarRenderers.push(renderers);
					barIndex = renderers.lastMasterBarIndex;
				}
				this._barsFromPreviousSystem = [];
				let systemIsFull = false;
				if (barsPerRow === -1 && system.width >= maxWidth && system.masterBarsRenderers.length !== 0) systemIsFull = true;
				else if (system.masterBarsRenderers.length === barsPerRow + 1) systemIsFull = true;
				if (systemIsFull) {
					let reverted = system.revertLastBar();
					if (reverted) {
						this._barsFromPreviousSystem.push(reverted);
						while (reverted && !reverted.canWrap && system.masterBarsRenderers.length > 1) {
							reverted = system.revertLastBar();
							if (reverted) this._barsFromPreviousSystem.push(reverted);
						}
					}
					system.isFull = true;
					system.isLast = false;
					this._barsFromPreviousSystem.reverse();
					return system;
				}
				if (this._needsLineBreak(barIndex)) {
					system.isFull = true;
					system.isLast = false;
					return system;
				}
				system.x = 0;
				barIndex++;
			}
			system.isLast = endIndex === system.lastBarIndex;
			return system;
		}
		_needsLineBreak(barIndex) {
			let anyTrackNeedsLineBreak = false;
			let allTracksNeedLineBreak = true;
			for (const track of this.renderer.tracks) if (track.lineBreaks && track.lineBreaks.has(barIndex + 1)) anyTrackNeedsLineBreak = true;
			else allTracksNeedLineBreak = false;
			return anyTrackNeedsLineBreak && allTracksNeedLineBreak;
		}
		get _maxWidth() {
			return this.scaledWidth - this.pagePadding[0] - this.pagePadding[2];
		}
	};
	//#endregion
	//#region src/rendering/layout/PageViewLayout.ts
	/**
	* This layout arranges the bars into a fixed width and dynamic height region.
	* @internal
	*/
	var PageViewLayout = class extends VerticalLayoutBase {
		get name() {
			return "PageView";
		}
		getBarsPerSystem(systemIndex) {
			let barsPerRow = this.renderer.settings.display.barsPerRow;
			if (this.renderer.settings.display.systemsLayoutMode === SystemsLayoutMode.UseModelLayout) barsPerRow = ModelUtils.getSystemLayout(this.renderer.score, systemIndex, this.renderer.tracks);
			return barsPerRow;
		}
		get shouldApplyBarScale() {
			return this.renderer.settings.display.systemsLayoutMode === SystemsLayoutMode.UseModelLayout;
		}
	};
	//#endregion
	//#region src/rendering/layout/ParchmentLayout.ts
	/**
	* This layout arranges the bars into a fixed width and dynamic height region
	* respecting the systems layout specified in the data model.
	* @internal
	*/
	var ParchmentLayout = class extends VerticalLayoutBase {
		get name() {
			return "Parchment";
		}
		getBarsPerSystem(systemIndex) {
			return ModelUtils.getSystemLayout(this.renderer.score, systemIndex, this.renderer.tracks);
		}
		get shouldApplyBarScale() {
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BarLineGlyph.ts
	/**
	* @internal
	*/
	var BarLineGlyphBase = class extends Glyph {
		doLayout() {
			this.width = this.renderer.smuflMetrics.thinBarlineThickness;
		}
		paint(cx, cy, canvas) {
			this.paintExtended(cx, cy, canvas, this.height);
		}
	};
	/**
	* @internal
	*/
	var BarLineLightGlyph = class extends BarLineGlyphBase {
		_isRepeat;
		constructor(x, y, isRepeat) {
			super(x, y);
			this._isRepeat = isRepeat;
		}
		doLayout() {
			this.width = this._isRepeat ? this.renderer.smuflMetrics.repeatEndingLineThickness : this.renderer.smuflMetrics.thinBarlineThickness;
		}
		paintExtended(cx, cy, canvas, newHeight) {
			canvas.fillRect(cx + this.x, cy + this.y, this.renderer.smuflMetrics.thinBarlineThickness, newHeight);
		}
	};
	/**
	* @internal
	*/
	var BarLineDottedGlyph = class extends BarLineGlyphBase {
		paintExtended(cx, cy, canvas, newHeight) {
			const circleRadius = this.renderer.smuflMetrics.thinBarlineThickness / 2;
			const lineHeight = this.renderer.getLineHeight(1);
			let circleY = cy + this.y + lineHeight * .5 + circleRadius;
			const bottom = cy + this.y + newHeight;
			while (circleY < bottom) {
				canvas.fillCircle(cx + this.x, circleY, circleRadius);
				circleY += lineHeight;
			}
		}
	};
	/**
	* @internal
	*/
	var BarLineDashedGlyph = class extends BarLineGlyphBase {
		paintExtended(cx, cy, canvas, newHeight) {
			const dashSize = this.renderer.smuflMetrics.dashedBarlineDashLength;
			const x = cx + this.x - this.width / 2;
			const dashes = Math.ceil(newHeight / 2 / dashSize);
			const bottom = cy + this.y + newHeight;
			const dashGapLength = this.renderer.smuflMetrics.dashedBarlineGapLength;
			const lw = canvas.lineWidth;
			canvas.lineWidth = this.renderer.smuflMetrics.dashedBarlineThickness;
			canvas.beginPath();
			if (dashes < 1) {
				canvas.moveTo(x, cy + this.y);
				canvas.lineTo(x, bottom);
			} else {
				let dashY = cy + this.y;
				while (dashY < bottom) {
					canvas.moveTo(x, dashY);
					const remaining = Math.min(bottom - dashY, dashSize);
					canvas.lineTo(x, dashY + remaining);
					dashY += dashSize + dashGapLength;
				}
			}
			canvas.stroke();
			canvas.lineWidth = lw;
		}
	};
	/**
	* @internal
	*/
	var BarLineHeavyGlyph = class extends BarLineGlyphBase {
		doLayout() {
			this.width = this.renderer.smuflMetrics.thickBarlineThickness;
		}
		paintExtended(cx, cy, canvas, newHeight) {
			canvas.fillRect(cx + this.x, cy + this.y, this.width, newHeight);
		}
	};
	/**
	* @internal
	*/
	var BarLineRepeatDotsGlyph = class extends BarLineGlyphBase {
		doLayout() {
			this.width = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.RepeatDot);
		}
		paintExtended(cx, cy, canvas, _newHeight) {
			const renderer = this.renderer;
			const lineOffset = renderer.heightLineCount % 2 === 0 ? 1 : .5;
			const exactCenter = cy + this.y + this.height / 2;
			const lineHeight = renderer.getLineHeight(lineOffset);
			const dotOffset = renderer.smuflMetrics.glyphTop.get(MusicFontSymbol.RepeatDot) - renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.RepeatDot) / 2;
			CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, exactCenter + dotOffset - lineHeight, 1, MusicFontSymbol.RepeatDot);
			CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, exactCenter + dotOffset + lineHeight, 1, MusicFontSymbol.RepeatDot);
		}
	};
	/**
	* @internal
	*/
	var BarLineShortGlyph = class extends BarLineGlyphBase {
		paintExtended(cx, cy, canvas, _newHeight) {
			const renderer = this.renderer;
			if (renderer.drawnLineCount - 1 <= 2) return;
			const padding = renderer.smuflMetrics.staffLineThickness / 2;
			const centerLine = (renderer.drawnLineCount - 1) / 2;
			const top = renderer.getLineY(centerLine - 1) - padding;
			const bottom = renderer.getLineY(centerLine + 1) + padding;
			canvas.fillRect(cx + this.x, cy + top, renderer.smuflMetrics.thinBarlineThickness, bottom - top);
		}
	};
	/**
	* @internal
	*/
	var BarLineTickGlyph = class extends BarLineGlyphBase {
		paintExtended(cx, cy, canvas, _newHeight) {
			const lineHeight = this.renderer.getLineHeight(1);
			const lineY = -(lineHeight / 2) + 1;
			canvas.fillRect(cx + this.x, cy + this.y + lineY, 1, lineHeight);
		}
	};
	/**
	* @internal
	*/
	var BarLineGlyph = class extends LeftToRightLayoutingGlyphGroup {
		_isRight;
		_extendToNextStaff;
		constructor(isRight, extendToNextStaff) {
			super();
			this._isRight = isRight;
			this._extendToNextStaff = extendToNextStaff;
		}
		doLayout() {
			const bar = this.renderer.bar;
			const masterBar = bar.masterBar;
			const actualLineType = this._isRight ? bar.getActualBarLineRight() : bar.getActualBarLineLeft(this.renderer.index === 0);
			const isRepeatHeavy = this._isRight && masterBar.isRepeatEnd || !this._isRight && masterBar.isRepeatStart;
			let previousLineType = BarLineStyle.Automatic;
			if (!this._isRight) {
				const previousRenderer = this.renderer.previousRenderer;
				if (previousRenderer && previousRenderer.staff === this.renderer.staff) {
					previousLineType = previousRenderer.bar.getActualBarLineRight();
					if (actualLineType === previousLineType) return;
				}
			}
			if (this._isRight) {
				if (masterBar.isRepeatEnd) {
					this.addGlyph(new BarLineRepeatDotsGlyph(0, 0));
					this.width += this.renderer.smuflMetrics.repeatBarlineDotSeparation;
				}
			}
			switch (actualLineType) {
				case BarLineStyle.Dashed:
					this.addGlyph(new BarLineDashedGlyph(0, 0));
					break;
				case BarLineStyle.Dotted:
					this.addGlyph(new BarLineDottedGlyph(0, 0));
					break;
				case BarLineStyle.Heavy:
					if (previousLineType !== BarLineStyle.LightHeavy && previousLineType !== BarLineStyle.HeavyHeavy) this.addGlyph(new BarLineHeavyGlyph(0, 0));
					break;
				case BarLineStyle.HeavyHeavy:
					if (previousLineType !== BarLineStyle.LightHeavy && previousLineType !== BarLineStyle.Heavy) this.addGlyph(new BarLineHeavyGlyph(0, 0));
					this.width += this.renderer.smuflMetrics.barlineSeparation;
					this.addGlyph(new BarLineHeavyGlyph(0, 0));
					break;
				case BarLineStyle.HeavyLight:
					if (previousLineType !== BarLineStyle.LightHeavy && previousLineType !== BarLineStyle.Heavy && previousLineType !== BarLineStyle.HeavyHeavy) this.addGlyph(new BarLineHeavyGlyph(0, 0));
					this.width += this.renderer.smuflMetrics.thinThickBarlineSeparation;
					this.addGlyph(new BarLineLightGlyph(0, 0, isRepeatHeavy));
					break;
				case BarLineStyle.LightHeavy:
					if (previousLineType !== BarLineStyle.HeavyLight && previousLineType !== BarLineStyle.Regular && previousLineType !== BarLineStyle.LightLight) this.addGlyph(new BarLineLightGlyph(0, 0, isRepeatHeavy));
					this.width += this.renderer.smuflMetrics.thinThickBarlineSeparation;
					this.addGlyph(new BarLineHeavyGlyph(0, 0));
					break;
				case BarLineStyle.LightLight:
					if (previousLineType !== BarLineStyle.HeavyLight && previousLineType !== BarLineStyle.Regular) this.addGlyph(new BarLineLightGlyph(0, 0, isRepeatHeavy));
					this.width += this.renderer.smuflMetrics.barlineSeparation;
					this.addGlyph(new BarLineLightGlyph(0, 0, isRepeatHeavy));
					break;
				case BarLineStyle.None: break;
				case BarLineStyle.Regular:
					if (previousLineType !== BarLineStyle.HeavyLight && previousLineType !== BarLineStyle.LightLight) this.addGlyph(new BarLineLightGlyph(0, 0, isRepeatHeavy));
					break;
				case BarLineStyle.Short:
					this.addGlyph(new BarLineShortGlyph(0, 0));
					break;
				case BarLineStyle.Tick:
					this.addGlyph(new BarLineTickGlyph(0, 0));
					break;
			}
			if (!this._isRight) {
				if (masterBar.isRepeatStart) {
					this.width += this.renderer.smuflMetrics.repeatBarlineDotSeparation;
					this.addGlyph(new BarLineRepeatDotsGlyph(0, 0));
				}
			}
			const lineRenderer = this.renderer;
			const lineYOffset = lineRenderer.smuflMetrics.staffLineThickness;
			let top = this.y;
			let bottom = this.y;
			if (lineRenderer.drawnLineCount < 2 || !this._isRight && lineRenderer.isFirstOfStaff || this._isRight && lineRenderer.isLastOfStaff) {
				top -= lineYOffset;
				bottom += lineRenderer.height;
			} else {
				top += lineRenderer.getLineY(0) - lineYOffset / 2;
				bottom += lineRenderer.getLineY(lineRenderer.drawnLineCount - 1) + lineYOffset / 2;
			}
			const h = bottom - top;
			let xShift = 0;
			if (this._extendToNextStaff && this._isRight) {
				const fullWidth = Math.ceil(this.width);
				xShift = fullWidth - this.width;
				this.width = fullWidth;
			}
			for (const g of this.glyphs) {
				g.y = top;
				g.x += xShift;
				g.height = h;
			}
		}
		paint(cx, cy, canvas) {
			const lines = this.glyphs;
			if (!lines) return;
			const renderer = this.renderer;
			const _ = ElementStyleHelper.bar(canvas, renderer.barLineBarSubElement, this.renderer.bar, true);
			try {
				let actualLineHeight = this.height;
				const thisStaff = renderer.staff;
				const allStaves = thisStaff.system.allStaves;
				let isExtended = false;
				if (this._extendToNextStaff && thisStaff.index < allStaves.length - 1) {
					const nextStaff = allStaves[thisStaff.index + 1];
					const lineTop = thisStaff.y + renderer.y;
					actualLineHeight = nextStaff.y + nextStaff.topOverflow + renderer.smuflMetrics.staffLineThickness - lineTop;
					isExtended = true;
				}
				for (const line of lines) if (isExtended) line.paintExtended(cx, cy, canvas, actualLineHeight);
				else line.paint(cx, cy, canvas);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BarNumberGlyph.ts
	/**
	* @internal
	*/
	var BarNumberGlyph = class extends Glyph {
		_number;
		constructor(x, y, num) {
			super(x, y);
			this._number = `${num}  `;
		}
		doLayout() {
			this.renderer.scoreRenderer.canvas.font = this.renderer.resources.elementFonts.get(NotationElement.BarNumber);
			const size = this.renderer.scoreRenderer.canvas.measureText(this._number);
			this.width = size.width;
			this.height = size.height;
			this.y -= this.height;
		}
		paint(cx, cy, canvas) {
			if (!this.renderer.staff.isFirstInSystem) return;
			const _ = ElementStyleHelper.bar(canvas, this.renderer.barNumberBarSubElement, this.renderer.bar, true);
			try {
				const res = this.renderer.resources;
				const baseline = canvas.textBaseline;
				canvas.font = res.elementFonts.get(NotationElement.BarNumber);
				canvas.textBaseline = TextBaseline.Top;
				canvas.fillText(this._number, cx + this.x, cy + this.y);
				canvas.textBaseline = baseline;
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NumberedTieGlyph.ts
	/**
	* @internal
	*/
	var NumberedTieGlyph = class extends NoteTieGlyph {
		shouldDrawBendSlur() {
			return this.renderer.settings.notation.extendBendArrowsOnTiedNotes && !!this.startNote.bendOrigin && this.startNote.isTieOrigin;
		}
		calculateTieDirection() {
			return BeamDirection.Up;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/AccidentalGroupGlyph.ts
	/**
	* @internal
	*/
	var AccidentalColumnInfo = class {
		x = 0;
		y = -3e3;
		width = 0;
	};
	/**
	* @internal
	*/
	var AccidentalGroupGlyph = class extends GlyphGroup {
		constructor() {
			super(0, 0);
		}
		doLayout() {
			if (!this.glyphs || this.glyphs.length === 0) {
				this.width = 0;
				return;
			}
			this.glyphs.sort((a, b) => {
				if (a.y < b.y) return -1;
				if (a.y > b.y) return 1;
				return 0;
			});
			const columns = [];
			columns.push(new AccidentalColumnInfo());
			for (let i = 0, j = this.glyphs.length; i < j; i++) {
				const g = this.glyphs[i];
				g.renderer = this.renderer;
				g.doLayout();
				let gColumn = 0;
				while (columns[gColumn].y > g.y) {
					gColumn++;
					if (gColumn === columns.length) columns.push(new AccidentalColumnInfo());
				}
				g.x = gColumn;
				columns[gColumn].y = g.y + g.height;
				if (columns[gColumn].width < g.width) columns[gColumn].width = g.width;
			}
			this.width = 0;
			const padding = this.renderer.smuflMetrics.accidentalPadding;
			for (const column of columns) {
				this.width += column.width + padding;
				column.x = this.width;
			}
			for (let i = 0, j = this.glyphs.length; i < j; i++) {
				const g = this.glyphs[i];
				const column = columns[g.x];
				g.x = this.width - column.x;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/AugmentationDotGlyph.ts
	/**
	* @internal
	*/
	var AugmentationDotGlyph = class extends MusicFontGlyph {
		constructor(x, y) {
			super(x, y, 1, MusicFontSymbol.AugmentationDot);
		}
		doLayout() {
			super.doLayout();
			this.offsetX = this.width / 2;
			this.width *= 1.5;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BeatGlyphBase.ts
	/**
	* @internal
	*/
	var BeatGlyphBase = class extends GlyphGroup {
		_effectGlyphs = [];
		_normalGlyphs = [];
		container;
		computedWidth = 0;
		constructor() {
			super(0, 0);
		}
		doLayout() {
			let w = 0;
			if (this.glyphs) for (let i = 0, j = this.glyphs.length; i < j; i++) {
				const g = this.glyphs[i];
				g.x = w;
				g.renderer = this.renderer;
				g.doLayout();
				w += g.width;
			}
			this.width = w;
			this.computedWidth = w;
		}
		noteLoop(action) {
			for (let i = this.container.beat.notes.length - 1; i >= 0; i--) action(this.container.beat.notes[i]);
		}
		addEffect(g) {
			super.addGlyph(g);
			this._effectGlyphs.push(g);
		}
		addNormal(g) {
			super.addGlyph(g);
			this._normalGlyphs.push(g);
		}
		get effectElement() {}
		paint(cx, cy, canvas) {
			this._paintEffects(cx, cy, canvas);
			this._paintNormal(cx, cy, canvas);
		}
		_paintNormal(cx, cy, canvas) {
			for (const g of this._normalGlyphs) g.paint(cx + this.x, cy + this.y, canvas);
		}
		_paintEffects(cx, cy, canvas) {
			try {
				var _usingCtx$3 = _usingCtx();
				_usingCtx$3.u(this.effectElement ? ElementStyleHelper.beat(canvas, this.effectElement, this.container.beat) : void 0);
				for (const g of this._effectGlyphs) g.paint(cx + this.x, cy + this.y, canvas);
			} catch (_) {
				_usingCtx$3.e = _;
			} finally {
				_usingCtx$3.d();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BeatOnNoteGlyphBase.ts
	/**
	* @internal
	*/
	var BeatOnNoteGlyphBase = class extends BeatGlyphBase {
		onTimeX = 0;
		middleX = 0;
		stemX = 0;
	};
	//#endregion
	//#region src/rendering/glyphs/DeadSlappedBeatGlyph.ts
	/**
	* @internal
	*/
	var DeadSlappedBeatGlyph = class extends Glyph {
		_topY = 0;
		constructor() {
			super(0, 0);
		}
		getBoundingBoxTop() {
			return this._topY;
		}
		getBoundingBoxBottom() {
			return this._topY + this.height;
		}
		doLayout() {
			this.width = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.NoteheadSlashWhiteHalf);
			const renderer = this.renderer;
			const crossHeight = renderer.getLineHeight(renderer.heightLineCount - 1);
			const topY = renderer.getLineY(0) + (renderer.drawnLineCount > 0 ? renderer.getLineHeight(renderer.drawnLineCount - 1) : 0) / 2 - crossHeight / 2;
			this.height = crossHeight;
			this._topY = topY;
		}
		paint(cx, cy, canvas) {
			const crossHeight = this.height;
			const topY = this._topY;
			const lw = canvas.lineWidth;
			canvas.lineWidth = this.renderer.smuflMetrics.deadSlappedLineWidth;
			canvas.moveTo(cx + this.x, cy + topY);
			canvas.lineTo(cx + this.x + this.width, cy + topY + crossHeight);
			canvas.moveTo(cx + this.x, cy + topY + crossHeight);
			canvas.lineTo(cx + this.x + this.width, cy + topY);
			canvas.stroke();
			canvas.lineWidth = lw;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NumberedNoteHeadGlyph.ts
	/**
	* @internal
	*/
	var NumberedNoteHeadGlyph = class extends Glyph {
		_isGrace;
		_beat;
		_number;
		_octaveDots;
		_octaveDotsY = 0;
		_octaveDotHeight = 0;
		constructor(x, y, number, isGrace, beat, octaveDots) {
			super(x, y);
			this._isGrace = isGrace;
			this._number = number;
			this._beat = beat;
			this._octaveDots = octaveDots;
		}
		getBoundingBoxTop() {
			let y = -this.height / 2;
			if (this._octaveDots > 0 && this._octaveDotsY < y) y = this._octaveDotsY;
			return this.y + y;
		}
		getBoundingBoxBottom() {
			let y = this.height / 2;
			const dotsBottom = this._octaveDotsY + Math.abs(this._octaveDots) * this._octaveDotHeight * 2;
			if (this._octaveDots < 0 && y < dotsBottom) y = dotsBottom;
			return this.y + y;
		}
		paint(cx, cy, canvas) {
			try {
				var _usingCtx$2 = _usingCtx();
				_usingCtx$2.u(this._beat.isRest ? ElementStyleHelper.beat(canvas, BeatSubElement.NumberedRests, this._beat) : this._beat.notes.length > 0 ? ElementStyleHelper.note(canvas, NoteSubElement.NumberedNumber, this._beat.notes[0]) : void 0);
				const res = this.renderer.resources;
				canvas.font = this._isGrace ? res.numberedNotationGraceFont : res.numberedNotationFont;
				const baseline = canvas.textBaseline;
				canvas.textBaseline = TextBaseline.Middle;
				canvas.textAlign = TextAlign.Left;
				canvas.fillText(this._number.toString(), cx + this.x, cy + this.y);
				canvas.textBaseline = baseline;
				const dotCount = Math.abs(this._octaveDots);
				let dotsY = this._octaveDotsY + res.engravingSettings.glyphTop.get(MusicFontSymbol.AugmentationDot);
				for (let d = 0; d < dotCount; d++) {
					CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + this.width / 2, cy + this.y + dotsY, 1, MusicFontSymbol.AugmentationDot, true);
					dotsY += this._octaveDotHeight * 2;
				}
			} catch (_) {
				_usingCtx$2.e = _;
			} finally {
				_usingCtx$2.d();
			}
		}
		doLayout() {
			const res = this.renderer.resources;
			const font = this._isGrace ? res.numberedNotationGraceFont : res.numberedNotationFont;
			const c = this.renderer.scoreRenderer.canvas;
			c.font = font;
			const size = c.measureText(`${this._number}`);
			this.height = size.height;
			this.width = size.width;
			const dotCount = this._octaveDots;
			const dotHeight = res.engravingSettings.glyphHeights.get(MusicFontSymbol.AugmentationDot);
			const allDotsHeight = Math.abs(dotCount) * dotHeight * 2;
			if (dotCount > 0) this._octaveDotsY = -(this.height / 2) - allDotsHeight - res.engravingSettings.glyphTop.get(MusicFontSymbol.AugmentationDot);
			else if (dotCount < 0) this._octaveDotsY = this.height / 2 + dotHeight + res.engravingSettings.glyphTop.get(MusicFontSymbol.AugmentationDot);
			this._octaveDotHeight = dotHeight;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/SpacingGlyph.ts
	/**
	* This simple glyph allows to put an empty region in to a BarRenderer.
	* @internal
	*/
	var SpacingGlyph = class extends Glyph {
		constructor(x, y, width) {
			super(x, y);
			this.width = width;
		}
		getBoundingBoxTop() {
			return NaN;
		}
		getBoundingBoxBottom() {
			return NaN;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NumberedBeatGlyph.ts
	/**
	* @internal
	*/
	var NumberedBeatPreNotesGlyph = class extends BeatGlyphBase {
		accidental = AccidentalType.None;
		skipLayout = false;
		get effectElement() {
			return BeatSubElement.NumberedEffects;
		}
		doLayout() {
			if (this.skipLayout) return;
			if (!this.container.beat.isRest && !this.container.beat.isEmpty) {
				const accidentals = new AccidentalGroupGlyph();
				accidentals.renderer = this.renderer;
				if (this.container.beat.notes.length > 0) {
					const note = this.container.beat.notes[0];
					const spelling = ModelUtils.resolveSpelling(this.renderer.bar.keySignature, note.displayValue, note.accidentalMode);
					const ksOffset = ModelUtils.getKeySignatureAccidentalOffset(this.renderer.bar.keySignature, spelling.degree);
					const requiredOffset = spelling.accidentalOffset - ksOffset;
					let accidentalToSet = AccidentalType.None;
					if (note.accidentalMode !== NoteAccidentalMode.ForceNone) {
						if (note.hasQuarterToneOffset) if (requiredOffset > 0) accidentalToSet = AccidentalType.SharpQuarterNoteUp;
						else if (requiredOffset < 0) accidentalToSet = AccidentalType.FlatQuarterNoteUp;
						else accidentalToSet = AccidentalType.NaturalQuarterNoteUp;
						else if (requiredOffset !== 0) accidentalToSet = ModelUtils.accidentalOffsetToType(requiredOffset);
					}
					if (accidentalToSet !== AccidentalType.None) {
						this.accidental = accidentalToSet;
						const sr = this.renderer;
						const color = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.NumberedAccidentals, note);
						const g = new AccidentalGlyph(0, sr.getLineY(0), accidentalToSet, note.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale * EngravingSettings.GraceScale : EngravingSettings.GraceScale);
						g.colorOverride = color;
						g.renderer = this.renderer;
						accidentals.addGlyph(g);
						this.addNormal(accidentals);
						this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding));
					}
				}
			}
			super.doLayout();
		}
	};
	/**
	* @internal
	*/
	var NumberedBeatGlyph = class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
		noteHeads = null;
		deadSlapped = null;
		get effectElement() {
			return BeatSubElement.NumberedEffects;
		}
		getNoteX(_note, requestedPosition) {
			let g = null;
			if (this.noteHeads) g = this.noteHeads;
			else if (this.deadSlapped) g = this.deadSlapped;
			if (g) {
				let pos = g.x;
				switch (requestedPosition) {
					case NoteXPosition.Left: break;
					case NoteXPosition.Center:
						pos += g.width / 2;
						break;
					case NoteXPosition.Right:
						pos += g.width;
						break;
				}
				return pos;
			}
			return 0;
		}
		buildBoundingsLookup(beatBounds, cx, cy) {
			if (this.noteHeads && this.container.beat.notes.length > 0) {
				const noteBounds = new NoteBounds();
				noteBounds.note = this.container.beat.notes[0];
				noteBounds.noteHeadBounds = new Bounds();
				noteBounds.noteHeadBounds.x = cx + this.x + this.noteHeads.x;
				noteBounds.noteHeadBounds.y = cy + this.y + this.noteHeads.y - this.noteHeads.height / 2;
				noteBounds.noteHeadBounds.w = this.width;
				noteBounds.noteHeadBounds.h = this.height;
				beatBounds.addNote(noteBounds);
			}
		}
		getLowestNoteY(requestedPosition) {
			return this._internalGetNoteY(requestedPosition);
		}
		getHighestNoteY(requestedPosition) {
			return this._internalGetNoteY(requestedPosition);
		}
		getNoteY(_note, requestedPosition) {
			return this._internalGetNoteY(requestedPosition);
		}
		getRestY(requestedPosition) {
			return this._internalGetNoteY(requestedPosition);
		}
		_internalGetNoteY(requestedPosition) {
			let g = null;
			if (this.noteHeads) g = this.noteHeads;
			else if (this.deadSlapped) g = this.deadSlapped;
			if (g) {
				let pos = this.y + g.y;
				switch (requestedPosition) {
					case NoteYPosition.Top:
					case NoteYPosition.TopWithStem:
						pos -= g.height / 2;
						break;
					case NoteYPosition.Center: break;
					case NoteYPosition.Bottom:
					case NoteYPosition.BottomWithStem:
						pos += g.height / 2;
						break;
					case NoteYPosition.StemUp:
					case NoteYPosition.StemDown: break;
				}
				return pos;
			}
			return 0;
		}
		static _majorKeySignatureOneValues = [
			59,
			66,
			61,
			68,
			63,
			70,
			65,
			60,
			67,
			62,
			69,
			64,
			71,
			66,
			61
		];
		static _minorKeySignatureOneValues = [
			68,
			63,
			70,
			65,
			60,
			67,
			62,
			69,
			64,
			71,
			66,
			61,
			68,
			63,
			70
		];
		doLayout() {
			const sr = this.renderer;
			if (sr.shortestDuration < this.container.beat.duration) sr.shortestDuration = this.container.beat.duration;
			let octaveDots = 0;
			if (!this.container.beat.isEmpty) {
				const glyphY = sr.getLineY(0);
				let numberWithinOctave = "0";
				if (this.container.beat.notes.length > 0) {
					const note = this.container.beat.notes[0];
					if (note.isDead) numberWithinOctave = "X";
					else {
						const ks = this.renderer.bar.keySignature;
						const kst = this.renderer.bar.keySignatureType;
						const ksi = ks + 7;
						const oneNoteValue = (kst === KeySignatureType.Minor ? NumberedBeatGlyph._minorKeySignatureOneValues : NumberedBeatGlyph._majorKeySignatureOneValues)[ksi];
						const spelling = ModelUtils.resolveSpelling(ks, note.displayValue, note.accidentalMode);
						const tonicDegree = ModelUtils.getKeySignatureTonicDegree(ks, kst);
						const effectiveTonic = kst === KeySignatureType.Minor ? (tonicDegree + 2) % 7 : tonicDegree;
						numberWithinOctave = ((spelling.degree - effectiveTonic + 7) % 7 + 1).toString();
						const noteValue = note.displayValue - oneNoteValue;
						octaveDots = Math.floor(noteValue / 12);
					}
				}
				if (this.container.beat.deadSlapped) {
					const deadSlapped = new DeadSlappedBeatGlyph();
					deadSlapped.renderer = this.renderer;
					deadSlapped.doLayout();
					this.deadSlapped = deadSlapped;
					this.addEffect(deadSlapped);
				} else {
					const isGrace = this.container.beat.graceType !== GraceType.None;
					const noteHeadGlyph = new NumberedNoteHeadGlyph(0, glyphY, numberWithinOctave, isGrace, this.container.beat, octaveDots);
					this.noteHeads = noteHeadGlyph;
					this.addNormal(noteHeadGlyph);
				}
				if (this.container.beat.dots > 0 && this.container.beat.duration >= Duration.Quarter) for (let i = 0; i < this.container.beat.dots; i++) {
					const dot = new AugmentationDotGlyph(0, glyphY);
					dot.renderer = this.renderer;
					this.addEffect(dot);
				}
			}
			super.doLayout();
			if (this.container.beat.isEmpty) this.onTimeX = this.width / 2;
			else if (this.noteHeads) this.onTimeX = this.noteHeads.x + this.noteHeads.width / 2;
			else if (this.deadSlapped) this.onTimeX = this.deadSlapped.x + this.deadSlapped.width / 2;
			this.middleX = this.onTimeX;
			this.stemX = this.middleX;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabTieGlyph.ts
	/**
	* @internal
	*/
	var TabTieGlyph = class TabTieGlyph extends NoteTieGlyph {
		calculateTieDirection() {
			if (this.isLeftHandTap) return BeamDirection.Up;
			return TabTieGlyph.getBeamDirectionForNote(this.startNote);
		}
		static getBeamDirectionForNote(note) {
			return note.string > 3 ? BeamDirection.Up : BeamDirection.Down;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TieGlyphLabel.ts
	/**
	* Helpers for building `TieGlyphLabel` instances from model-side
	* {@link SlurSegment}s.
	* @internal
	*/
	var TieGlyphLabels = class {
		/**
		* Builds a `TieGlyphLabel` for one segment of a slur. The
		* `isAscending` flag selects between the H/P glyph for hammer-on
		* vs. pull-off — score side passes a comparison on `realValue`,
		* tab side passes a comparison on `fret`.
		*/
		static build(s, isAscending) {
			if (s.kind === SlurSegmentKind.LegatoSlide) return {
				fromNote: s.fromNote,
				toNote: s.toNote,
				text: s.text !== null ? s.text : "sl.",
				element: NotationElement.EffectSlideText
			};
			return {
				fromNote: s.fromNote,
				toNote: s.toNote,
				text: s.text !== null ? s.text : isAscending ? "H" : "P",
				element: NotationElement.EffectHammerOnPullOffText
			};
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabSlurGlyph.ts
	/**
	* @internal
	*/
	var TabSlurGlyph = class extends TabTieGlyph {
		_forSlide;
		_labels = null;
		constructor(slurEffectId, startNote, endNote, forSlide, forEnd) {
			super(slurEffectId, startNote, endNote, forEnd);
			this._forSlide = forSlide;
		}
		getTieHeight(startX, _startY, endX, _endY) {
			return Math.log(endX - startX + 1) * this.renderer.settings.notation.slurHeight / 2;
		}
		getSlurLabels() {
			if (this._labels === null) {
				this._labels = [];
				const slur = this.startNote.effectSlur;
				if (slur !== null) {
					const notationSettings = this.renderer.settings.notation;
					for (const s of slur.segments) {
						const label = TieGlyphLabels.build(s, s.toNote.fret >= s.fromNote.fret);
						if (notationSettings.isNotationElementVisible(label.element)) this._labels.push(label);
					}
				}
			}
			return this._labels.length > 0 ? this._labels : null;
		}
		tryExpand(startNote, endNote, forSlide, forEnd) {
			if (this._forSlide !== forSlide) return false;
			if (this.startNote.beat.id !== startNote.beat.id) return false;
			if (this.endNote.beat.id !== endNote.beat.id) return false;
			if (this.renderer === this.lookupEndBeatRenderer() !== forEnd) return false;
			if (this.tieDirection !== TabTieGlyph.getBeamDirectionForNote(startNote)) return false;
			switch (this.tieDirection) {
				case BeamDirection.Up:
					if (startNote.realValue > this.startNote.realValue) {
						this.startNote = startNote;
						this._labels = null;
					}
					if (endNote.realValue > this.endNote.realValue) this.endNote = endNote;
					break;
				case BeamDirection.Down:
					if (startNote.realValue < this.startNote.realValue) {
						this.startNote = startNote;
						this._labels = null;
					}
					if (endNote.realValue < this.endNote.realValue) this.endNote = endNote;
					break;
			}
			return true;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NumberedSlurGlyph.ts
	/**
	* @internal
	*/
	var NumberedSlurGlyph = class extends TabSlurGlyph {
		calculateTieDirection() {
			return BeamDirection.Up;
		}
	};
	//#endregion
	//#region src/rendering/NumberedBeatContainerGlyph.ts
	/**
	* @internal
	*/
	var NumberedBeatContainerGlyph = class extends BeatContainerGlyph {
		_slurs = /* @__PURE__ */ new Map();
		_effectSlurs = [];
		_dashes;
		hasAdditionalNumbers = false;
		*iterateAdditionalNumbers() {
			const dashes = this._dashes;
			if (!dashes) return;
			for (const d of dashes) if (d instanceof NumberedNoteBeatContainerGlyphBase) yield d;
		}
		constructor(beat) {
			super(beat);
			this.preNotes = new NumberedBeatPreNotesGlyph();
			this.onNotes = new NumberedBeatGlyph();
		}
		addDash(dash) {
			let dashes = this._dashes;
			if (!dashes) {
				dashes = [];
				this._dashes = dashes;
			}
			dashes.push(dash);
		}
		addNotes(dash) {
			let dashes = this._dashes;
			if (!dashes) {
				dashes = [];
				this._dashes = dashes;
			}
			dashes.push(dash);
			this.hasAdditionalNumbers = true;
		}
		doLayout() {
			this._slurs.clear();
			this._effectSlurs = [];
			super.doLayout();
		}
		buildBoundingsLookup(barBounds, cx, cy) {
			super.buildBoundingsLookup(barBounds, cx, cy);
			const dashes = this._dashes;
			if (dashes) {
				const beatBounds = barBounds.beats[barBounds.beats.length - 1];
				const lastDash = dashes[dashes.length - 1];
				const visualEndX = lastDash.x + lastDash.contentWidth;
				beatBounds.visualBounds.w = visualEndX - beatBounds.visualBounds.x;
				const realEnd = lastDash.x + lastDash.width;
				beatBounds.realBounds.w = realEnd - beatBounds.realBounds.x;
			}
		}
		createTies(n) {
			if (!n.isVisible) return;
			if (n.isTieOrigin && n.tieDestination.isVisible && !this._slurs.has("numbered.tie")) {
				const tie = new NumberedTieGlyph(`numbered.tie.${n.beat.id}`, n, n.tieDestination, false);
				this.addTie(tie);
				this._slurs.set(tie.slurEffectId, tie);
			}
			if (n.isTieDestination) {
				const tie = new NumberedTieGlyph(`numbered.tie.${n.tieOrigin.beat.id}`, n.tieOrigin, n, true);
				this.addTie(tie);
			}
			if (n.isLeftHandTapped && !n.isHammerPullDestination && !this._slurs.has(`numbered.tie.leftHandTap.${n.beat.id}`)) {
				const tapSlur = new NumberedTieGlyph(`numbered.tie.leftHandTap.${n.beat.id}`, n, n, false);
				this.addTie(tapSlur);
				this._slurs.set(tapSlur.slurEffectId, tapSlur);
			}
			if (n.isEffectSlurOrigin && n.effectSlurDestination) {
				let expanded = false;
				for (const slur of this._effectSlurs) if (slur.tryExpand(n, n.effectSlurDestination, false, false)) {
					expanded = true;
					break;
				}
				if (!expanded) {
					const effectSlur = new NumberedSlurGlyph(`numbered.slur.effect`, n, n.effectSlurDestination, false, false);
					this._effectSlurs.push(effectSlur);
					this.addTie(effectSlur);
					this._slurs.set(effectSlur.slurEffectId, effectSlur);
					this._slurs.set("numbered.slur.effect", effectSlur);
				}
			}
			if (n.isEffectSlurDestination && n.effectSlurOrigin) {
				let expanded = false;
				for (const slur of this._effectSlurs) if (slur.tryExpand(n.effectSlurOrigin, n, false, true)) {
					expanded = true;
					break;
				}
				if (!expanded) {
					const effectSlur = new NumberedSlurGlyph(`numbered.slur.effect`, n.effectSlurOrigin, n, false, true);
					this._effectSlurs.push(effectSlur);
					this.addTie(effectSlur);
					this._slurs.set(effectSlur.slurEffectId, effectSlur);
					this._slurs.set("numbered.slur.effect", effectSlur);
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NumberedDashBeatContainerGlyph.ts
	/**
	* @internal
	*/
	var NumberedNoteBeatContainerGlyphBase = class NumberedNoteBeatContainerGlyphBase extends NumberedBeatContainerGlyph {
		_absoluteDisplayStart;
		_displayDuration;
		constructor(beat, absoluteDisplayStart, displayDuration) {
			super(beat);
			this._absoluteDisplayStart = absoluteDisplayStart;
			this._displayDuration = displayDuration;
			this.preNotes.skipLayout = true;
			this.barCount = NumberedNoteBeatContainerGlyphBase._ticksToBarCount(displayDuration);
		}
		static _ticksToBarCount(displayDuration) {
			if (displayDuration >= MidiUtils.toTicks(Duration.Eighth)) return 1;
			else if (displayDuration >= MidiUtils.toTicks(Duration.Sixteenth)) return 2;
			else if (displayDuration >= MidiUtils.toTicks(Duration.ThirtySecond)) return 3;
			else if (displayDuration >= MidiUtils.toTicks(Duration.SixtyFourth)) return 4;
			else if (displayDuration >= MidiUtils.toTicks(Duration.OneHundredTwentyEighth)) return 5;
			else if (displayDuration >= MidiUtils.toTicks(Duration.TwoHundredFiftySixth)) return 6;
			return 0;
		}
		barCount;
		get beatId() {
			return -1;
		}
		get contentWidth() {
			return this.onNotes.width;
		}
		get absoluteDisplayStart() {
			return this._absoluteDisplayStart;
		}
		get displayDuration() {
			return this._displayDuration;
		}
		get graceType() {
			return GraceType.None;
		}
		get graceIndex() {
			return 0;
		}
		get graceGroup() {
			return null;
		}
		get isFirstOfTupletGroup() {
			return false;
		}
		get tupletGroup() {
			return null;
		}
		get isLastOfVoice() {
			return false;
		}
		buildBoundingsLookup(_barBounds, _cx, _cy) {}
	};
	/**
	* @internal
	*/
	var NumberedDashBeatContainerGlyph = class extends BeatContainerGlyphBase {
		_absoluteDisplayStart;
		_voiceIndex;
		constructor(voiceIndex, absoluteDisplayStart) {
			super(0, 0);
			this._absoluteDisplayStart = absoluteDisplayStart;
			this._voiceIndex = voiceIndex;
		}
		get beatId() {
			return -1;
		}
		get contentWidth() {
			return this.renderer.smuflMetrics.numberedDashGlyphWidth;
		}
		get absoluteDisplayStart() {
			return this._absoluteDisplayStart;
		}
		get displayDuration() {
			return MidiUtils.QuarterTime;
		}
		get onTimeX() {
			return this.renderer.smuflMetrics.numberedDashGlyphWidth / 2;
		}
		get graceType() {
			return GraceType.None;
		}
		get graceIndex() {
			return 0;
		}
		get graceGroup() {
			return null;
		}
		get voiceIndex() {
			return this._voiceIndex;
		}
		get isFirstOfTupletGroup() {
			return false;
		}
		get tupletGroup() {
			return null;
		}
		get isLastOfVoice() {
			return false;
		}
		getLowestNoteY(_requestedPosition) {
			return 0;
		}
		getHighestNoteY(_requestedPosition) {
			return 0;
		}
		getNoteY(_note, _requestedPosition) {
			return 0;
		}
		doMultiVoiceLayout() {}
		getRestY(_requestedPosition) {
			return 0;
		}
		getNoteX(_note, _requestedPosition) {
			return 0;
		}
		getBeatX(_requestedPosition, _useSharedSizes) {
			return 0;
		}
		registerLayoutingInfo(layoutings) {
			const width = this.renderer.smuflMetrics.numberedDashGlyphWidth;
			layoutings.addBeatSpring(this, width / 2, width / 2);
		}
		applyLayoutingInfo(_info) {}
		buildBoundingsLookup(_barBounds, _cx, _cy) {}
		paint(cx, cy, canvas) {
			const renderer = this.renderer;
			const dashWidth = renderer.smuflMetrics.numberedDashGlyphWidth;
			const dashHeight = renderer.smuflMetrics.numberedBarRendererBarSize;
			const dashY = Math.ceil(cy + renderer.getLineY(0) - dashHeight);
			canvas.fillRect(cx + this.x, dashY, dashWidth, dashHeight);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/GhostParenthesisGlyph.ts
	/**
	* @internal
	*/
	var GhostParenthesisGlyph = class extends Glyph {
		_isOpen;
		colorOverride;
		constructor(isOpen) {
			super(0, 0);
			this._isOpen = isOpen;
		}
		doLayout() {
			super.doLayout();
			this.width = this.renderer.smuflMetrics.ghostParenthesisWidth + this.renderer.smuflMetrics.ghostParenthesisPadding;
		}
		paint(cx, cy, canvas) {
			const c = canvas.color;
			if (this.colorOverride) canvas.color = this.colorOverride;
			if (this._isOpen) TieGlyph.paintTie(canvas, 1, cx + this.x + this.renderer.smuflMetrics.ghostParenthesisWidth, cy + this.y + this.height, cx + this.x + this.renderer.smuflMetrics.ghostParenthesisWidth, cy + this.y, false, this.renderer.smuflMetrics.ghostParenthesisWidth / 2, this.renderer.smuflMetrics.tieMidpointThickness);
			else TieGlyph.paintTie(canvas, 1, cx + this.x + this.renderer.smuflMetrics.ghostParenthesisPadding, cy + this.y, cx + this.x + this.renderer.smuflMetrics.ghostParenthesisPadding, cy + this.y + this.height, false, this.renderer.smuflMetrics.ghostParenthesisWidth / 2, this.renderer.smuflMetrics.tieMidpointThickness);
			canvas.color = c;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TimeSignatureGlyph.ts
	/**
	* @internal
	*/
	var TimeSignatureGlyph = class extends GlyphGroup {
		_numerator = 0;
		_denominator = 0;
		_isCommon;
		_isFreeTime;
		barSubElement = BarSubElement.StandardNotationTimeSignature;
		constructor(x, y, numerator, denominator, isCommon, isFreeTime) {
			super(x, y);
			this._numerator = numerator;
			this._denominator = denominator;
			this._isCommon = isCommon;
			this._isFreeTime = isFreeTime;
		}
		paint(cx, cy, canvas) {
			const _ = ElementStyleHelper.bar(canvas, this.barSubElement, this.renderer.bar);
			try {
				super.paint(cx, cy, canvas);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		doLayout() {
			if (this._isCommon && this._numerator === 2 && this._denominator === 2) {
				const common = new MusicFontGlyph(0, 0, this.commonScale, MusicFontSymbol.TimeSigCutCommon);
				this.addGlyph(common);
				super.doLayout();
			} else if (this._isCommon && this._numerator === 4 && this._denominator === 4) {
				const common = new MusicFontGlyph(0, 0, this.commonScale, MusicFontSymbol.TimeSigCommon);
				this.addGlyph(common);
				super.doLayout();
			} else {
				const numerator = new NumberGlyph(0, 0, this._numerator, TextBaseline.Top, this.numberScale);
				const denominator = new NumberGlyph(0, 0, this._denominator, TextBaseline.Bottom, this.numberScale);
				this.addGlyph(numerator);
				this.addGlyph(denominator);
				super.doLayout();
				const glyphSpace = this.width;
				numerator.x = (glyphSpace - numerator.width) / 2;
				denominator.x = (glyphSpace - denominator.width) / 2;
				this.width = Math.max(numerator.x + numerator.width, denominator.x + denominator.width);
			}
			if (this._isFreeTime) {
				const numberHeight = this.renderer.smuflMetrics.oneStaffSpace * 2;
				const openParenthesis = new GhostParenthesisGlyph(true);
				openParenthesis.renderer = this.renderer;
				openParenthesis.y = -numberHeight;
				openParenthesis.height = numberHeight * 2;
				openParenthesis.doLayout();
				for (const g of this.glyphs) g.x += openParenthesis.width;
				this.width += openParenthesis.width;
				this.addGlyph(openParenthesis);
				const closeParenthesis = new GhostParenthesisGlyph(false);
				closeParenthesis.renderer = this.renderer;
				closeParenthesis.x = this.width;
				closeParenthesis.y = -numberHeight;
				closeParenthesis.height = numberHeight * 2;
				closeParenthesis.doLayout();
				this.addGlyph(closeParenthesis);
				this.width += closeParenthesis.width;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreTimeSignatureGlyph.ts
	/**
	* @internal
	*/
	var ScoreTimeSignatureGlyph = class extends TimeSignatureGlyph {
		get commonScale() {
			return 1;
		}
		get numberScale() {
			return 1;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/FlagGlyph.ts
	/**
	* @internal
	*/
	var FlagGlyph = class FlagGlyph extends MusicFontGlyph {
		constructor(x, y, duration, direction, isGrace) {
			super(x, y, isGrace ? EngravingSettings.GraceScale : 1, FlagGlyph.getSymbol(duration, direction, isGrace));
		}
		paint(cx, cy, canvas) {
			const c = canvas.color;
			super.paint(cx, cy, canvas);
			canvas.color = c;
		}
		static getSymbol(duration, direction, isGrace) {
			if (isGrace) duration = Duration.Eighth;
			if (direction === BeamDirection.Up) switch (duration) {
				case Duration.Eighth: return MusicFontSymbol.Flag8thUp;
				case Duration.Sixteenth: return MusicFontSymbol.Flag16thUp;
				case Duration.ThirtySecond: return MusicFontSymbol.Flag32ndUp;
				case Duration.SixtyFourth: return MusicFontSymbol.Flag64thUp;
				case Duration.OneHundredTwentyEighth: return MusicFontSymbol.Flag128thUp;
				case Duration.TwoHundredFiftySixth: return MusicFontSymbol.Flag256thUp;
				default: return MusicFontSymbol.Flag8thUp;
			}
			switch (duration) {
				case Duration.Eighth: return MusicFontSymbol.Flag8thDown;
				case Duration.Sixteenth: return MusicFontSymbol.Flag16thDown;
				case Duration.ThirtySecond: return MusicFontSymbol.Flag32ndDown;
				case Duration.SixtyFourth: return MusicFontSymbol.Flag64thDown;
				case Duration.OneHundredTwentyEighth: return MusicFontSymbol.Flag128thDown;
				case Duration.TwoHundredFiftySixth: return MusicFontSymbol.Flag128thDown;
				default: return MusicFontSymbol.Flag8thDown;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/RepeatCountGlyph.ts
	/**
	* @internal
	*/
	var RepeatCountGlyph = class extends Glyph {
		_count = 0;
		constructor(x, y, count) {
			super(x, y);
			this._count = 0;
			this._count = count;
		}
		doLayout() {
			this.renderer.scoreRenderer.canvas.font = this.renderer.resources.elementFonts.get(NotationElement.RepeatCount);
			const size = this.renderer.scoreRenderer.canvas.measureText(`x${this._count}`);
			this.width = 0;
			this.height = size.height;
			this.y -= size.height;
		}
		paint(cx, cy, canvas) {
			const _ = ElementStyleHelper.bar(canvas, this.renderer.repeatsBarSubElement, this.renderer.bar);
			try {
				const res = this.renderer.resources;
				const oldAlign = canvas.textAlign;
				canvas.font = res.elementFonts.get(NotationElement.RepeatCount);
				canvas.textAlign = TextAlign.Right;
				const s = `x${this._count}`;
				const w = canvas.measureText(s).width / 1.5;
				canvas.fillText(s, cx + this.x - w, cy + this.y);
				canvas.textAlign = oldAlign;
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/LineBarRenderer.ts
	/**
	* This is a base class for any bar renderer which renders music notation on a staff
	* with lines like Standard Notation, Guitar Tablatures and Slash Notation.
	*
	* This base class takes care of the typical bits like drawing lines,
	* allowing note positioning and creating glyphs like repeats, bar numbers etc..
	* @internal
	*/
	var LineBarRenderer = class LineBarRenderer extends BarRendererBase {
		firstLineY = 0;
		_startSpacing = false;
		tupletSize = 0;
		get lineOffset() {
			return this.lineSpacing;
		}
		get tupletOffset() {
			return this.smuflMetrics.oneStaffSpace * .5;
		}
		get topGlyphOverflow() {
			return 0;
		}
		get bottomGlyphOverflow() {
			return 0;
		}
		initLineBasedSizes() {
			this.height = this.lineOffset * (this.heightLineCount - 1);
		}
		updateSizes() {
			this.initLineBasedSizes();
			this.adjustSizes();
			this.updateFirstLineY();
			super.updateSizes();
		}
		adjustSizes() {}
		updateFirstLineY() {
			const fullLineHeight = this.lineOffset * (this.heightLineCount - 1);
			const actualLineHeight = this.drawnLineCount === 0 ? 0 : (this.drawnLineCount - 1) * this.lineOffset;
			const lineYOffset = this.smuflMetrics.staffLineThickness / 2;
			this.firstLineY = ((fullLineHeight - actualLineHeight) / 2 | 0) - lineYOffset;
		}
		doLayout() {
			this.initLineBasedSizes();
			this.updateFirstLineY();
			this.tupletSize = this.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tuplet0);
			super.doLayout();
		}
		getLineY(line) {
			return this.firstLineY + this.getLineHeight(line);
		}
		getLineHeight(line) {
			return this.lineOffset * line;
		}
		paintContent(cx, cy, canvas) {
			super.paintContent(cx, cy, canvas);
			this.paintBeams(cx, cy, canvas, this.flagsSubElement, this.beamsSubElement);
			this.paintTuplets(cx, cy, canvas, this.tupletSubElement);
		}
		paintBackground(cx, cy, canvas) {
			super.paintBackground(cx, cy, canvas);
			this.paintStaffLines(cx, cy, canvas);
			this.paintSimileMark(cx, cy, canvas);
		}
		paintStaffLines(cx, cy, canvas) {
			const _ = ElementStyleHelper.bar(canvas, this.staffLineBarSubElement, this.bar, true);
			try {
				const spaces = [];
				for (let i = 0, j = this.drawnLineCount; i < j; i++) spaces.push([]);
				if (!this.additionalMultiRestBars) this.collectSpaces(spaces);
				for (const line of spaces) line.sort((a, b) => {
					return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0;
				});
				const lineWidth = this.width;
				const lineYOffset = this.smuflMetrics.staffLineThickness / 2;
				for (let i = 0; i < this.drawnLineCount; i++) {
					const lineY = this.getLineY(i) - lineYOffset;
					let lineX = 0;
					for (const line of spaces[i]) {
						canvas.fillRect(cx + this.x + lineX, cy + this.y + lineY, line[0] - lineX, this.smuflMetrics.staffLineThickness);
						lineX = line[0] + line[1];
					}
					canvas.fillRect(cx + this.x + lineX, cy + this.y + lineY, lineWidth - lineX, this.smuflMetrics.staffLineThickness);
				}
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		collectSpaces(_spaces) {}
		createStartSpacing() {
			if (this._startSpacing) return false;
			const padding = this.index === 0 ? this.settings.display.firstStaffPaddingLeft : this.settings.display.staffPaddingLeft;
			this.addPreBeatGlyph(new SpacingGlyph(0, 0, padding));
			this._startSpacing = true;
			return true;
		}
		paintTuplets(cx, cy, canvas, beatElement, bracketsAsArcs = false) {
			for (const v of this.voiceContainer.voiceDrawOrder) if (this.voiceContainer.tupletGroups.has(v)) {
				const voice = this.voiceContainer.tupletGroups.get(v);
				for (const tupletGroup of voice) this._paintTupletHelper(cx, cy, canvas, tupletGroup, beatElement, bracketsAsArcs);
			}
		}
		getBeatDirection(beat) {
			const helper = this.helpers.getBeamingHelperForBeat(beat);
			return helper ? this.getBeamDirection(helper) : BeamDirection.Up;
		}
		getTupletBeamDirection(helper) {
			return this.getBeamDirection(helper);
		}
		calculateBeamYWithDirection(h, x, direction) {
			this.ensureBeamDrawingInfo(h, direction);
			return h.drawingInfos.get(direction).calcY(x);
		}
		_paintTupletHelper(cx, cy, canvas, h, beatElement, bracketsAsArcs) {
			const res = this.resources;
			const oldAlign = canvas.textAlign;
			const oldBaseLine = canvas.textBaseline;
			canvas.color = h.voice.index === 0 ? this.resources.mainGlyphColor : this.resources.secondaryGlyphColor;
			canvas.textAlign = TextAlign.Center;
			canvas.textBaseline = TextBaseline.Middle;
			let s;
			const num = h.beats[0].tupletNumerator;
			const den = h.beats[0].tupletDenominator;
			if (num === 2 && den === 3) s = [MusicFontSymbol.Tuplet2];
			else if (num === 3 && den === 2) s = [MusicFontSymbol.Tuplet3];
			else if (num === 4 && den === 6) s = [MusicFontSymbol.Tuplet4];
			else if (num === 5 && den === 4) s = [MusicFontSymbol.Tuplet5];
			else if (num === 6 && den === 4) s = [MusicFontSymbol.Tuplet6];
			else if (num === 7 && den === 4) s = [MusicFontSymbol.Tuplet7];
			else if (num === 9 && den === 8) s = [MusicFontSymbol.Tuplet9];
			else if (num === 10 && den === 8) s = [MusicFontSymbol.Tuplet1, MusicFontSymbol.Tuplet0];
			else if (num === 11 && den === 8) s = [MusicFontSymbol.Tuplet1, MusicFontSymbol.Tuplet1];
			else if (num === 12 && den === 8) s = [MusicFontSymbol.Tuplet1, MusicFontSymbol.Tuplet2];
			else if (num === 13 && den === 8) s = [MusicFontSymbol.Tuplet1, MusicFontSymbol.Tuplet3];
			else {
				s = [];
				const zero = MusicFontSymbol.Tuplet0;
				if (num > 10) {
					const tens = Math.floor(num / 10);
					s.push(zero + tens);
					s.push(zero + (num - 10 * tens));
				} else s.push(zero + num);
				s.push(MusicFontSymbol.TupletColon);
				if (den > 10) {
					const tens = Math.floor(den / 10);
					s.push(zero + tens);
					s.push(zero + (den - 10 * tens));
				} else s.push(zero + den);
			}
			const offset = this.tupletOffset;
			const size = this.tupletSize;
			const shift = offset + size * .5;
			const _ = ElementStyleHelper.beat(canvas, beatElement, h.beats[0]);
			try {
				const l = canvas.lineWidth;
				canvas.lineWidth = this.smuflMetrics.tupletBracketThickness;
				if (h.beats.length === 1 || !h.isFull) for (const beat of h.beats) {
					const beamingHelper = this.helpers.getBeamingHelperForBeat(beat);
					if (!beamingHelper) continue;
					const direction = this.getTupletBeamDirection(beamingHelper);
					const tupletX = this.getBeatX(beat, BeatXPosition.Stem);
					let tupletY = this.calculateBeamYWithDirection(beamingHelper, tupletX, direction);
					if (direction === BeamDirection.Down) tupletY += shift;
					else tupletY -= shift;
					canvas.fillMusicFontSymbols(cx + this.x + tupletX, cy + this.y + tupletY + size * .5, 1, s, true);
				}
				else {
					const firstBeat = h.beats[0];
					const lastBeat = h.beats[h.beats.length - 1];
					let firstNonRestBeat = null;
					let lastNonRestBeat = null;
					for (let i = 0; i < h.beats.length; i++) if (!h.beats[i].isRest) {
						firstNonRestBeat = h.beats[i];
						break;
					}
					for (let i = h.beats.length - 1; i >= 0; i--) if (!h.beats[i].isRest) {
						lastNonRestBeat = h.beats[i];
						break;
					}
					let isRestOnly = false;
					if (!firstNonRestBeat) {
						firstNonRestBeat = firstBeat;
						isRestOnly = true;
					}
					if (!lastNonRestBeat) lastNonRestBeat = lastBeat;
					const startX = this.getBeatX(firstBeat, BeatXPosition.OnNotes);
					const endX = this.getBeatX(lastBeat, BeatXPosition.PostNotes);
					const firstNonRestBeamingHelper = this.helpers.getBeamingHelperForBeat(firstNonRestBeat);
					const lastNonRestBeamingHelper = this.helpers.getBeamingHelperForBeat(lastNonRestBeat);
					const direction = this.getTupletBeamDirection(firstNonRestBeamingHelper);
					let startY;
					let endY;
					if (isRestOnly) {
						if (direction === BeamDirection.Up) startY = Math.min(this.getRestY(firstNonRestBeat, NoteYPosition.Top), this.getRestY(lastNonRestBeat, NoteYPosition.Top));
						else startY = Math.max(this.getRestY(firstNonRestBeat, NoteYPosition.Bottom), this.getRestY(lastNonRestBeat, NoteYPosition.Bottom));
						endY = startY;
					} else {
						startY = this.calculateBeamYWithDirection(firstNonRestBeamingHelper, startX, direction);
						endY = this.calculateBeamYWithDirection(lastNonRestBeamingHelper, endX, direction);
					}
					if (direction === BeamDirection.Down) {
						startY += shift;
						endY += shift;
					} else {
						startY -= shift;
						endY -= shift;
					}
					const sw = s.reduce((acc, sym) => acc + res.engravingSettings.glyphWidths.get(sym), 0);
					const sp = res.engravingSettings.oneStaffSpace * .5;
					const middleX = (startX + endX) / 2;
					const offset1X = middleX - sw / 2 - sp;
					const offset2X = middleX + sw / 2 + sp;
					const k = (endY - startY) / (endX - startX);
					const d = startY - k * startX;
					const offset1Y = k * offset1X + d;
					const middleY = k * middleX + d;
					const offset2Y = k * offset2X + d;
					const angleStartY = direction === BeamDirection.Down ? startY - size * .5 : startY + size * .5;
					const angleEndY = direction === BeamDirection.Down ? endY - size * .5 : endY + size * .5;
					const pixelAlignment = canvas.lineWidth % 2 === 0 ? 0 : .5;
					cx += pixelAlignment;
					cy += pixelAlignment;
					if (offset1X > startX) {
						canvas.beginPath();
						canvas.moveTo(cx + this.x + startX, cy + this.y + angleStartY);
						if (bracketsAsArcs) canvas.quadraticCurveTo(cx + this.x + (offset1X + startX) / 2, cy + this.y + offset1Y, cx + this.x + offset1X, cy + this.y + offset1Y);
						else {
							canvas.lineTo(cx + this.x + startX, cy + this.y + startY);
							canvas.lineTo(cx + this.x + offset1X, cy + this.y + offset1Y);
						}
						canvas.moveTo(cx + this.x + offset2X, cy + this.y + offset2Y);
						if (bracketsAsArcs) canvas.quadraticCurveTo(cx + this.x + (endX + offset2X) / 2, cy + this.y + offset2Y, cx + this.x + endX, cy + this.y + angleEndY);
						else {
							canvas.lineTo(cx + this.x + endX, cy + this.y + endY);
							canvas.lineTo(cx + this.x + endX, cy + this.y + angleEndY);
						}
						canvas.stroke();
					}
					canvas.fillMusicFontSymbols(cx + this.x + middleX, cy + this.y + middleY + size * .5, 1, s, true);
				}
				canvas.textAlign = oldAlign;
				canvas.textBaseline = oldBaseLine;
				canvas.lineWidth = l;
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		paintBeams(cx, cy, canvas, flagsElement, beamsElement) {
			for (const v of this.voiceContainer.voiceDrawOrder) for (const h of this.helpers.beamHelpers[v]) this.paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement);
		}
		drawBeamHelperAsFlags(h) {
			return h.beats.length === 1;
		}
		hasFlag(beat) {
			if (beat.isRest) return false;
			const helper = this.helpers.getBeamingHelperForBeat(beat);
			if (helper) return helper.hasFlag(this.drawBeamHelperAsFlags(helper), beat);
			return BeamingHelper.beatHasFlag(beat);
		}
		hasStem(beat) {
			if (beat.isRest) return false;
			const helper = this.helpers.getBeamingHelperForBeat(beat);
			if (helper) return helper.hasStem(this.drawBeamHelperAsFlags(helper), beat);
			return BeamingHelper.beatHasStem(beat);
		}
		paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement) {
			canvas.color = h.voice.index === 0 ? this.resources.mainGlyphColor : this.resources.secondaryGlyphColor;
			if (this.shouldPaintBeamingHelper(h)) if (this.drawBeamHelperAsFlags(h)) this.paintFlag(cx, cy, canvas, h, flagsElement);
			else this.paintBar(cx, cy, canvas, h, beamsElement);
		}
		shouldPaintBeamingHelper(h) {
			return !h.isRestBeamHelper;
		}
		shouldPaintFlag(beat) {
			if (beat.graceType === GraceType.BendGrace) return false;
			if (beat.deadSlapped) return false;
			if (beat.graceType !== GraceType.None && this.settings.notation.notationMode === NotationMode.SongBook) return false;
			if (beat.duration === Duration.Whole || beat.duration === Duration.DoubleWhole || beat.duration === Duration.QuadrupleWhole) return false;
			return true;
		}
		paintFlag(cx, cy, canvas, h, flagsElement) {
			for (const beat of h.beats) {
				if (!this.shouldPaintFlag(beat)) continue;
				const isGrace = beat.graceType !== GraceType.None;
				const beatLineX = this.getBeatX(beat, BeatXPosition.Stem);
				const direction = this.getBeamDirection(h);
				const topY = cy + this.y + this.getFlagTopY(beat, direction);
				const bottomY = cy + this.y + this.getFlagBottomY(beat, direction);
				let flagY = 0;
				if (direction === BeamDirection.Down) flagY = bottomY;
				else flagY = topY;
				if (!h.hasStem(true, beat)) continue;
				this.paintBeamingStem(beat, cy + this.y, cx + this.x + beatLineX, topY, bottomY, canvas);
				const _ = ElementStyleHelper.beat(canvas, flagsElement, beat);
				try {
					let flagWidth = 0;
					if (h.hasFlag(true, beat)) {
						const glyph = new FlagGlyph(cx + this.x + beatLineX, flagY, beat.duration, direction, isGrace);
						glyph.renderer = this;
						glyph.doLayout();
						glyph.paint(0, 0, canvas);
						flagWidth = glyph.width / 2;
					}
					if (beat.graceType === GraceType.BeforeBeat) if (direction === BeamDirection.Down) CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + beatLineX + flagWidth / 2, (topY + bottomY - this.smuflMetrics.glyphHeights.get(MusicFontSymbol.GraceNoteSlashStemDown)) / 2, EngravingSettings.GraceScale, MusicFontSymbol.GraceNoteSlashStemDown, true);
					else CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + beatLineX + flagWidth / 2, (topY + bottomY + this.smuflMetrics.glyphHeights.get(MusicFontSymbol.GraceNoteSlashStemUp)) / 2, EngravingSettings.GraceScale, MusicFontSymbol.GraceNoteSlashStemUp, true);
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
		recreatePreBeatGlyphs() {
			this._startSpacing = false;
			super.recreatePreBeatGlyphs();
		}
		calculateBeamY(h, x) {
			return this.calculateBeamYWithDirection(h, x, this.getBeamDirection(h));
		}
		createPreBeatGlyphs() {
			super.createPreBeatGlyphs();
			this.addPreBeatGlyph(new BarLineGlyph(false, this.bar.staff.track.score.stylesheet.extendBarLines));
			this.createLinePreBeatGlyphs();
			let hasSpaceAfterStartGlyphs = false;
			if (this.index === 0) hasSpaceAfterStartGlyphs = this.createStartSpacing();
			if (this.shouldCreateBarNumber()) this.addPreBeatGlyph(new BarNumberGlyph(0, this.getLineHeight(-.5), this.bar.index + 1));
			else if (!hasSpaceAfterStartGlyphs) this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.oneStaffSpace));
		}
		shouldCreateBarNumber() {
			let display = BarNumberDisplay.AllBars;
			if (!this.settings.notation.isNotationElementVisible(NotationElement.BarNumber)) display = BarNumberDisplay.Hide;
			else if (this.bar.barNumberDisplay !== void 0) display = this.bar.barNumberDisplay;
			else display = this.bar.staff.track.score.stylesheet.barNumberDisplay;
			switch (display) {
				case BarNumberDisplay.AllBars: return true;
				case BarNumberDisplay.FirstOfSystem: return this.isFirstOfStaff;
				case BarNumberDisplay.Hide: return false;
			}
			return true;
		}
		createPostBeatGlyphs() {
			super.createPostBeatGlyphs();
			const lastBar = this.lastBar;
			this.addPostBeatGlyph(new BarLineGlyph(true, this.bar.staff.track.score.stylesheet.extendBarLines));
			if (lastBar.masterBar.isRepeatEnd && lastBar.masterBar.repeatCount > 2 && this.settings.notation.isNotationElementVisible(NotationElement.RepeatCount)) this.addPostBeatGlyph(new RepeatCountGlyph(0, this.getLineHeight(-.5), this.bar.masterBar.repeatCount));
		}
		paintBar(cx, cy, canvas, h, beamsElement) {
			const direction = this.getBeamDirection(h);
			const scaleMod = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
			let barSpacing = (this.beamSpacing + this.beamThickness) * scaleMod;
			let barSize = this.beamThickness * scaleMod;
			if (direction === BeamDirection.Down) {
				barSpacing = -barSpacing;
				barSize = -barSize;
			}
			for (let i = 0, j = h.beats.length; i < j; i++) {
				const beat = h.beats[i];
				if (beat.deadSlapped) continue;
				const stemX = this.getBeatX(beat, BeatXPosition.Stem);
				let y1 = cy + this.y;
				if (direction === BeamDirection.Up) y1 += this.getFlagBottomY(beat, direction);
				else y1 += this.getFlagTopY(beat, direction);
				const y2 = cy + this.y + this.calculateBeamY(h, stemX);
				let stemY1;
				let stemY2;
				if (y1 < y2) {
					stemY1 = y1;
					stemY2 = y2;
				} else {
					stemY1 = y2;
					stemY2 = y1;
				}
				this.paintBeamingStem(beat, cy + this.y, cx + this.x + stemX, stemY1, stemY2, canvas);
				const _ = ElementStyleHelper.beat(canvas, beamsElement, beat);
				try {
					const brokenBarOffset = this.smuflMetrics.brokenBeamWidth * scaleMod;
					const barCount = ModelUtils.getIndex(beat.duration) - 2;
					const barStart = cy + this.y;
					const stemThickness = this.smuflMetrics.stemThickness;
					for (let barIndex = 0; barIndex < barCount; barIndex++) {
						let barStartX = Math.floor(stemX + stemThickness);
						let barEndX = 0;
						let barStartY = 0;
						let barEndY = 0;
						const barY = barStart + barIndex * barSpacing;
						if (i < h.beats.length - 1) {
							const isFullBarJoin = BeamingHelper.isFullBarJoin(beat, h.beats[i + 1], barIndex);
							if (barIndex === barCount - 1 && isFullBarJoin && beat.beamingMode === BeatBeamingMode.ForceSplitOnSecondaryToNext) {
								barEndX = Math.ceil(barStartX + brokenBarOffset);
								barStartY = barY + this.calculateBeamY(h, barStartX);
								barEndY = barY + this.calculateBeamY(h, barEndX);
								LineBarRenderer.paintSingleBar(canvas, cx + this.x + barStartX, barStartY, cx + this.x + barEndX, barEndY, barSize);
								barEndX = Math.floor(this.getBeatX(h.beats[i + 1], BeatXPosition.Stem));
								barStartX = Math.floor(barEndX - brokenBarOffset);
								barStartY = barY + this.calculateBeamY(h, barStartX);
								barEndY = barY + this.calculateBeamY(h, barEndX);
								LineBarRenderer.paintSingleBar(canvas, cx + this.x + barStartX, barStartY, cx + this.x + barEndX, barEndY, barSize);
							} else {
								if (isFullBarJoin) barEndX = Math.ceil(this.getBeatX(h.beats[i + 1], BeatXPosition.Stem));
								else if (i === 0 || !BeamingHelper.isFullBarJoin(h.beats[i - 1], beat, barIndex)) barEndX = Math.ceil(barStartX + brokenBarOffset);
								else continue;
								barStartY = barY + this.calculateBeamY(h, barStartX);
								barEndY = barY + this.calculateBeamY(h, barEndX);
								LineBarRenderer.paintSingleBar(canvas, cx + this.x + barStartX, barStartY, cx + this.x + barEndX, barEndY, barSize);
							}
						} else if (i > 0 && !BeamingHelper.isFullBarJoin(beat, h.beats[i - 1], barIndex)) {
							barEndX = Math.ceil(stemX);
							barStartX = Math.floor(stemX - brokenBarOffset);
							barStartY = barY + this.calculateBeamY(h, barStartX);
							barEndY = barY + this.calculateBeamY(h, barEndX);
							LineBarRenderer.paintSingleBar(canvas, cx + this.x + barStartX, barStartY, cx + this.x + barEndX, barEndY, barSize);
						}
					}
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
			if (h.graceType === GraceType.BeforeBeat) {
				const beatLineX = this.getBeatX(h.beats[0], BeatXPosition.Stem);
				const flagWidth = this.smuflMetrics.glyphWidths.get(MusicFontSymbol.Flag8thUp) * EngravingSettings.GraceScale;
				let slashY = cy + this.y + this.calculateBeamY(h, beatLineX) | 0;
				slashY += barSize + barSpacing;
				if (direction === BeamDirection.Down) CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + beatLineX + flagWidth / 2, slashY, EngravingSettings.GraceScale, MusicFontSymbol.GraceNoteSlashStemDown, true);
				else CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x + beatLineX + flagWidth / 2, slashY, EngravingSettings.GraceScale, MusicFontSymbol.GraceNoteSlashStemUp, true);
			}
		}
		static paintSingleBar(canvas, x1, y1, x2, y2, size) {
			canvas.beginPath();
			canvas.moveTo(x1, y1);
			canvas.lineTo(x2, y2);
			canvas.lineTo(x2, y2 + size);
			canvas.lineTo(x1, y1 + size);
			canvas.closePath();
			canvas.fill();
		}
		calculateBeamingOverflows(rendererTop, rendererBottom) {
			let maxNoteY = 0;
			let minNoteY = 0;
			for (const v of this.helpers.beamHelpers) for (const h of v) if (!this.shouldPaintBeamingHelper(h)) {
				if (h.hasTuplet && h.isRestBeamHelper) {
					const tupletGroup = h.beats[0].tupletGroup;
					const tupletFirst = tupletGroup.beats[0];
					const tupletLast = tupletGroup.beats[tupletGroup.beats.length - 1];
					if (this.getTupletBeamDirection(h) === BeamDirection.Up) {
						const topY = Math.min(this.getRestY(tupletFirst, NoteYPosition.Top), this.getRestY(tupletLast, NoteYPosition.Top)) - this.tupletSize - this.tupletOffset;
						if (topY < maxNoteY) maxNoteY = topY;
					} else {
						const bottomY = Math.max(this.getRestY(tupletFirst, NoteYPosition.Bottom), this.getRestY(tupletLast, NoteYPosition.Bottom)) + this.tupletSize + this.tupletOffset;
						if (bottomY > minNoteY) minNoteY = bottomY;
					}
				}
			} else if (h.beats.length === 1 && h.beats[0].duration >= Duration.Half) {
				const tupletDirection = this.getTupletBeamDirection(h);
				const direction = this.getBeamDirection(h);
				const flagOverflow = this.smuflMetrics.stemFlagOffsets.get(h.beats[0].duration);
				if (direction === BeamDirection.Up) {
					let topY = this.getFlagTopY(h.beats[0], direction) - flagOverflow;
					if (h.hasTuplet && tupletDirection === direction) topY -= this.tupletSize + this.tupletOffset;
					if (topY < maxNoteY) maxNoteY = topY;
					if (h.hasTuplet && tupletDirection !== direction) {
						let bottomY = this.getFlagBottomY(h.beats[0], tupletDirection);
						bottomY += this.tupletSize + this.tupletOffset;
						if (bottomY > minNoteY) minNoteY = bottomY;
					}
				} else {
					let bottomY = this.getFlagBottomY(h.beats[0], direction) + flagOverflow;
					if (h.hasTuplet && tupletDirection === direction) bottomY += this.tupletSize + this.tupletOffset;
					if (bottomY > minNoteY) minNoteY = bottomY;
					if (h.hasTuplet && tupletDirection !== direction) {
						let topY = this.getFlagTopY(h.beats[0], tupletDirection);
						topY -= this.tupletSize + this.tupletOffset;
						if (topY < maxNoteY) maxNoteY = topY;
					}
				}
			} else {
				const direction = this.getBeamDirection(h);
				this.ensureBeamDrawingInfo(h, direction);
				const drawingInfo = h.drawingInfos.get(direction);
				const tupletDirection = this.getTupletBeamDirection(h);
				if (direction === BeamDirection.Up) {
					let topY = Math.min(drawingInfo.startY, drawingInfo.endY);
					if (h.hasTuplet && tupletDirection === direction) topY -= this.tupletSize + this.tupletOffset;
					if (topY < maxNoteY) maxNoteY = topY;
					let bottomY = this.voiceContainer.getLowestNoteY(h.beatOfLowestNote, NoteYPosition.Bottom);
					if (h.hasTuplet && tupletDirection !== direction) bottomY += this.tupletSize + this.tupletOffset;
					if (bottomY > minNoteY) minNoteY = bottomY;
				} else {
					let bottomY = Math.max(drawingInfo.startY, drawingInfo.endY);
					if (h.hasTuplet && tupletDirection === direction) bottomY += this.tupletSize + this.tupletOffset;
					if (bottomY > minNoteY) minNoteY = bottomY;
					let topY = this.voiceContainer.getHighestNoteY(h.beatOfHighestNote, NoteYPosition.Top);
					if (h.hasTuplet && tupletDirection !== direction) topY -= this.tupletSize + this.tupletOffset;
					if (topY < maxNoteY) maxNoteY = topY;
				}
			}
			if (maxNoteY < rendererTop) this.registerOverflowTop(Math.abs(maxNoteY));
			if (minNoteY > rendererBottom) this.registerOverflowBottom(Math.abs(minNoteY) - rendererBottom);
		}
		initializeBeamDrawingInfo(h, direction) {
			const drawingInfo = new BeamingHelperDrawInfo();
			const firstBeat = h.beats[0];
			const lastBeat = h.beats[h.beats.length - 1];
			drawingInfo.startBeat = firstBeat;
			drawingInfo.startX = this.getBeatX(firstBeat, BeatXPosition.Stem);
			drawingInfo.startY = direction === BeamDirection.Up ? this.getFlagTopY(firstBeat, direction) : this.getFlagBottomY(firstBeat, direction);
			drawingInfo.endBeat = lastBeat;
			drawingInfo.endX = this.getBeatX(lastBeat, BeatXPosition.Stem);
			drawingInfo.endY = direction === BeamDirection.Up ? this.getFlagTopY(lastBeat, direction) : this.getFlagBottomY(lastBeat, direction);
			const maxSlope = this.smuflMetrics.oneStaffSpace;
			if (direction === BeamDirection.Down && drawingInfo.startY > drawingInfo.endY && drawingInfo.startY - drawingInfo.endY > maxSlope) drawingInfo.endY = drawingInfo.startY - maxSlope;
			if (direction === BeamDirection.Down && drawingInfo.endY > drawingInfo.startY && drawingInfo.endY - drawingInfo.startY > maxSlope) drawingInfo.startY = drawingInfo.endY - maxSlope;
			if (direction === BeamDirection.Up && drawingInfo.startY < drawingInfo.endY && drawingInfo.endY - drawingInfo.startY > maxSlope) drawingInfo.endY = drawingInfo.startY + maxSlope;
			if (direction === BeamDirection.Up && drawingInfo.endY < drawingInfo.startY && drawingInfo.startY - drawingInfo.endY > maxSlope) drawingInfo.startY = drawingInfo.endY + maxSlope;
			return drawingInfo;
		}
		get beamSpacing() {
			return this.smuflMetrics.beamSpacing;
		}
		get beamThickness() {
			return this.smuflMetrics.beamThickness;
		}
		ensureBeamDrawingInfo(h, direction) {
			if (h.drawingInfos.has(direction)) return;
			const drawingInfo = this.initializeBeamDrawingInfo(h, direction);
			h.drawingInfos.set(direction, drawingInfo);
			const barCount = ModelUtils.getIndex(h.shortestDuration) - 2;
			const barDrawingShift = this.applyBarShift(h, direction, drawingInfo, barCount);
			if (h.beats.length > 1) {
				if (direction === BeamDirection.Up) {
					const yNeededForHighestNote = barDrawingShift + this.getFlagTopY(h.beatOfHighestNote, direction);
					const diff = drawingInfo.calcY(this.getBeatX(h.beatOfHighestNote, BeatXPosition.Stem)) - yNeededForHighestNote;
					if (diff > 0) {
						drawingInfo.startY -= diff;
						drawingInfo.endY -= diff;
					}
				} else {
					const diff = barDrawingShift + this.getFlagBottomY(h.beatOfLowestNote, direction) - drawingInfo.calcY(this.getBeatX(h.beatOfLowestNote, BeatXPosition.Stem));
					if (diff > 0) {
						drawingInfo.startY += diff;
						drawingInfo.endY += diff;
					}
				}
				let barSpacing = 0;
				if (h.restBeats.length > 0) {
					const scaleMod = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
					barSpacing = barCount * (this.beamSpacing + this.beamThickness) * scaleMod;
				}
				for (const b of h.restBeats) if (b.isRest && b.index < h.beats[h.beats.length - 1].index) {
					if (direction === BeamDirection.Up) {
						const yNeededForRest = this.getBeatContainer(b).getBoundingBoxTop() - barSpacing;
						const diff = drawingInfo.calcY(this.getBeatX(b, BeatXPosition.Stem)) - yNeededForRest;
						if (diff > 0) {
							drawingInfo.startY -= diff;
							drawingInfo.endY -= diff;
						}
					} else if (direction === BeamDirection.Down) {
						const diff = this.getBeatContainer(b).getBoundingBoxBottom() + barSpacing - drawingInfo.calcY(this.getBeatX(b, BeatXPosition.Stem));
						if (diff > 0) {
							drawingInfo.startY += diff;
							drawingInfo.endY += diff;
						}
					}
				}
				if (h.slashBeats.length > 0) for (const b of h.slashBeats) {
					const yGivenByCurrentValues = drawingInfo.calcY(this.getBeatX(b, BeatXPosition.Stem));
					const diff = (direction === BeamDirection.Up ? this.getFlagTopY(b, direction) : this.getFlagBottomY(b, direction)) - yGivenByCurrentValues;
					if (diff > 0) {
						drawingInfo.startY += diff;
						drawingInfo.endY += diff;
					}
				}
			}
			if (direction === BeamDirection.Up) {
				drawingInfo.startY = Math.round(drawingInfo.startY);
				drawingInfo.endY = Math.round(drawingInfo.endY);
			} else {
				drawingInfo.startY = Math.round(drawingInfo.startY);
				drawingInfo.endY = Math.round(drawingInfo.endY);
			}
		}
		applyBarShift(h, direction, drawingInfo, barCount) {
			let barDrawingShift = 0;
			const isRest = h.isRestBeamHelper;
			const scale = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
			if (barCount > 2 && !isRest) {
				const beamSpacing = this.beamSpacing * scale;
				const beamThickness = this.beamThickness * scale;
				const totalBarsHeight = barCount * beamThickness + (barCount - 1) * beamSpacing;
				if (direction === BeamDirection.Up) {
					const barTopY = drawingInfo.startY + 2 * beamThickness + beamSpacing - totalBarsHeight;
					const diff = drawingInfo.startY - barTopY;
					if (diff > 0) {
						barDrawingShift = diff * -1;
						drawingInfo.startY -= diff;
						drawingInfo.endY -= diff;
					}
				} else {
					const diff = drawingInfo.startY - 2 * beamThickness + beamSpacing + totalBarsHeight - drawingInfo.startY;
					if (diff > 0) {
						barDrawingShift = diff;
						drawingInfo.startY += diff;
						drawingInfo.endY += diff;
					}
				}
			}
			return barDrawingShift;
		}
		getMinLineOfBeat(_beat) {
			return 0;
		}
		getMaxLineOfBeat(_beat) {
			return 0;
		}
	};
	//#endregion
	//#region src/rendering/NumberedBarRenderer.ts
	/**
	* This BarRenderer renders a bar using (Jianpu) Numbered Music Notation
	* @internal
	*/
	var NumberedBarRenderer = class extends LineBarRenderer {
		static StaffId = "numbered";
		simpleWhammyOverflow = 0;
		_isOnlyNumbered;
		shortestDuration = Duration.QuadrupleWhole;
		get dotSpacing() {
			return this.smuflMetrics.glyphHeights.get(MusicFontSymbol.AugmentationDot) * 2;
		}
		get repeatsBarSubElement() {
			return BarSubElement.NumberedRepeats;
		}
		get barNumberBarSubElement() {
			return BarSubElement.NumberedBarNumber;
		}
		get barLineBarSubElement() {
			return BarSubElement.NumberedBarLines;
		}
		get staffLineBarSubElement() {
			return BarSubElement.NumberedStaffLine;
		}
		constructor(renderer, bar) {
			super(renderer, bar);
			this._isOnlyNumbered = !bar.staff.showSlash && !bar.staff.showTablature && !bar.staff.showStandardNotation;
		}
		get lineSpacing() {
			return this.smuflMetrics.oneStaffSpace;
		}
		get heightLineCount() {
			return 5;
		}
		get drawnLineCount() {
			return 0;
		}
		get bottomGlyphOverflow() {
			return 0;
		}
		get flagsSubElement() {
			return BeatSubElement.NumberedDuration;
		}
		get beamsSubElement() {
			return BeatSubElement.NumberedDuration;
		}
		get tupletSubElement() {
			return BeatSubElement.NumberedTuplet;
		}
		shouldPaintBeamingHelper(_h) {
			return true;
		}
		paintFlag(cx, cy, canvas, h, flagsElement) {
			this.paintBar(cx, cy, canvas, h, flagsElement);
		}
		paintBar(cx, cy, canvas, h, flagsElement) {
			if (h.beats.length === 0 || h.graceType !== GraceType.None) return;
			for (let i = 0, j = h.beats.length; i < j; i++) {
				const beat = h.beats[i];
				const _ = ElementStyleHelper.beat(canvas, flagsElement, beat);
				try {
					const direction = this.getBeamDirection(h);
					const scaleMod = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
					let barSpacing = (this.beamSpacing + this.beamThickness) * scaleMod;
					let barSize = this.beamThickness * scaleMod;
					if (direction === BeamDirection.Down) {
						barSpacing = -barSpacing;
						barSize = -barSize;
					}
					let barCount = ModelUtils.getIndex(beat.duration) - 2;
					let beatLineX = this.getBeatX(beat, BeatXPosition.PreNotes);
					let barStartX = 0;
					let barEndX = 0;
					if (i === h.beats.length - 1) {
						barStartX = beatLineX;
						barEndX = this.getBeatX(beat, BeatXPosition.PostNotes);
					} else {
						barStartX = beatLineX;
						barEndX = this.getBeatX(h.beats[i + 1], BeatXPosition.PreNotes);
					}
					const barStart = cy + this.y + this.calculateBeamY(h, beatLineX);
					for (let barIndex = 0; barIndex < barCount; barIndex++) {
						const barY = barStart + barIndex * barSpacing;
						LineBarRenderer.paintSingleBar(canvas, cx + this.x + barStartX, barY, cx + this.x + barEndX, barY, barSize);
					}
					const container = this.voiceContainer.getBeatContainer(beat);
					if (container && container.hasAdditionalNumbers) for (const additionalNumber of container.iterateAdditionalNumbers()) {
						barCount = additionalNumber.barCount;
						beatLineX = this.beatGlyphsStart + additionalNumber.x + additionalNumber.getBeatX(BeatXPosition.PreNotes, false);
						for (let barIndex = 0; barIndex < barCount; barIndex++) {
							const barY = barStart + barIndex * barSpacing;
							const additionalBarEndX = this.beatGlyphsStart + additionalNumber.x + additionalNumber.getBeatX(BeatXPosition.PostNotes, false);
							LineBarRenderer.paintSingleBar(canvas, cx + this.x + beatLineX, barY, cx + this.x + additionalBarEndX, barY, barSize);
						}
					}
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
		calculateOverflows(rendererTop, rendererBottom) {
			super.calculateOverflows(rendererTop, rendererBottom);
			if (this.bar.isEmpty) return;
			this.calculateBeamingOverflows(rendererTop, rendererBottom);
		}
		getNoteLine(_note) {
			return 0;
		}
		_calculateBarHeight(beat) {
			const barCount = ModelUtils.getIndex(beat.duration) - 2;
			let barHeight = 0;
			if (barCount > 0) {
				const smufl = this.smuflMetrics;
				barHeight = smufl.numberedBarRendererBarSpacing + barCount * (smufl.numberedBarRendererBarSpacing + smufl.numberedBarRendererBarSize);
			}
			return barHeight;
		}
		getFlagTopY(beat, direction) {
			const barHeight = this._calculateBarHeight(beat);
			const container = this.voiceContainer.getBeatContainer(beat);
			if (!container) {
				if (direction === BeamDirection.Up) return this.voiceContainer.getBoundingBoxTop() - barHeight;
				return this.voiceContainer.getBoundingBoxBottom();
			}
			if (direction === BeamDirection.Up) return container.getBoundingBoxTop() - barHeight;
			return container.getBoundingBoxBottom();
		}
		getFlagBottomY(beat, direction) {
			const barHeight = this._calculateBarHeight(beat);
			const container = this.voiceContainer.getBeatContainer(beat);
			if (!container) {
				if (direction === BeamDirection.Down) return this.voiceContainer.getBoundingBoxBottom() + barHeight;
				return this.getLineY(0);
			}
			if (direction === BeamDirection.Down) return container.getBoundingBoxBottom() + barHeight;
			return this.getLineY(0);
		}
		getBeamDirection(_helper) {
			return BeamDirection.Down;
		}
		getTupletBeamDirection(_helper) {
			return BeamDirection.Up;
		}
		createPreBeatGlyphs() {
			this.wasFirstOfStaff = this.isFirstOfStaff;
			if (this.index === 0 || this.bar.masterBar.isRepeatStart && this._isOnlyNumbered) this.addPreBeatGlyph(new BarLineGlyph(false, this.bar.staff.track.score.stylesheet.extendBarLines));
			this.createLinePreBeatGlyphs();
			const hasSpaceAfterStartGlyphs = this.createStartSpacing();
			if (this.shouldCreateBarNumber()) this.addPreBeatGlyph(new BarNumberGlyph(0, this.getLineHeight(-.5), this.bar.index + 1));
			else if (!hasSpaceAfterStartGlyphs) this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.oneStaffSpace));
		}
		createLinePreBeatGlyphs() {
			if (this._isOnlyNumbered && (!this.bar.previousBar || this.bar.previousBar && this.bar.masterBar.timeSignatureNumerator !== this.bar.previousBar.masterBar.timeSignatureNumerator || this.bar.previousBar && this.bar.masterBar.timeSignatureDenominator !== this.bar.previousBar.masterBar.timeSignatureDenominator || this.bar.previousBar && this.bar.masterBar.isFreeTime && this.bar.masterBar.isFreeTime !== this.bar.previousBar.masterBar.isFreeTime)) {
				this.createStartSpacing();
				this._createTimeSignatureGlyphs();
			}
		}
		_createTimeSignatureGlyphs() {
			const masterBar = this.bar.masterBar;
			const g = new ScoreTimeSignatureGlyph(0, this.getLineY(0), masterBar.timeSignatureNumerator, masterBar.timeSignatureDenominator, masterBar.timeSignatureCommon, masterBar.isFreeTime && (masterBar.previousMasterBar == null || masterBar.isFreeTime !== masterBar.previousMasterBar.isFreeTime));
			g.barSubElement = BarSubElement.NumberedTimeSignature;
			this.addPreBeatGlyph(g);
		}
		createPostBeatGlyphs() {
			if (this._isOnlyNumbered) super.createPostBeatGlyphs();
		}
		createVoiceGlyphs(v) {
			if (v.index > 0) return;
			super.createVoiceGlyphs(v);
			const absoluteStart = this.bar.masterBar.start;
			for (const b of v.beats) {
				const mainContainer = new NumberedBeatContainerGlyph(b);
				this.addBeatGlyph(mainContainer);
				if (b.duration < Duration.Quarter) {
					const endTick = b.displayStart + b.displayDuration;
					let dashTick = b.displayStart + MidiUtils.QuarterTime;
					while (dashTick < endTick) {
						if (endTick - dashTick >= MidiUtils.QuarterTime) {
							const dash = new NumberedDashBeatContainerGlyph(v.index, absoluteStart + dashTick);
							this.addBeatGlyph(dash);
							mainContainer.addDash(dash);
						} else if (b.duration === Duration.Half && b.dots > 1) {
							const remainingTickNumber = new NumberedNoteBeatContainerGlyphBase(b, absoluteStart + dashTick, endTick - dashTick);
							this.addBeatGlyph(remainingTickNumber);
							mainContainer.addNotes(remainingTickNumber);
						}
						dashTick += MidiUtils.QuarterTime;
					}
				}
			}
		}
		paintBeamingStem(_beat, _cy, _x, _topY, _bottomY, _canvas) {}
		get beamSpacing() {
			return this.smuflMetrics.numberedBarRendererBarSpacing;
		}
		get beamThickness() {
			return this.smuflMetrics.numberedBarRendererBarSize;
		}
		paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement) {
			if (h.voice?.index === 0) super.paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement);
		}
		applyBarShift(_h, _direction, _drawingInfo, _barCount) {
			return 0;
		}
		calculateBeamYWithDirection(h, _x, direction) {
			this.ensureBeamDrawingInfo(h, direction);
			const info = h.drawingInfos.get(direction);
			if (direction === BeamDirection.Up) return Math.min(info.startY, info.endY);
			else return Math.max(info.startY, info.endY);
		}
		paintTuplets(cx, cy, canvas, beatElement, _bracketsAsArcs = false) {
			super.paintTuplets(cx, cy, canvas, beatElement, true);
		}
	};
	//#endregion
	//#region src/rendering/NumberedBarRendererFactory.ts
	/**
	* This Factory produces NumberedBarRenderer instances
	* @internal
	*/
	var NumberedBarRendererFactory = class extends BarRendererFactory {
		get staffId() {
			return NumberedBarRenderer.StaffId;
		}
		create(renderer, bar) {
			return new NumberedBarRenderer(renderer, bar);
		}
		canCreate(track, staff) {
			return super.canCreate(track, staff) && staff.showNumbered;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ClefGlyph.ts
	/**
	* @internal
	*/
	var ClefGlyph = class ClefGlyph extends MusicFontGlyph {
		_clef;
		_clefOttava;
		_ottavaGlyph;
		constructor(x, y, clef, clefOttava) {
			super(x, y, 1, ClefGlyph._getSymbol(clef, clefOttava));
			this._clef = clef;
			this._clefOttava = clefOttava;
		}
		getBoundingBoxTop() {
			let top = super.getBoundingBoxTop();
			const ottava = this._ottavaGlyph;
			if (ottava) {
				const ottavaTop = this.y + ottava.getBoundingBoxTop();
				top = ModelUtils.minBoundingBox(top, ottavaTop);
			}
			return top;
		}
		getBoundingBoxBottom() {
			let bottom = super.getBoundingBoxBottom();
			const ottava = this._ottavaGlyph;
			if (ottava) {
				const ottavaBottom = this.y + ottava.getBoundingBoxBottom();
				bottom = ModelUtils.maxBoundingBox(bottom, ottavaBottom);
			}
			return bottom;
		}
		doLayout() {
			this.center = true;
			super.doLayout();
			this.width = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.GClef);
			this.offsetX = this.width / 2;
			this._ottavaGlyph = void 0;
			switch (this._clef) {
				case Clef.C3:
				case Clef.C4:
					switch (this._clefOttava) {
						case Ottavia._8vb: return;
					}
					break;
				case Clef.F4:
				case Clef.G2: return;
			}
			let ottavaSymbol;
			let top = false;
			switch (this._clefOttava) {
				case Ottavia._15ma:
					ottavaSymbol = MusicFontSymbol.Clef15;
					top = true;
					break;
				case Ottavia._8va:
					ottavaSymbol = MusicFontSymbol.Clef8;
					top = true;
					break;
				case Ottavia._8vb:
					ottavaSymbol = MusicFontSymbol.Clef8;
					break;
				case Ottavia._15mb:
					ottavaSymbol = MusicFontSymbol.Clef15;
					break;
				default: return;
			}
			const ottavaX = this.width / 2;
			const ottavaY = top ? this.renderer.smuflMetrics.glyphTop.get(this.symbol) : this.renderer.smuflMetrics.glyphBottom.get(this.symbol) - this.renderer.smuflMetrics.glyphHeights.get(ottavaSymbol);
			this._ottavaGlyph = new MusicFontGlyph(ottavaX, -ottavaY, 1, ottavaSymbol);
			this._ottavaGlyph.center = true;
			this._ottavaGlyph.renderer = this.renderer;
			this._ottavaGlyph.doLayout();
		}
		static _getSymbol(clef, clefOttava) {
			switch (clef) {
				case Clef.Neutral: return MusicFontSymbol.UnpitchedPercussionClef1;
				case Clef.C3:
				case Clef.C4: switch (clefOttava) {
					case Ottavia._8vb: return MusicFontSymbol.CClef8vb;
					default: return MusicFontSymbol.CClef;
				}
				case Clef.F4: switch (clefOttava) {
					case Ottavia._15ma: return MusicFontSymbol.FClef15ma;
					case Ottavia._8va: return MusicFontSymbol.FClef8va;
					case Ottavia._8vb: return MusicFontSymbol.FClef8vb;
					case Ottavia._15mb: return MusicFontSymbol.FClef15mb;
					default: return MusicFontSymbol.FClef;
				}
				case Clef.G2: switch (clefOttava) {
					case Ottavia._15ma: return MusicFontSymbol.GClef15ma;
					case Ottavia._8va: return MusicFontSymbol.GClef8va;
					case Ottavia._8vb: return MusicFontSymbol.GClef8vb;
					case Ottavia._15mb: return MusicFontSymbol.GClef15mb;
					default: return MusicFontSymbol.GClef;
				}
				default: return MusicFontSymbol.None;
			}
		}
		paint(cx, cy, canvas) {
			const _ = ElementStyleHelper.bar(canvas, BarSubElement.StandardNotationClef, this.renderer.bar);
			try {
				super.paint(cx, cy, canvas);
				const ottava = this._ottavaGlyph;
				if (ottava) ottava.paint(cx + this.x, cy + this.y, canvas);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/KeySignatureGlyph.ts
	/**
	* @internal
	*/
	var KeySignatureGlyph = class extends LeftToRightLayoutingGlyphGroup {
		paint(cx, cy, canvas) {
			const _ = ElementStyleHelper.bar(canvas, BarSubElement.StandardNotationKeySignature, this.renderer.bar);
			try {
				super.paint(cx, cy, canvas);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/AccentuationGlyph.ts
	/**
	* @internal
	*/
	var AccentuationGlyph = class AccentuationGlyph extends EffectGlyph {
		_note;
		constructor(x, y, note) {
			super(x, y);
			this._note = note;
		}
		static _getSymbol(accentuation, above) {
			switch (accentuation) {
				case AccentuationType.None: return MusicFontSymbol.None;
				case AccentuationType.Normal: return above ? MusicFontSymbol.ArticAccentAbove : MusicFontSymbol.ArticAccentBelow;
				case AccentuationType.Heavy: return above ? MusicFontSymbol.ArticMarcatoAbove : MusicFontSymbol.ArticMarcatoBelow;
				case AccentuationType.Tenuto: return above ? MusicFontSymbol.ArticTenutoAbove : MusicFontSymbol.ArticTenutoBelow;
				default: return MusicFontSymbol.None;
			}
		}
		doLayout() {
			this.width = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.ArticAccentAbove);
			this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.ArticAccentAbove);
		}
		paint(cx, cy, canvas) {
			const dir = this.renderer.getBeatDirection(this._note.beat);
			const symbol = AccentuationGlyph._getSymbol(this._note.accentuated, dir === BeamDirection.Down);
			const y = dir === BeamDirection.Up ? cy + this.y : cy + this.y + this.height;
			CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, y, 1, symbol, true);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ArticStaccatoAboveGlyph.ts
	/**
	* @internal
	*/
	var ArticStaccatoAboveGlyph = class extends MusicFontGlyph {
		constructor(x, y) {
			super(x, y, EngravingSettings.GraceScale, MusicFontSymbol.ArticStaccatoAbove);
			this.center = true;
		}
		doLayout() {
			super.doLayout();
			this.offsetY = this.height;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NoteHeadGlyph.ts
	/**
	* @internal
	*/
	var NoteHeadGlyphBase = class extends MusicFontGlyph {
		centerOnStem = false;
		constructor(x, y, isGrace, symbol) {
			super(x, y, isGrace ? EngravingSettings.GraceScale : 1, symbol);
		}
		paint(cx, cy, canvas) {
			if (this.centerOnStem) this.center = true;
			super.paint(cx, cy, canvas);
		}
	};
	/**
	* @internal
	*/
	var NoteHeadGlyph = class NoteHeadGlyph extends NoteHeadGlyphBase {
		constructor(x, y, duration, isGrace) {
			super(x, y, isGrace, NoteHeadGlyph.getSymbol(duration));
		}
		static getSymbol(duration) {
			switch (duration) {
				case Duration.QuadrupleWhole: return MusicFontSymbol.NoteheadDoubleWholeSquare;
				case Duration.DoubleWhole: return MusicFontSymbol.NoteheadDoubleWhole;
				case Duration.Whole: return MusicFontSymbol.NoteheadWhole;
				case Duration.Half: return MusicFontSymbol.NoteheadHalf;
				default: return MusicFontSymbol.NoteheadBlack;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/DeadNoteHeadGlyph.ts
	/**
	* @internal
	*/
	var DeadNoteHeadGlyph = class extends NoteHeadGlyphBase {
		constructor(x, y, isGrace) {
			super(x, y, isGrace, MusicFontSymbol.NoteheadXOrnate);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/DiamondNoteHeadGlyph.ts
	/**
	* @internal
	*/
	var DiamondNoteHeadGlyph = class DiamondNoteHeadGlyph extends NoteHeadGlyphBase {
		constructor(x, y, duration, isGrace) {
			super(x, y, isGrace, DiamondNoteHeadGlyph._getSymbol(duration));
		}
		static _getSymbol(duration) {
			switch (duration) {
				case Duration.QuadrupleWhole:
				case Duration.DoubleWhole:
				case Duration.Whole:
				case Duration.Half: return MusicFontSymbol.NoteheadDiamondWhiteWide;
				default: return MusicFontSymbol.NoteheadDiamondBlackWide;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/GhostNoteContainerGlyph.ts
	/**
	* @internal
	*/
	var GhostNoteInfo = class {
		steps = 0;
		isGhost;
		color;
		constructor(line, isGhost, color) {
			this.steps = line;
			this.isGhost = isGhost;
			this.color = color;
		}
	};
	/**
	* @internal
	*/
	var GhostNoteContainerGlyph = class extends Glyph {
		_isOpen;
		_infos = [];
		_glyphs = [];
		isEmpty = true;
		constructor(isOpen) {
			super(0, 0);
			this._isOpen = isOpen;
		}
		addParenthesis(n) {
			const sr = this.renderer;
			const steps = sr.getNoteSteps(n);
			const hasParenthesis = n.isGhost || this._isTiedBend(n) && sr.settings.notation.isNotationElementVisible(NotationElement.ParenthesisOnTiedBends);
			const color = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.Effects, n);
			this._add(new GhostNoteInfo(steps, hasParenthesis, color));
		}
		addParenthesisOnSteps(line, hasParenthesis) {
			const info = new GhostNoteInfo(line, hasParenthesis, void 0);
			this._add(info);
		}
		_add(info) {
			this._infos.push(info);
			if (info.isGhost) this.isEmpty = false;
		}
		_isTiedBend(note) {
			if (note.isTieDestination) {
				if (note.tieOrigin.hasBend) return true;
				return this._isTiedBend(note.tieOrigin);
			}
			return false;
		}
		doLayout() {
			const sr = this.renderer;
			this._infos.sort((a, b) => {
				return a.steps - b.steps;
			});
			let previousGlyph = null;
			const sizePerLine = sr.getScoreHeight(1);
			for (let i = 0, j = this._infos.length; i < j; i++) {
				let g;
				if (!this._infos[i].isGhost) previousGlyph = null;
				else if (!previousGlyph) {
					g = new GhostParenthesisGlyph(this._isOpen);
					g.colorOverride = this._infos[i].color;
					g.renderer = this.renderer;
					g.y = sr.getScoreY(this._infos[i].steps) - sizePerLine;
					g.height = sizePerLine * 2;
					g.doLayout();
					this._glyphs.push(g);
					previousGlyph = g;
				} else {
					const y = sr.getScoreY(this._infos[i].steps) + sizePerLine;
					previousGlyph.height = y - previousGlyph.y;
				}
			}
			this.width = this._glyphs.length > 0 ? this._glyphs[0].width : 0;
		}
		paint(cx, cy, canvas) {
			super.paint(cx, cy, canvas);
			for (const g of this._glyphs) g.paint(cx + this.x, cy + this.y, canvas);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/PercussionNoteHeadGlyph.ts
	/**
	* @internal
	*/
	var PercussionNoteHeadGlyph = class extends NoteHeadGlyphBase {
		_isGrace;
		_articulation;
		constructor(x, y, articulation, duration, isGrace) {
			super(x, y, isGrace, articulation.getSymbol(duration));
			this._isGrace = isGrace;
			this._articulation = articulation;
		}
		paint(cx, cy, canvas) {
			const c = canvas.color;
			if (this.colorOverride) canvas.color = this.colorOverride;
			const offset = this._isGrace ? 1 : 0;
			CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, cy + this.y + offset, this.glyphScale, this.symbol, false);
			if (this._articulation.techniqueSymbol !== MusicFontSymbol.None && this._articulation.techniqueSymbolPlacement === TechniqueSymbolPlacement.Inside) CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, cy + this.y + offset, this.glyphScale, this._articulation.techniqueSymbol, false);
			canvas.color = c;
		}
		doLayout() {
			super.doLayout();
			if (this.width === 0) this.height = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.NoteheadBlack);
			if (this.height === 0) this.height = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.NoteheadBlack);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/PictEdgeOfCymbalGlyph.ts
	/**
	* @internal
	*/
	var PictEdgeOfCymbalGlyph = class extends MusicFontGlyph {
		constructor(x, y) {
			super(x, y, .5, MusicFontSymbol.PictEdgeOfCymbal);
			this.center = true;
		}
		doLayout() {
			super.doLayout();
			this.offsetY = this.height;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreNoteChordGlyphBase.ts
	/**
	* @internal
	*/
	var ScoreChordNoteHeadInfo = class ScoreChordNoteHeadInfo {
		/**
		* The direction of the main voice.
		*/
		mainVoiceDirection = BeamDirection.Up;
		/**
		* All groups respective to their direction.
		*/
		groups = /* @__PURE__ */ new Map();
		minX = 0;
		maxX = 0;
		_isFinished = false;
		constructor(mainVoiceDirection) {
			this.mainVoiceDirection = mainVoiceDirection;
		}
		update() {
			let minX = 0;
			let maxX = 0;
			for (const g of this.groups.values()) {
				const gMinX = g.minX + g.multiVoiceShiftX;
				const gMaxX = g.maxX + g.multiVoiceShiftX;
				if (gMinX < minX) minX = gMinX;
				if (maxX < gMaxX) maxX = gMaxX;
			}
			this.minX = minX;
			this.maxX = maxX;
		}
		finish(smufl) {
			if (this._isFinished) return;
			this._isFinished = true;
			for (const g of this.groups.values()) this._checkForGroupDisplacement(g, smufl);
			this.update();
		}
		_checkForGroupDisplacement(noteGroup, smufl) {
			if (this.mainVoiceDirection === noteGroup.direction) return;
			const mainGroup = this.groups.get(this.mainVoiceDirection);
			const intersection = ScoreChordNoteHeadInfo._checkIntersection(mainGroup, noteGroup);
			const spacing = smufl.multiVoiceDisplacedNoteHeadSpacing;
			switch (intersection) {
				case 0: return;
				case 3:
					if (!ScoreChordNoteHeadInfo._canShareNoteHead(mainGroup, noteGroup)) if (mainGroup.direction === BeamDirection.Up) if (noteGroup.displacedNotes) noteGroup.multiVoiceShiftX = noteGroup.stemX + noteGroup.correctNotes.width + spacing;
					else noteGroup.multiVoiceShiftX = noteGroup.correctNotes.width + spacing;
					else mainGroup.multiVoiceShiftX = noteGroup.stemX + spacing;
					break;
				case 1:
					if (mainGroup.direction === BeamDirection.Up) if (mainGroup.displacedNotes) noteGroup.multiVoiceShiftX = mainGroup.stemX;
					else noteGroup.multiVoiceShiftX = mainGroup.stemX - noteGroup.stemX;
					else if (mainGroup.displacedNotes) noteGroup.multiVoiceShiftX = -noteGroup.stemX;
					else mainGroup.multiVoiceShiftX = noteGroup.stemX - mainGroup.stemX;
					break;
				case 2:
					if (mainGroup.direction === BeamDirection.Up) {
						mainGroup.multiVoiceShiftX = mainGroup.stemX;
						if (noteGroup.hasFlag) mainGroup.multiVoiceShiftX += spacing;
					} else {
						noteGroup.multiVoiceShiftX = noteGroup.stemX;
						if (mainGroup.hasFlag) noteGroup.multiVoiceShiftX += spacing;
					}
					break;
				case 4:
					if (!mainGroup.hasStem && !noteGroup.hasStem) {} else if (mainGroup.direction === BeamDirection.Up) {
						mainGroup.multiVoiceShiftX = mainGroup.stemX;
						if (noteGroup.hasFlag) mainGroup.multiVoiceShiftX += spacing;
						else mainGroup.multiVoiceShiftX -= spacing;
					} else {
						noteGroup.multiVoiceShiftX = noteGroup.stemX;
						if (mainGroup.hasFlag) noteGroup.multiVoiceShiftX += spacing;
						else noteGroup.multiVoiceShiftX -= spacing;
					}
					break;
			}
		}
		static _canShareNoteHead(mainGroup, thisGroup) {
			const mainGroupBottom = mainGroup.direction === BeamDirection.Up ? mainGroup.maxStep : mainGroup.minStep;
			const thisGroupBottom = thisGroup.direction === BeamDirection.Up ? thisGroup.maxStep : thisGroup.minStep;
			const mainGroupBottomNoteHead = mainGroup.correctNotes.notes.get(mainGroupBottom);
			if (mainGroupBottomNoteHead.length > 1) return false;
			const thisGroupBottomNoteHead = thisGroup.correctNotes.notes.get(thisGroupBottom);
			if (thisGroupBottomNoteHead.length > 1) return false;
			return ScoreChordNoteHeadInfo._canShareNoteHeadGlyph(mainGroupBottomNoteHead[0].glyph, thisGroupBottomNoteHead[0].glyph);
		}
		static _canShareNoteHeadGlyph(mainGlyph, thisGlyph) {
			return mainGlyph.glyphScale === thisGlyph.glyphScale && mainGlyph.centerOnStem === thisGlyph.centerOnStem && MusicFontSymbolLookup.isBlackNoteHead(mainGlyph.symbol) && MusicFontSymbolLookup.isBlackNoteHead(thisGlyph.symbol);
		}
		static _checkIntersection(mainGroup, thisGroup) {
			let bottomGap = 0;
			if (mainGroup.direction === BeamDirection.Up) {
				const mainGroupBottom = mainGroup.maxStep;
				bottomGap = thisGroup.minStep - mainGroupBottom;
			} else bottomGap = mainGroup.minStep - thisGroup.maxStep;
			if (bottomGap === 0) return 3;
			if (bottomGap === 1) return 1;
			if (bottomGap === -1) return 2;
			if (bottomGap < 0) return 4;
			return 0;
		}
	};
	/**
	* @internal
	*/
	var ScoreNoteChordGlyphBase = class ScoreNoteChordGlyphBase extends Glyph {
		_infos = [];
		_noteHeadInfo;
		noteGroup;
		minStepsNote = null;
		maxStepsNote = null;
		get stemX() {
			if (!this.noteGroup) return 0;
			return this.noteGroup.stemX + this.noteGroup.multiVoiceShiftX;
		}
		noteStartX = 0;
		onTimeX = 0;
		constructor() {
			super(0, 0);
		}
		getBoundingBoxTop() {
			return this.minStepsNote ? this.minStepsNote.glyph.getBoundingBoxTop() : this.y;
		}
		getBoundingBoxBottom() {
			return this.maxStepsNote ? this.maxStepsNote.glyph.getBoundingBoxBottom() : this.y + this.height;
		}
		add(noteGlyph, noteSteps) {
			const info = {
				glyph: noteGlyph,
				steps: noteSteps
			};
			this._infos.push(info);
			if (!this.minStepsNote || this.minStepsNote.steps > info.steps) this.minStepsNote = info;
			if (!this.maxStepsNote || this.maxStepsNote.steps < info.steps) this.maxStepsNote = info;
		}
		_prepareForLayout(info) {
			const direction = this.direction;
			if (!info.groups) info.mainVoiceDirection = direction;
			if (direction === BeamDirection.Up) this._infos.sort((a, b) => {
				return b.steps - a.steps;
			});
			else this._infos.sort((a, b) => {
				return a.steps - b.steps;
			});
			let group;
			const hasFlag = this.hasFlag;
			const hasStem = this.hasStem;
			if (info.groups.has(direction)) {
				group = info.groups.get(direction);
				if (hasFlag) group.hasFlag = hasFlag;
				if (hasStem) group.hasStem = hasStem;
			} else {
				group = {
					correctNotes: {
						notes: /* @__PURE__ */ new Map(),
						width: 0,
						minX: NaN
					},
					direction,
					stemX: 0,
					maxX: NaN,
					minX: NaN,
					minStep: NaN,
					maxStep: NaN,
					multiVoiceShiftX: 0,
					hasFlag,
					hasStem
				};
				info.groups.set(direction, group);
			}
			return group;
		}
		doLayout() {
			const info = this.getScoreChordNoteHeadInfo();
			const noteGroup = this._prepareForLayout(info);
			this.noteGroup = noteGroup;
			this._noteHeadInfo = info;
			this._collectNoteDisplacements(noteGroup);
			this._alignNoteHeadsGroup(noteGroup);
			info.update();
			this._updateSizes();
		}
		_updateSizes() {
			const noteGroup = this.noteGroup;
			this.onTimeX = noteGroup.correctNotes.minX + noteGroup.correctNotes.width / 2;
			this.width = this.noteStartX + noteGroup.multiVoiceShiftX + noteGroup.maxX - noteGroup.minX;
		}
		doMultiVoiceLayout() {
			this._noteHeadInfo.finish(this.renderer.smuflMetrics);
			this._updateSizes();
		}
		_alignNoteHeadsGroup(noteGroup) {
			if (noteGroup.direction === BeamDirection.Up) {
				this._alignNoteHeads(noteGroup, noteGroup.correctNotes, true);
				if (noteGroup.displacedNotes) this._alignNoteHeads(noteGroup, noteGroup.displacedNotes, false);
			} else {
				this._alignNoteHeads(noteGroup, noteGroup.correctNotes, false);
				if (noteGroup.displacedNotes) this._alignNoteHeads(noteGroup, noteGroup.displacedNotes, true);
			}
		}
		_alignNoteHeads(noteGroup, side, leftOfStem) {
			const scale = this.scale;
			const smufl = this.renderer.smuflMetrics;
			for (const stepInfos of side.notes.values()) for (const info of stepInfos) {
				info.glyph.x = noteGroup.stemX;
				if (info.glyph.centerOnStem) {} else if (leftOfStem) if (smufl.stemUp.has(info.glyph.symbol)) info.glyph.x -= smufl.stemUp.get(info.glyph.symbol).x * scale;
				else info.glyph.x -= smufl.glyphWidths.get(info.glyph.symbol) * scale;
				else if (smufl.stemDown.has(info.glyph.symbol)) info.glyph.x += smufl.stemDown.get(info.glyph.symbol).x * scale;
				side.width = Math.max(side.width, info.glyph.width);
				if (Number.isNaN(side.minX) || info.glyph.x < side.minX) side.minX = info.glyph.x;
				if (Number.isNaN(noteGroup.minX) || info.glyph.x < noteGroup.minX) noteGroup.minX = info.glyph.x;
				const maxX = info.glyph.x + info.glyph.width;
				if (Number.isNaN(noteGroup.maxX) || maxX > noteGroup.maxX) noteGroup.maxX = maxX;
			}
		}
		static _hasCollision(side, info) {
			return side.notes.has(info.steps) || side.notes.has(info.steps + 1) || side.notes.has(info.steps - 1);
		}
		_collectNoteDisplacements(noteGroup) {
			for (const info of this._infos) {
				info.glyph.renderer = this.renderer;
				info.glyph.doLayout();
				const isGroupCollision = ScoreNoteChordGlyphBase._hasCollision(noteGroup.correctNotes, info);
				let noteLookup;
				if (isGroupCollision) {
					if (!noteGroup.displacedNotes) noteGroup.displacedNotes = {
						notes: /* @__PURE__ */ new Map(),
						width: 0,
						minX: 0
					};
					noteLookup = noteGroup.displacedNotes;
				} else noteLookup = noteGroup.correctNotes;
				let stepInfos;
				if (noteLookup.notes.has(info.steps)) stepInfos = noteLookup.notes.get(info.steps);
				else {
					stepInfos = [];
					noteLookup.notes.set(info.steps, stepInfos);
				}
				stepInfos.push(info);
				if (Number.isNaN(noteGroup.minStep) || info.steps < noteGroup.minStep) noteGroup.minStep = info.steps;
				if (Number.isNaN(noteGroup.maxStep) || info.steps > noteGroup.maxStep) noteGroup.maxStep = info.steps;
				this._updateGroupStemXPosition(info, noteGroup);
			}
		}
		_updateGroupStemXPosition(info, noteGroup) {
			const smufl = this.renderer.smuflMetrics;
			const scale = this.scale;
			let stemX;
			if (noteGroup.direction === BeamDirection.Up || noteGroup.displacedNotes) if (smufl.stemUp.has(info.glyph.symbol)) stemX = smufl.stemUp.get(info.glyph.symbol).x * scale;
			else stemX = smufl.glyphWidths.get(info.glyph.symbol) * scale;
			else if (smufl.stemDown.has(info.glyph.symbol)) stemX = smufl.stemDown.get(info.glyph.symbol).x * scale;
			else stemX = 0;
			stemX += this.noteStartX;
			if (stemX > noteGroup.stemX) noteGroup.stemX = stemX;
		}
		paint(cx, cy, canvas) {
			cx += this.x;
			cy += this.y;
			this._paintLedgerLines(cx, cy, canvas);
			const noteGroup = this.noteGroup;
			cx += noteGroup.multiVoiceShiftX;
			const infos = this._infos;
			for (const g of infos) {
				g.glyph.renderer = this.renderer;
				g.glyph.paint(cx, cy, canvas);
			}
		}
		_paintLedgerLines(cx, cy, canvas) {
			if (!this.minStepsNote) return;
			const scoreRenderer = this.renderer;
			const _ = ElementStyleHelper.bar(canvas, BarSubElement.StandardNotationStaffLine, scoreRenderer.bar, true);
			try {
				const scale = this.scale;
				const lineExtension = this.renderer.smuflMetrics.legerLineExtension * scale;
				const lineWidth = this.width + lineExtension * 2 - this.noteStartX;
				const lineSpacing = scoreRenderer.getLineHeight(1);
				const firstTopLedgerY = scoreRenderer.getLineY(-1);
				const firstBottomLedgerY = scoreRenderer.getLineY(scoreRenderer.drawnLineCount);
				const minNoteLineY = scoreRenderer.getLineY(this.minStepsNote.steps / 2);
				const maxNoteLineY = scoreRenderer.getLineY(this.maxStepsNote.steps / 2);
				const lineYOffset = this.renderer.smuflMetrics.legerLineThickness * scale / 2;
				let y = firstTopLedgerY;
				while (y >= minNoteLineY) {
					canvas.fillRect(cx - lineExtension + this.noteStartX, cy + y - lineYOffset, lineWidth, this.renderer.smuflMetrics.legerLineThickness * scale);
					y -= lineSpacing;
				}
				y = firstBottomLedgerY;
				while (y <= maxNoteLineY) {
					canvas.fillRect(cx - lineExtension + this.noteStartX, cy + y - lineYOffset, lineWidth, this.renderer.smuflMetrics.legerLineThickness * scale);
					y += lineSpacing;
				}
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TremoloPickingGlyph.ts
	/**
	* @internal
	*/
	var TremoloPickingGlyph = class TremoloPickingGlyph extends MusicFontGlyph {
		constructor(x, y, effect) {
			super(x, y, 1, TremoloPickingGlyph._getSymbol(effect));
		}
		static _getSymbol(effect) {
			if (effect.style === TremoloPickingStyle.BuzzRoll) return MusicFontSymbol.BuzzRoll;
			else switch (effect.marks) {
				case 1: return MusicFontSymbol.Tremolo1;
				case 2: return MusicFontSymbol.Tremolo2;
				case 3: return MusicFontSymbol.Tremolo3;
				case 4: return MusicFontSymbol.Tremolo4;
				case 5: return MusicFontSymbol.Tremolo5;
				default: return MusicFontSymbol.None;
			}
		}
		stemExtensionHeight = 0;
		alignTremoloPickingGlyph(direction, flagEnd, firstNoteY, duration) {
			const lr = this.renderer;
			const smufl = lr.smuflMetrics;
			let tremoloY = 0;
			const tremoloOverlap = smufl.glyphHeights.get(MusicFontSymbol.Tremolo1) / 2;
			const tremoloCenterOffset = this.height / 2;
			const forceAlignWithStaffLine = this.symbol === MusicFontSymbol.Tremolo1;
			const lineSpacing = lr.lineSpacing;
			const spacing = forceAlignWithStaffLine ? lineSpacing : lineSpacing / 2;
			if (direction === BeamDirection.Up) {
				let flagBottom = flagEnd;
				flagBottom += smufl.stemFlagHeight.get(duration);
				flagBottom -= smufl.stemFlagOffsets.get(duration);
				tremoloY = spacing * Math.ceil(flagBottom / spacing);
				const tremoloBottomY = tremoloY + tremoloCenterOffset;
				const minSpacingY = firstNoteY - lineSpacing;
				if (minSpacingY < tremoloBottomY) tremoloY = minSpacingY - tremoloCenterOffset;
				flagBottom += tremoloOverlap;
				const tremoloTop = tremoloY - tremoloCenterOffset;
				if (flagBottom > tremoloTop) this.stemExtensionHeight = flagBottom - tremoloTop;
				else this.stemExtensionHeight = 0;
			} else {
				let flagTop = flagEnd;
				flagTop -= smufl.stemFlagHeight.get(duration);
				flagTop += smufl.stemFlagOffsets.get(duration);
				tremoloY = spacing * Math.floor(flagTop / spacing);
				const tremoloTopY = tremoloY - tremoloCenterOffset;
				const minSpacingY = firstNoteY + lineSpacing;
				if (minSpacingY > tremoloTopY) tremoloY = minSpacingY + tremoloCenterOffset;
				flagTop -= tremoloOverlap;
				const tremoloBottom = tremoloY + tremoloCenterOffset;
				if (flagTop < tremoloBottom) this.stemExtensionHeight = tremoloBottom - flagTop;
				else this.stemExtensionHeight = 0;
			}
			this.y = tremoloY;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreNoteChordGlyph.ts
	/**
	* @internal
	*/
	var ScoreNoteChordGlyph = class extends ScoreNoteChordGlyphBase {
		_noteGlyphLookup = /* @__PURE__ */ new Map();
		_notes = [];
		_deadSlapped = null;
		_tremoloPicking = null;
		_stemLengthExtension = 0;
		aboveBeatEffects = /* @__PURE__ */ new Map();
		belowBeatEffects = /* @__PURE__ */ new Map();
		beat;
		get direction() {
			return this.renderer.getBeatDirection(this.beat);
		}
		get hasFlag() {
			return this.renderer.hasFlag(this.beat);
		}
		get hasStem() {
			return this.renderer.hasStem(this.beat);
		}
		get scale() {
			return this.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
		}
		getScoreChordNoteHeadInfo() {
			if (this.beat.graceType !== GraceType.None) return new ScoreChordNoteHeadInfo(this.direction);
			const staff = this.beat.voice.bar.staff;
			const key = `score.noteheads.${staff.track.index}.${staff.index}.${this.beat.voice.bar.index}.${this.beat.absoluteDisplayStart}`;
			let existing = this.renderer.staff.getSharedLayoutData(key, void 0);
			if (!existing) {
				existing = new ScoreChordNoteHeadInfo(this.direction);
				this.renderer.staff.setSharedLayoutData(key, existing);
			}
			return existing;
		}
		getNoteX(note, requestedPosition) {
			if (this._noteGlyphLookup.has(note.id)) {
				const n = this._noteGlyphLookup.get(note.id);
				let pos = this.x + n.x;
				switch (requestedPosition) {
					case NoteXPosition.Left: break;
					case NoteXPosition.Center:
						pos += n.width / 2;
						break;
					case NoteXPosition.Right:
						pos += n.width;
						break;
				}
				return pos;
			}
			return 0;
		}
		getNoteY(note, requestedPosition) {
			if (this._noteGlyphLookup.has(note.id)) {
				const n = this._noteGlyphLookup.get(note.id);
				return this._internalGetNoteY(n, requestedPosition);
			}
			return 0;
		}
		getLowestNoteY(requestedPosition) {
			return this.maxStepsNote ? this._internalGetNoteY(this.maxStepsNote.glyph, requestedPosition) : 0;
		}
		getHighestNoteY(requestedPosition) {
			return this.minStepsNote ? this._internalGetNoteY(this.minStepsNote.glyph, requestedPosition) : 0;
		}
		_internalGetNoteY(n, requestedPosition) {
			let pos = this.y + n.y;
			const sr = this.renderer;
			const scale = this.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
			switch (requestedPosition) {
				case NoteYPosition.TopWithStem:
					pos -= (sr.smuflMetrics.stemUp.has(n.symbol) ? sr.smuflMetrics.stemUp.get(n.symbol).bottomY : 0) * scale;
					pos -= sr.smuflMetrics.getStemLength(this.beat.duration, sr.hasFlag(this.beat)) * scale;
					pos -= this._stemLengthExtension;
					let topCenterY = sr.centerStaffStemY(this.direction);
					topCenterY -= this._stemLengthExtension;
					return Math.min(topCenterY, pos);
				case NoteYPosition.Top:
					pos -= n.height / 2;
					break;
				case NoteYPosition.Center: break;
				case NoteYPosition.Bottom:
					pos += n.height / 2;
					break;
				case NoteYPosition.BottomWithStem:
					pos -= (this.renderer.smuflMetrics.stemDown.has(n.symbol) ? this.renderer.smuflMetrics.stemDown.get(n.symbol).topY : -this.renderer.smuflMetrics.glyphHeights.get(n.symbol) / 2) * scale;
					pos += sr.smuflMetrics.getStemLength(this.beat.duration, sr.hasFlag(this.beat)) * scale;
					pos += this._stemLengthExtension;
					let bottomCenterY = sr.centerStaffStemY(this.direction);
					bottomCenterY += this._stemLengthExtension;
					return Math.max(bottomCenterY, pos);
				case NoteYPosition.StemUp:
					pos -= (sr.smuflMetrics.stemUp.has(n.symbol) ? sr.smuflMetrics.stemUp.get(n.symbol).bottomY : 0) * scale;
					break;
				case NoteYPosition.StemDown:
					pos -= (sr.smuflMetrics.stemDown.has(n.symbol) ? sr.smuflMetrics.stemDown.get(n.symbol).topY : -sr.smuflMetrics.glyphHeights.get(n.symbol) / 2) * scale;
					break;
			}
			return pos;
		}
		addMainNoteGlyph(noteGlyph, note, noteLine) {
			super.add(noteGlyph, noteLine);
			this._noteGlyphLookup.set(note.id, noteGlyph);
			this._notes.push(note);
		}
		addEffectNoteGlyph(noteGlyph, noteLine) {
			super.add(noteGlyph, noteLine);
		}
		doLayout() {
			super.doLayout();
			const scoreRenderer = this.renderer;
			if (this.beat.deadSlapped) {
				this._deadSlapped = new DeadSlappedBeatGlyph();
				this._deadSlapped.renderer = this.renderer;
				this._deadSlapped.doLayout();
				this.width = this._deadSlapped.width;
				this.onTimeX = this.width / 2;
			}
			let aboveBeatEffectsY = 0;
			let belowBeatEffectsY = 0;
			const effectSpacing = this.renderer.smuflMetrics.onNoteEffectPadding;
			if (this.beat.deadSlapped) {
				belowBeatEffectsY = scoreRenderer.getScoreY(0);
				aboveBeatEffectsY = scoreRenderer.getScoreY(scoreRenderer.heightLineCount);
			} else if (this.direction === BeamDirection.Up) {
				belowBeatEffectsY = this._internalGetNoteY(this.maxStepsNote.glyph, NoteYPosition.Bottom) + effectSpacing;
				aboveBeatEffectsY = this._internalGetNoteY(this.minStepsNote.glyph, NoteYPosition.TopWithStem) - effectSpacing;
			} else {
				belowBeatEffectsY = this._internalGetNoteY(this.maxStepsNote.glyph, NoteYPosition.BottomWithStem) + effectSpacing;
				aboveBeatEffectsY = this._internalGetNoteY(this.minStepsNote.glyph, NoteYPosition.Top) - effectSpacing;
			}
			let minEffectY = null;
			let maxEffectY = null;
			for (const effect of this.aboveBeatEffects.values()) {
				effect.renderer = this.renderer;
				effect.doLayout();
				aboveBeatEffectsY -= effect.height;
				effect.y = aboveBeatEffectsY;
				if (minEffectY === null || minEffectY > aboveBeatEffectsY) minEffectY = aboveBeatEffectsY;
				if (maxEffectY === null || maxEffectY < aboveBeatEffectsY) maxEffectY = aboveBeatEffectsY;
				aboveBeatEffectsY -= effectSpacing;
			}
			for (const effect of this.belowBeatEffects.values()) {
				effect.renderer = this.renderer;
				effect.doLayout();
				effect.y = belowBeatEffectsY;
				if (minEffectY === null || minEffectY > belowBeatEffectsY) minEffectY = belowBeatEffectsY;
				if (maxEffectY === null || maxEffectY < belowBeatEffectsY) maxEffectY = belowBeatEffectsY;
				belowBeatEffectsY += effect.height + effectSpacing;
			}
			if (minEffectY !== null) scoreRenderer.registerBeatEffectOverflows(minEffectY, maxEffectY ?? 0);
			if (this.beat.isTremolo && !this.beat.deadSlapped) {
				this._tremoloPicking = new TremoloPickingGlyph(0, 0, this.beat.tremoloPicking);
				this._tremoloPicking.renderer = this.renderer;
				this._tremoloPicking.doLayout();
				this._alignTremoloPickingGlyph();
			}
		}
		_alignTremoloPickingGlyph() {
			const g = this._tremoloPicking;
			const direction = this.direction;
			if (direction === BeamDirection.Up) g.alignTremoloPickingGlyph(direction, this.getHighestNoteY(NoteYPosition.TopWithStem), this.getHighestNoteY(NoteYPosition.Center), this.beat.duration);
			else g.alignTremoloPickingGlyph(direction, this.getLowestNoteY(NoteYPosition.BottomWithStem), this.getLowestNoteY(NoteYPosition.Center), this.beat.duration);
			this._stemLengthExtension = g.stemExtensionHeight;
			let tremoloX = this.stemX;
			if (this.beat.duration < Duration.Half) tremoloX = this.width / 2;
			g.x = tremoloX;
		}
		buildBoundingsLookup(beatBounds, cx, cy) {
			for (const note of this._notes) if (this._noteGlyphLookup.has(note.id)) {
				const glyph = this._noteGlyphLookup.get(note.id);
				const noteBounds = new NoteBounds();
				noteBounds.note = note;
				noteBounds.noteHeadBounds = new Bounds();
				noteBounds.noteHeadBounds.x = cx + this.x + glyph.x;
				noteBounds.noteHeadBounds.y = cy + this.y + glyph.y - glyph.height / 2;
				noteBounds.noteHeadBounds.w = glyph.width;
				noteBounds.noteHeadBounds.h = glyph.height;
				beatBounds.addNote(noteBounds);
			}
		}
		paint(cx, cy, canvas) {
			this._paintEffects(cx, cy, canvas);
			super.paint(cx, cy, canvas);
		}
		_paintEffects(cx, cy, canvas) {
			const _ = ElementStyleHelper.beat(canvas, BeatSubElement.StandardNotationEffects, this.beat);
			try {
				for (const g of this.aboveBeatEffects.values()) g.paint(cx + this.x + this.width / 2, cy + this.y, canvas);
				for (const g of this.belowBeatEffects.values()) g.paint(cx + this.x + this.width / 2, cy + this.y, canvas);
				if (this._tremoloPicking) this._tremoloPicking.paint(cx, cy, canvas);
				if (this._deadSlapped) this._deadSlapped.paint(cx, cy, canvas);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreRestGlyph.ts
	/**
	* @internal
	*/
	var ScoreRestGlyph = class ScoreRestGlyph extends MusicFontGlyph {
		constructor(x, y, duration) {
			super(x, y, 1, ScoreRestGlyph.getSymbol(duration));
		}
		static getSymbol(duration) {
			switch (duration) {
				case Duration.QuadrupleWhole: return MusicFontSymbol.RestLonga;
				case Duration.DoubleWhole: return MusicFontSymbol.RestDoubleWhole;
				case Duration.Whole: return MusicFontSymbol.RestWhole;
				case Duration.Half: return MusicFontSymbol.RestHalf;
				case Duration.Quarter: return MusicFontSymbol.RestQuarter;
				case Duration.Eighth: return MusicFontSymbol.Rest8th;
				case Duration.Sixteenth: return MusicFontSymbol.Rest16th;
				case Duration.ThirtySecond: return MusicFontSymbol.Rest32nd;
				case Duration.SixtyFourth: return MusicFontSymbol.Rest64th;
				case Duration.OneHundredTwentyEighth: return MusicFontSymbol.Rest128th;
				case Duration.TwoHundredFiftySixth: return MusicFontSymbol.Rest256th;
				default: return MusicFontSymbol.None;
			}
		}
		paint(cx, cy, canvas) {
			this.internalPaint(cx, cy, canvas, BeatSubElement.StandardNotationRests);
		}
		internalPaint(cx, cy, canvas, element) {
			const _ = ElementStyleHelper.beat(canvas, element, this.beat);
			try {
				super.paint(cx, cy, canvas);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/BendNoteHeadGroupGlyph.ts
	/**
	* @internal
	*/
	var BendNoteHeadGroupGlyph = class extends ScoreNoteChordGlyphBase {
		_beat;
		_showParenthesis = false;
		_noteValueLookup = /* @__PURE__ */ new Map();
		_accidentals = new AccidentalGroupGlyph();
		_preNoteParenthesis = null;
		_postNoteParenthesis = null;
		isEmpty = true;
		_groupId;
		get scale() {
			return EngravingSettings.GraceScale;
		}
		get hasFlag() {
			return false;
		}
		get hasStem() {
			return false;
		}
		get direction() {
			return BeamDirection.Up;
		}
		constructor(groupId, beat, showParenthesis = false) {
			super();
			this._beat = beat;
			this._groupId = groupId;
			this._showParenthesis = showParenthesis;
			if (showParenthesis) {
				this._preNoteParenthesis = new GhostNoteContainerGlyph(true);
				this._postNoteParenthesis = new GhostNoteContainerGlyph(false);
			}
		}
		getScoreChordNoteHeadInfo() {
			const staff = this._beat.voice.bar.staff;
			const key = `score.noteheads.${this._groupId}.${staff.track.index}.${staff.index}.${this._beat.absoluteDisplayStart}`;
			let existing = this.renderer.staff.getSharedLayoutData(key, void 0);
			if (!existing) {
				existing = new ScoreChordNoteHeadInfo(this.direction);
				this.renderer.staff.setSharedLayoutData(key, existing);
			}
			return new ScoreChordNoteHeadInfo(this.direction);
		}
		containsNoteValue(noteValue) {
			return this._noteValueLookup.has(noteValue);
		}
		getNoteValueY(noteValue) {
			if (this._noteValueLookup.has(noteValue)) return this.y + this._noteValueLookup.get(noteValue).y;
			return 0;
		}
		addGlyph(noteValue, quarterBend, _color) {
			const sr = this.renderer;
			const noteHeadGlyph = new NoteHeadGlyph(0, 0, Duration.Quarter, true);
			const accidental = sr.accidentalHelper.applyAccidentalForValue(this._beat, noteValue, quarterBend, true);
			const steps = sr.accidentalHelper.getNoteStepsForValue(noteValue, false);
			noteHeadGlyph.y = sr.getScoreY(steps);
			if (this._showParenthesis) {
				this._preNoteParenthesis.renderer = this.renderer;
				this._postNoteParenthesis.renderer = this.renderer;
				this._preNoteParenthesis.addParenthesisOnSteps(steps, true);
				this._postNoteParenthesis.addParenthesisOnSteps(steps, true);
			}
			if (accidental !== AccidentalType.None) {
				const g = new AccidentalGlyph(0, noteHeadGlyph.y, accidental, EngravingSettings.GraceScale);
				g.renderer = this.renderer;
				this._accidentals.renderer = this.renderer;
				this._accidentals.addGlyph(g);
			}
			this._noteValueLookup.set(noteValue, noteHeadGlyph);
			this.add(noteHeadGlyph, steps);
			this.isEmpty = false;
		}
		doLayout() {
			let x = 0;
			if (this._showParenthesis) {
				this._preNoteParenthesis.x = x;
				this._preNoteParenthesis.renderer = this.renderer;
				this._preNoteParenthesis.doLayout();
				x += this._preNoteParenthesis.width + this.renderer.smuflMetrics.bendNoteHeadElementPadding;
			}
			if (!this._accidentals.isEmpty) {
				x += this._accidentals.width + this.renderer.smuflMetrics.bendNoteHeadElementPadding;
				this._accidentals.x = x;
				this._accidentals.renderer = this.renderer;
				this._accidentals.doLayout();
				x += this._accidentals.width + this.renderer.smuflMetrics.bendNoteHeadElementPadding;
			}
			this.noteStartX = x;
			super.doLayout();
			if (this._showParenthesis) {
				this._postNoteParenthesis.x = this.width + this.renderer.smuflMetrics.bendNoteHeadElementPadding;
				this._postNoteParenthesis.renderer = this.renderer;
				this._postNoteParenthesis.doLayout();
				this.width += this._postNoteParenthesis.width + this.renderer.smuflMetrics.bendNoteHeadElementPadding;
			}
		}
		paint(cx, cy, canvas) {
			if (!this._accidentals.isEmpty) this._accidentals.paint(cx + this.x, cy + this.y, canvas);
			if (this._showParenthesis) {
				this._preNoteParenthesis.paint(cx + this.x, cy + this.y, canvas);
				this._postNoteParenthesis.paint(cx + this.x, cy + this.y, canvas);
			}
			super.paint(cx, cy, canvas);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreHelperNotesBaseGlyph.ts
	/**
	* @internal
	*/
	var ScoreHelperNotesBaseGlyph = class extends GlyphGroup {
		drawBendSlur(canvas, x1, y1, x2, y2, down, slurText) {
			TieGlyph.drawBendSlur(canvas, x1, y1, x2, y2, down, this.renderer.smuflMetrics.tieHeight, slurText);
		}
		doLayout() {
			if (!this.glyphs) return;
			this.width = 0;
			for (const noteHeads of this.glyphs) {
				noteHeads.doLayout();
				this.width += noteHeads.width;
			}
		}
		getTieDirection(beat, noteRenderer) {
			switch (noteRenderer.getBeatDirection(beat)) {
				case BeamDirection.Up: return BeamDirection.Down;
				default: return BeamDirection.Up;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreWhammyBarGlyph.ts
	/**
	* @internal
	*/
	var ScoreWhammyBarGlyph = class extends ScoreHelperNotesBaseGlyph {
		_container;
		_beat;
		_endGlyph = null;
		checkForOverflow = false;
		constructor(container) {
			super(0, 0);
			this._container = container;
			this._beat = container.beat;
		}
		get hasBoundingBox() {
			const endGlyph = this._endGlyph;
			if (!endGlyph) return false;
			return !!endGlyph.minStepsNote && !!endGlyph.maxStepsNote;
		}
		getBoundingBoxTop() {
			if (this._endGlyph?.minStepsNote) return this._endGlyph.minStepsNote.glyph.getBoundingBoxTop();
			return super.getBoundingBoxTop();
		}
		getBoundingBoxBottom() {
			if (this._endGlyph?.maxStepsNote) return this._endGlyph.maxStepsNote.glyph.getBoundingBoxBottom();
			return super.getBoundingBoxBottom();
		}
		doMultiVoiceLayout() {
			this._endGlyph?.doMultiVoiceLayout();
		}
		doLayout() {
			const sr = this.renderer;
			const whammyMode = sr.settings.notation.notationMode;
			switch (this._beat.whammyBarType) {
				case WhammyType.None:
				case WhammyType.Custom:
				case WhammyType.Hold: return;
				case WhammyType.Dive:
				case WhammyType.PrediveDive:
					{
						const endGlyphs = new BendNoteHeadGroupGlyph("postwhammy", this._beat, false);
						this._endGlyph = endGlyphs;
						endGlyphs.renderer = sr;
						const lastWhammyPoint = this._beat.whammyBarPoints[this._beat.whammyBarPoints.length - 1];
						for (const note of this._beat.notes) if (!note.isTieOrigin) endGlyphs.addGlyph(this._getBendNoteValue(note, lastWhammyPoint), lastWhammyPoint.value % 2 !== 0, void 0);
						endGlyphs.doLayout();
						this.addGlyph(endGlyphs);
					}
					break;
				case WhammyType.Dip:
					if (whammyMode === NotationMode.SongBook) return;
					else {
						const middleGlyphs = new BendNoteHeadGroupGlyph("middlewhammy", this._beat, false);
						middleGlyphs.renderer = sr;
						if (sr.settings.notation.notationMode === NotationMode.GuitarPro) {
							const middleBendPoint = this._beat.whammyBarPoints[1];
							for (const note of this._beat.notes) middleGlyphs.addGlyph(this._getBendNoteValue(note, this._beat.whammyBarPoints[1]), middleBendPoint.value % 2 !== 0, void 0);
						}
						middleGlyphs.doLayout();
						this.addGlyph(middleGlyphs);
						const endGlyphs = new BendNoteHeadGroupGlyph("postwhammy", this._beat, false);
						endGlyphs.renderer = sr;
						this._endGlyph = endGlyphs;
						if (sr.settings.notation.notationMode === NotationMode.GuitarPro) {
							const lastBendPoint = this._beat.whammyBarPoints[this._beat.whammyBarPoints.length - 1];
							for (const note of this._beat.notes) endGlyphs.addGlyph(this._getBendNoteValue(note, lastBendPoint), lastBendPoint.value % 2 !== 0, void 0);
						}
						endGlyphs.doLayout();
						this.addGlyph(endGlyphs);
					}
					break;
				case WhammyType.Predive: break;
			}
			super.doLayout();
			this.width = this.width / 2;
		}
		paint(cx, cy, canvas) {
			const beat = this._beat;
			switch (beat.whammyBarType) {
				case WhammyType.None:
				case WhammyType.Custom: return;
			}
			const whammyMode = this.renderer.settings.notation.notationMode;
			const startNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, beat.voice.bar);
			const _beatStyle = ElementStyleHelper.beat(canvas, BeatSubElement.StandardNotationEffects, beat);
			try {
				const startX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(beat, BeatXPosition.MiddleNotes);
				const beatDirection = this.getTieDirection(beat, startNoteRenderer);
				let direction = this._beat.notes.length === 1 ? beatDirection : BeamDirection.Up;
				const textalign = canvas.textAlign;
				const noteHeadHeight = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.NoteheadBlack);
				for (let i = 0; i < beat.notes.length; i++) {
					const note = beat.notes[i];
					const _noteStyle = ElementStyleHelper.note(canvas, NoteSubElement.StandardNotationEffects, note);
					try {
						let startY = cy + startNoteRenderer.y;
						if (i > 0 && i >= (this._beat.notes.length / 2 | 0)) direction = BeamDirection.Down;
						if (direction === BeamDirection.Down) startY += startNoteRenderer.getNoteY(note, NoteYPosition.Bottom);
						else startY += startNoteRenderer.getNoteY(note, NoteYPosition.Top);
						let endX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(beat, BeatXPosition.EndBeat);
						endX -= this.renderer.smuflMetrics.postNoteEffectPadding;
						if (this._endGlyph) {
							const postBeatSize = this._endGlyph.width - this._endGlyph.onTimeX;
							endX -= postBeatSize;
						}
						const slurText = beat.whammyStyle === BendStyle.Gradual && i === 0 ? "grad." : "";
						let endNoteRenderer = null;
						if (note.isTieOrigin) {
							endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, note.tieDestination.beat.voice.bar);
							if (endNoteRenderer && endNoteRenderer.staff === startNoteRenderer.staff) endX = cx + endNoteRenderer.x + endNoteRenderer.getBeatX(note.tieDestination.beat, BeatXPosition.MiddleNotes);
							else endNoteRenderer = null;
						}
						let heightOffset = noteHeadHeight * EngravingSettings.GraceScale * .5;
						if (direction === BeamDirection.Up) heightOffset = -heightOffset;
						const endValue = beat.whammyBarPoints.length > 0 ? this._getBendNoteValue(note, beat.whammyBarPoints[beat.whammyBarPoints.length - 1]) : 0;
						let endY = 0;
						let bendTie = false;
						if (this.glyphs && this.glyphs[0].containsNoteValue(endValue)) {
							endY = this.glyphs[0].getNoteValueY(endValue) + heightOffset;
							bendTie = true;
						} else if (endNoteRenderer && (note.isTieOrigin && note.tieDestination.beat.hasWhammyBar || note.beat.isContinuedWhammy)) {
							endY = cy + endNoteRenderer.y + endNoteRenderer.getNoteY(note.tieDestination, NoteYPosition.Top);
							bendTie = true;
							if (direction === BeamDirection.Down) endY += noteHeadHeight;
						} else if (note.isTieOrigin) {
							if (!endNoteRenderer) endY = startY;
							else endY = cy + endNoteRenderer.y + endNoteRenderer.getNoteY(note.tieDestination, NoteYPosition.Top);
							if (direction === BeamDirection.Down) endY += noteHeadHeight;
						}
						switch (beat.whammyBarType) {
							case WhammyType.Hold:
								if (note.isTieOrigin) TieGlyph.paintTie(canvas, 1, startX, startY, endX, endY, beatDirection === BeamDirection.Down, this.renderer.smuflMetrics.tieHeight, this.renderer.smuflMetrics.slurMidpointThickness);
								break;
							case WhammyType.Dive:
								if (i === 0) {
									const g0 = this.glyphs[0];
									g0.x = endX - g0.onTimeX;
									const previousY = this.glyphs[0].y;
									g0.y = cy + startNoteRenderer.y;
									g0.paint(0, 0, canvas);
									if (g0.containsNoteValue(endValue)) {
										endY -= previousY;
										endY += g0.y;
									}
								}
								if (bendTie) this.drawBendSlur(canvas, startX, startY, endX, endY, direction === BeamDirection.Down, slurText);
								else if (note.isTieOrigin) TieGlyph.paintTie(canvas, 1, startX, startY, endX, endY, beatDirection === BeamDirection.Down, this.renderer.smuflMetrics.tieHeight, this.renderer.smuflMetrics.slurMidpointThickness);
								break;
							case WhammyType.Dip:
								if (whammyMode === NotationMode.SongBook) {
									if (note.isTieOrigin) TieGlyph.paintTie(canvas, 1, startX, startY, endX, endY, beatDirection === BeamDirection.Down, this.renderer.smuflMetrics.tieHeight, this.renderer.smuflMetrics.slurMidpointThickness);
								} else {
									const middleX = (startX + endX) / 2;
									const g0 = this.glyphs[0];
									g0.x = middleX - g0.onTimeX;
									g0.y = cy + startNoteRenderer.y;
									g0.paint(0, 0, canvas);
									const middleValue = this._getBendNoteValue(note, beat.whammyBarPoints[1]);
									const middleY = g0.getNoteValueY(middleValue) + heightOffset;
									this.drawBendSlur(canvas, startX, startY, middleX, middleY, direction === BeamDirection.Down, slurText);
									const g1 = this.glyphs[1];
									g1.x = endX - g1.onTimeX;
									g1.y = cy + startNoteRenderer.y;
									g1.paint(0, 0, canvas);
									endY = g1.getNoteValueY(endValue) + heightOffset;
									this.drawBendSlur(canvas, middleX, middleY, endX, endY, direction === BeamDirection.Down, slurText);
								}
								break;
							case WhammyType.PrediveDive:
							case WhammyType.Predive:
								let preX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(note.beat, BeatXPosition.PreNotes);
								preX += this._container.prebendNoteHeadOffset;
								const preY = cy + startNoteRenderer.y + startNoteRenderer.getScoreY(startNoteRenderer.accidentalHelper.getNoteStepsForValue(note.displayValue - (note.beat.whammyBarPoints[0].value / 2 | 0), false)) + heightOffset;
								this.drawBendSlur(canvas, preX, preY, startX, startY, direction === BeamDirection.Down, slurText);
								if (this.glyphs) {
									const g0 = this.glyphs[0];
									g0.x = endX - g0.onTimeX;
									g0.y = cy + startNoteRenderer.y;
									g0.paint(0, 0, canvas);
									this.drawBendSlur(canvas, startX, startY, endX, endY, direction === BeamDirection.Down, slurText);
								}
								break;
						}
					} finally {
						_noteStyle?.[Symbol.dispose]?.();
					}
				}
				canvas.textAlign = textalign;
			} finally {
				_beatStyle?.[Symbol.dispose]?.();
			}
		}
		_getBendNoteValue(note, bendPoint) {
			return note.displayValueWithoutBend + (bendPoint.value / 2 | 0);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/SlashNoteHeadGlyph.ts
	/**
	* @internal
	*/
	var SlashNoteHeadGlyph = class SlashNoteHeadGlyph extends NoteHeadGlyphBase {
		beatEffects = /* @__PURE__ */ new Map();
		noteHeadElement = NoteSubElement.SlashNoteHead;
		effectElement = BeatSubElement.SlashEffects;
		stemX = 0;
		constructor(x, y, beat) {
			super(x, y, beat.graceType !== GraceType.None, SlashNoteHeadGlyph.getSymbol(beat.duration));
			this.beat = beat;
		}
		paint(cx, cy, canvas) {
			try {
				var _usingCtx$1 = _usingCtx();
				_usingCtx$1.u(this.beat.notes.length === 0 ? void 0 : ElementStyleHelper.note(canvas, this.noteHeadElement, this.beat.notes[0]));
				super.paint(cx, cy, canvas);
				this._paintEffects(cx, cy, canvas);
			} catch (_) {
				_usingCtx$1.e = _;
			} finally {
				_usingCtx$1.d();
			}
		}
		_paintEffects(cx, cy, canvas) {
			const _ = ElementStyleHelper.beat(canvas, this.effectElement, this.beat);
			try {
				for (const g of this.beatEffects.values()) g.paint(cx + this.x, cy + this.y, canvas);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		doLayout() {
			super.doLayout();
			const lr = this.renderer;
			const effectSpacing = lr.smuflMetrics.onNoteEffectPadding;
			let effectY = lr.smuflMetrics.glyphHeights.get(this.symbol);
			let minEffectY = NaN;
			let maxEffectY = NaN;
			for (const g of this.beatEffects.values()) {
				g.y += effectY;
				g.x += this.width / 2;
				g.renderer = lr;
				effectY += g.height + effectSpacing;
				g.doLayout();
				if (Number.isNaN(minEffectY) || minEffectY > effectY) minEffectY = effectY;
				if (Number.isNaN(maxEffectY) || maxEffectY < effectY) maxEffectY = effectY;
			}
			if (!Number.isNaN(minEffectY)) lr.registerBeatEffectOverflows(minEffectY, maxEffectY);
			const direction = lr.getBeatDirection(this.beat);
			const symbol = this.symbol;
			if (direction === BeamDirection.Up) {
				const stemInfoUp = lr.smuflMetrics.stemUp.has(symbol) ? lr.smuflMetrics.stemUp.get(symbol).x : 0;
				this.stemX = stemInfoUp;
			} else {
				const stemInfoDown = lr.smuflMetrics.stemDown.has(symbol) ? lr.smuflMetrics.stemDown.get(symbol).x : 0;
				this.stemX = stemInfoDown;
			}
		}
		static getSymbol(duration) {
			switch (duration) {
				case Duration.QuadrupleWhole:
				case Duration.DoubleWhole:
				case Duration.Whole: return MusicFontSymbol.NoteheadSlashWhiteWhole;
				case Duration.Half: return MusicFontSymbol.NoteheadSlashWhiteHalf;
				default: return MusicFontSymbol.NoteheadSlashHorizontalEnds;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/StringNumberContainerGlyph.ts
	/**
	* @internal
	*/
	var StringNumberContainerGlyph = class extends EffectGlyph {
		_strings = /* @__PURE__ */ new Set();
		addString(string) {
			this._strings.add(string);
		}
		doLayout() {
			const circleHeight = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.GuitarString0) * this.renderer.smuflMetrics.tuningGlyphCircleNumberScale;
			this.height = (circleHeight + this.renderer.smuflMetrics.stringNumberCirclePadding) * this._strings.size;
			this.width = circleHeight;
		}
		paint(cx, cy, canvas) {
			const tuningLength = this.renderer.bar.staff.tuning.length;
			let y = 0;
			const circleHeight = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.GuitarString0) * this.renderer.smuflMetrics.tuningGlyphCircleNumberScale;
			for (const s of this._strings) {
				const stringValue = tuningLength - s;
				const symbol = MusicFontSymbol.GuitarString1 + stringValue;
				CanvasHelper.fillMusicFontSymbolSafe(canvas, cx + this.x, cy + this.y + circleHeight + y, this.renderer.smuflMetrics.tuningGlyphCircleNumberScale, symbol, true);
				y += circleHeight + this.renderer.smuflMetrics.stringNumberCirclePadding;
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreBeatGlyph.ts
	/**
	* @internal
	*/
	var ScoreBeatGlyph = class extends BeatOnNoteGlyphBase {
		_collisionOffset = NaN;
		_skipPaint = false;
		_whammy;
		noteHeads = null;
		restGlyph = null;
		get effectElement() {
			return BeatSubElement.StandardNotationEffects;
		}
		buildBoundingsLookup(beatBounds, cx, cy) {
			if (this.noteHeads) this.noteHeads.buildBoundingsLookup(beatBounds, cx + this.x, cy + this.y);
		}
		getBoundingBoxTop() {
			let y = this.y;
			if (this.noteHeads) y = this.noteHeads.getBoundingBoxTop();
			else if (this.restGlyph) y = this.restGlyph.getBoundingBoxTop();
			if (this._whammy?.hasBoundingBox) y = Math.min(y, this._whammy.getBoundingBoxTop());
			return y;
		}
		getBoundingBoxBottom() {
			let y = this.y + this.height;
			if (this.noteHeads) y = this.noteHeads.getBoundingBoxBottom();
			else if (this.restGlyph) y = this.restGlyph.getBoundingBoxBottom();
			if (this._whammy?.hasBoundingBox) y = Math.max(y, this._whammy.getBoundingBoxBottom());
			return y;
		}
		getLowestNoteY(requestedPosition) {
			return this.noteHeads ? this.noteHeads.getLowestNoteY(requestedPosition) : 0;
		}
		getHighestNoteY(requestedPosition) {
			return this.noteHeads ? this.noteHeads.getHighestNoteY(requestedPosition) : 0;
		}
		getNoteY(note, requestedPosition) {
			if (note.beat.slashed) note = note.beat.notes[0];
			return this.noteHeads ? this.noteHeads.getNoteY(note, requestedPosition) : 0;
		}
		getNoteX(note, requestedPosition) {
			if (note.beat.slashed) note = note.beat.notes[0];
			return this.noteHeads ? this.noteHeads.getNoteX(note, requestedPosition) : 0;
		}
		getRestY(requestedPosition) {
			const g = this.restGlyph;
			if (g) switch (requestedPosition) {
				case NoteYPosition.TopWithStem: return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
				case NoteYPosition.Top: return g.getBoundingBoxTop();
				case NoteYPosition.Center:
				case NoteYPosition.StemUp:
				case NoteYPosition.StemDown: return g.getBoundingBoxTop() + g.height / 2;
				case NoteYPosition.Bottom: return g.getBoundingBoxBottom();
				case NoteYPosition.BottomWithStem: return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
			}
			return 0;
		}
		applyRestCollisionOffset() {
			if (!this.restGlyph) return;
			if (Number.isNaN(this._collisionOffset)) {
				this._collisionOffset = this.renderer.collisionHelper.applyRestCollisionOffset(this.container.beat, this.restGlyph.y, this.renderer.getScoreHeight(1));
				this.y += this._collisionOffset;
				const existingRests = this.renderer.collisionHelper.restDurationsByDisplayTime;
				if (existingRests.has(this.container.beat.playbackStart) && existingRests.get(this.container.beat.playbackStart).has(this.container.beat.playbackDuration) && existingRests.get(this.container.beat.playbackStart).get(this.container.beat.playbackDuration) !== this.container.beat.id) this._skipPaint = true;
			}
		}
		paint(cx, cy, canvas) {
			if (!this._skipPaint) super.paint(cx, cy, canvas);
		}
		doMultiVoiceLayout() {
			this.applyRestCollisionOffset();
			this.noteHeads?.doMultiVoiceLayout();
			this._whammy?.doMultiVoiceLayout();
			let w = 0;
			if (this.glyphs) for (const g of this.glyphs) {
				g.x = w;
				w += g.width;
			}
			this.width = w;
			this.computedWidth = w;
			this._updatePositions();
		}
		doLayout() {
			this._createGlyphs();
			super.doLayout();
			this._updatePositions();
		}
		_updatePositions() {
			if (this.container.beat.isEmpty) {
				this.onTimeX = this.width / 2;
				this.middleX = this.onTimeX;
				this.stemX = this.middleX;
			} else if (this.restGlyph) {
				this.onTimeX = this.restGlyph.x + this.restGlyph.width / 2;
				this.middleX = this.onTimeX;
				this.stemX = this.middleX;
			} else if (this.noteHeads) {
				this.onTimeX = this.noteHeads.x + this.noteHeads.onTimeX;
				this.middleX = this.noteHeads.x + this.noteHeads.width / 2;
				this.stemX = this.noteHeads.x + this.noteHeads.stemX;
			}
		}
		_createGlyphs() {
			if (this.container.beat.isEmpty) return;
			if (!this.container.beat.isRest) this._createNoteGlyphs();
			else this._createRestGlyphs();
		}
		_createNoteGlyphs() {
			const sr = this.renderer;
			const noteHeads = new ScoreNoteChordGlyph();
			this.noteHeads = noteHeads;
			noteHeads.beat = this.container.beat;
			const ghost = new GhostNoteContainerGlyph(false);
			ghost.renderer = this.renderer;
			if (this.container.beat.slashed) {
				const steps = sr.heightLineCount - 1;
				const slash = new SlashNoteHeadGlyph(0, sr.getScoreY(steps), this.container.beat);
				slash.colorOverride = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationNoteHead, this.container.beat.notes[0]);
				this.noteHeads.addMainNoteGlyph(slash, this.container.beat.notes[0], steps);
			} else for (const note of this.container.beat.notes) if (note.isVisible) {
				this._createNoteGlyph(note);
				ghost.addParenthesis(note);
			}
			this.addNormal(noteHeads);
			if (!ghost.isEmpty) this.addEffect(ghost);
			if (this.container.beat.hasWhammyBar) {
				const whammy = new ScoreWhammyBarGlyph(this.container);
				this._whammy = whammy;
				whammy.renderer = this.renderer;
				whammy.doLayout();
				this.container.addTie(whammy);
			}
			if (this.container.beat.dots > 0) for (let i = 0; i < this.container.beat.dots; i++) {
				const group = new GlyphGroup(0, 0);
				group.renderer = this.renderer;
				for (const note of this.container.beat.notes) if (note.isVisible) {
					const g = this._createBeatDot(sr.getNoteSteps(note), group);
					g.colorOverride = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationEffects, note);
				}
				this.addEffect(group);
			}
			if (this.renderer.bar.isMultiVoice) {
				let highestNotePosition = 0;
				let lowestNotePosition = 0;
				const direction = sr.getBeatDirection(this.container.beat);
				let offset = 0;
				if (this.container.beat.hasTuplet) offset += sr.tupletOffset + sr.tupletSize;
				if (direction === BeamDirection.Up) {
					highestNotePosition = this.getHighestNoteY(NoteYPosition.TopWithStem) - offset;
					lowestNotePosition = this.getLowestNoteY(NoteYPosition.Bottom);
				} else {
					highestNotePosition = this.getHighestNoteY(NoteYPosition.Top);
					lowestNotePosition = this.getLowestNoteY(NoteYPosition.BottomWithStem) + offset;
				}
				this.renderer.collisionHelper.reserveBeatSlot(this.container.beat, highestNotePosition, lowestNotePosition);
			}
		}
		_createRestGlyphs() {
			const sr = this.renderer;
			let steps = Math.ceil((this.renderer.bar.staff.standardNotationLineCount - 1) / 2) * 2;
			if (this.container.beat.duration === Duration.Whole && this.renderer.bar.staff.standardNotationLineCount !== 1 && this.renderer.bar.staff.standardNotationLineCount !== 3) steps -= 2;
			const restGlyph = new ScoreRestGlyph(0, sr.getScoreY(steps), this.container.beat.duration);
			this.restGlyph = restGlyph;
			restGlyph.beat = this.container.beat;
			this.addNormal(restGlyph);
			if (this.renderer.bar.isMultiVoice) if (this.container.beat.voice.index === 0) {
				const restSizes = BeamingHelper.computeLineHeightsForRest(this.container.beat.duration);
				const restTop = restGlyph.y - sr.getScoreHeight(restSizes[0]);
				const restBottom = restGlyph.y + sr.getScoreHeight(restSizes[1]);
				this.renderer.collisionHelper.reserveBeatSlot(this.container.beat, restTop, restBottom);
			} else this.renderer.collisionHelper.registerRest(this.container.beat);
			if (this.container.beat.dots > 0) for (let i = 0; i < this.container.beat.dots; i++) {
				const group = new GlyphGroup(0, 0);
				group.renderer = this.renderer;
				this._createBeatDot(steps, group);
				this.addEffect(group);
			}
		}
		_createBeatDot(line, group) {
			const sr = this.renderer;
			const g = new AugmentationDotGlyph(0, sr.getScoreY(line));
			group.addGlyph(g);
			return g;
		}
		_createNoteHeadGlyph(n) {
			const isGrace = this.container.beat.graceType !== GraceType.None;
			const style = n.style;
			if (style?.noteHead !== void 0) {
				const noteHead = new NoteHeadGlyph(0, 0, n.beat.duration, isGrace);
				noteHead.symbol = style.noteHead;
				if (style.noteHeadCenterOnStem) noteHead.centerOnStem = true;
				return noteHead;
			}
			if (n.beat.voice.bar.staff.isPercussion) {
				const articulation = PercussionMapper.getArticulation(n);
				if (articulation) return new PercussionNoteHeadGlyph(0, 0, articulation, n.beat.duration, isGrace);
				Logger.warning("Rendering", `No articulation found for percussion instrument ${n.percussionArticulation}`);
			}
			if (n.isDead) return new DeadNoteHeadGlyph(0, 0, isGrace);
			if (n.beat.graceType === GraceType.BendGrace) return new NoteHeadGlyph(0, 0, Duration.Quarter, true);
			if (n.harmonicType === HarmonicType.Natural) return new DiamondNoteHeadGlyph(0, 0, n.beat.duration, isGrace);
			return new NoteHeadGlyph(0, 0, n.beat.duration, isGrace);
		}
		_createNoteGlyph(n) {
			if (n.beat.graceType === GraceType.BendGrace && !n.hasBend) return;
			const sr = this.renderer;
			const noteHeadGlyph = this._createNoteHeadGlyph(n);
			noteHeadGlyph.colorOverride = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationNoteHead, n);
			let steps = sr.getNoteSteps(n);
			noteHeadGlyph.y = sr.getScoreY(steps);
			this.noteHeads.addMainNoteGlyph(noteHeadGlyph, n, steps);
			if (!n.beat.slashed && n.harmonicType !== HarmonicType.None && n.harmonicType !== HarmonicType.Natural) {
				const harmonicFret = n.displayValue + n.harmonicPitch;
				const harmonicsGlyph = new DiamondNoteHeadGlyph(0, 0, n.beat.duration, this.container.beat.graceType !== GraceType.None);
				harmonicsGlyph.colorOverride = noteHeadGlyph.colorOverride;
				steps = sr.accidentalHelper.getNoteStepsForValue(harmonicFret, false);
				harmonicsGlyph.y = sr.getScoreY(steps);
				this.noteHeads.addEffectNoteGlyph(harmonicsGlyph, steps);
			}
			const belowBeatEffects = this.noteHeads.belowBeatEffects;
			const aboveBeatEffects = this.noteHeads.aboveBeatEffects;
			const outsideBeatEffects = sr.getBeatDirection(this.container.beat) === BeamDirection.Up ? this.noteHeads.belowBeatEffects : this.noteHeads.aboveBeatEffects;
			if (n.isStaccato && !belowBeatEffects.has("Staccato")) outsideBeatEffects.set("Staccato", new ArticStaccatoAboveGlyph(0, 0));
			if (n.accentuated === AccentuationType.Normal && !belowBeatEffects.has("Accent")) outsideBeatEffects.set("Accent", new AccentuationGlyph(0, 0, n));
			if (n.accentuated === AccentuationType.Heavy && !belowBeatEffects.has("HAccent")) outsideBeatEffects.set("HAccent", new AccentuationGlyph(0, 0, n));
			if (n.accentuated === AccentuationType.Tenuto && !belowBeatEffects.has("Tenuto")) outsideBeatEffects.set("Tenuto", new AccentuationGlyph(0, 0, n));
			if (n.showStringNumber && n.isStringed) {
				let container;
				if (!aboveBeatEffects.has("StringNumber")) {
					container = new StringNumberContainerGlyph(0, 0);
					aboveBeatEffects.set("StringNumber", container);
				} else container = aboveBeatEffects.get("StringNumber");
				container.addString(n.string);
			}
			if (n.isPercussion) {
				const articulation = PercussionMapper.getArticulation(n);
				if (articulation && articulation.techniqueSymbolPlacement !== TechniqueSymbolPlacement.Inside) {
					let effectContainer;
					switch (articulation.techniqueSymbolPlacement) {
						case TechniqueSymbolPlacement.Above:
							effectContainer = this.noteHeads.aboveBeatEffects;
							break;
						case TechniqueSymbolPlacement.Below:
							effectContainer = this.noteHeads.belowBeatEffects;
							break;
						case TechniqueSymbolPlacement.Outside:
							effectContainer = outsideBeatEffects;
							break;
						default: return;
					}
					switch (articulation.techniqueSymbol) {
						case MusicFontSymbol.PictEdgeOfCymbal:
							effectContainer.set("PictEdgeOfCymbal", new PictEdgeOfCymbalGlyph(0, 0));
							break;
						case MusicFontSymbol.ArticStaccatoAbove:
							effectContainer.set("ArticStaccatoAbove", new ArticStaccatoAboveGlyph(0, 0));
							break;
						case MusicFontSymbol.StringsUpBow:
							effectContainer.set("StringsUpBow", new PickStrokeGlyph(0, 0, PickStroke.Up));
							break;
						case MusicFontSymbol.StringsDownBow:
							effectContainer.set("StringsDownBow", new PickStrokeGlyph(0, 0, PickStroke.Down));
							break;
						case MusicFontSymbol.GuitarGolpe:
							effectContainer.set("GuitarGolpe", new GuitarGolpeGlyph(0, 0, true));
							break;
					}
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreBrushGlyph.ts
	/**
	* @internal
	*/
	var ScoreBrushGlyph = class extends Glyph {
		_beat;
		_noteVibratoGlyph;
		constructor(beat) {
			super(0, 0);
			this._beat = beat;
		}
		doLayout() {
			if (this._beat.brushType === BrushType.ArpeggioUp || this._beat.brushType === BrushType.ArpeggioDown) {
				const glyph = new NoteVibratoGlyph(0, 0, VibratoType.Slight, true);
				glyph.renderer = this.renderer;
				glyph.doLayout();
				this._noteVibratoGlyph = glyph;
				this.width = glyph.height;
			} else this.width = 0;
		}
		paint(cx, cy, canvas) {
			if (this._beat.brushType === BrushType.ArpeggioUp || this._beat.brushType === BrushType.ArpeggioDown) {
				const scoreBarRenderer = this.renderer;
				const lineSize = scoreBarRenderer.lineOffset;
				const startY = cy + this.y + (scoreBarRenderer.getNoteY(this._beat.maxNote, NoteYPosition.Bottom) - lineSize);
				const endY = cy + this.y + scoreBarRenderer.getNoteY(this._beat.minNote, NoteYPosition.Top) + lineSize;
				const arrowX = cx + this.x + this.width / 2;
				const arrowSize = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.ArrowheadBlackDown);
				const glyph = this._noteVibratoGlyph;
				if (this._beat.brushType === BrushType.ArpeggioUp) {
					const lineStartY = startY + arrowSize;
					const lineEndY = endY - arrowSize;
					glyph.width = Math.abs(lineEndY - lineStartY);
					canvas.beginRotate(cx + this.x, lineEndY, -90);
					glyph.paint(0, 0, canvas);
					canvas.endRotate();
					canvas.beginPath();
					canvas.moveTo(arrowX, endY);
					canvas.lineTo(arrowX + arrowSize / 2, endY - arrowSize);
					canvas.lineTo(arrowX - arrowSize / 2, endY - arrowSize);
					canvas.closePath();
					canvas.fill();
				} else if (this._beat.brushType === BrushType.ArpeggioDown) {
					const lineStartY = startY + arrowSize;
					glyph.width = Math.abs(endY - lineStartY);
					canvas.beginRotate(cx + this.x, lineStartY, 90);
					glyph.paint(0, -glyph.height, canvas);
					canvas.endRotate();
					canvas.beginPath();
					canvas.moveTo(arrowX, startY);
					canvas.lineTo(arrowX + arrowSize / 2, startY + arrowSize);
					canvas.lineTo(arrowX - arrowSize / 2, startY + arrowSize);
					canvas.closePath();
					canvas.fill();
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreBeatPreNotesGlyph.ts
	/**
	* @internal
	*/
	var ScoreBeatPreNotesGlyph = class extends BeatGlyphBase {
		_prebends = null;
		get prebendNoteHeadOffset() {
			return this._prebends ? this._prebends.x + this._prebends.onTimeX : 0;
		}
		get effectElement() {
			return BeatSubElement.StandardNotationEffects;
		}
		accidentals = null;
		doMultiVoiceLayout() {
			this._prebends?.doMultiVoiceLayout();
		}
		doLayout() {
			if (!this.container.beat.isRest) this._createGlyphs();
			super.doLayout();
		}
		_createGlyphs() {
			const accidentals = new AccidentalGroupGlyph();
			accidentals.renderer = this.renderer;
			const fingering = new FingeringGroupGlyph();
			fingering.renderer = this.renderer;
			const ghost = new GhostNoteContainerGlyph(true);
			ghost.renderer = this.renderer;
			let preBends = null;
			let hasSimpleSlideIn = false;
			for (const note of this.container.beat.notes) {
				const color = ElementStyleHelper.noteColor(this.renderer.resources, NoteSubElement.StandardNotationEffects, note);
				if (note.isVisible) {
					if (note.hasBend) switch (note.bendType) {
						case BendType.PrebendBend:
						case BendType.Prebend:
						case BendType.PrebendRelease:
							if (!preBends) {
								preBends = new BendNoteHeadGroupGlyph("prebend", this.container.beat, true);
								preBends.renderer = this.renderer;
							}
							preBends.addGlyph(note.displayValue - (note.bendPoints[0].value / 2 | 0), false, color);
							break;
					}
					else if (note.beat.hasWhammyBar) switch (note.beat.whammyBarType) {
						case WhammyType.PrediveDive:
						case WhammyType.Predive:
							if (!preBends) {
								preBends = new BendNoteHeadGroupGlyph("prebend", this.container.beat, true);
								preBends.renderer = this.renderer;
							}
							preBends.addGlyph(note.displayValue - (note.beat.whammyBarPoints[0].value / 2 | 0), false, color);
							break;
					}
					this._createAccidentalGlyph(note, accidentals);
					ghost.addParenthesis(note);
					fingering.addFingers(note);
					switch (note.slideInType) {
						case SlideInType.IntoFromBelow:
						case SlideInType.IntoFromAbove:
							hasSimpleSlideIn = true;
							break;
					}
				}
			}
			if (hasSimpleSlideIn) this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.simpleSlideWidth * (this.container.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1)));
			this._prebends = preBends;
			if (preBends) {
				this.addEffect(preBends);
				this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding * (this.container.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1)));
			}
			if (this.container.beat.brushType !== BrushType.None) {
				this.addEffect(new ScoreBrushGlyph(this.container.beat));
				this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding * (this.container.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1)));
			}
			if (!fingering.isEmpty) {
				if (!this.isEmpty) this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding * (this.container.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1)));
				this.addEffect(fingering);
				this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding * (this.container.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1)));
			}
			if (!ghost.isEmpty) this.addEffect(ghost);
			if (!accidentals.isEmpty) {
				this.accidentals = accidentals;
				if (!this.isEmpty) this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding * (this.container.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1)));
				this.addNormal(accidentals);
				this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding * (this.container.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1)));
			}
		}
		_createAccidentalGlyph(n, accidentals) {
			const sr = this.renderer;
			let accidental = sr.accidentalHelper.applyAccidental(n);
			let noteSteps = sr.getNoteSteps(n);
			const isGrace = this.container.beat.graceType !== GraceType.None;
			const color = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationAccidentals, n);
			const graceScale = isGrace ? EngravingSettings.GraceScale : 1;
			if (accidental !== AccidentalType.None) {
				const g = new AccidentalGlyph(0, sr.getScoreY(noteSteps), accidental, graceScale);
				g.colorOverride = color;
				g.renderer = this.renderer;
				accidentals.addGlyph(g);
			}
			if (n.harmonicType !== HarmonicType.None && n.harmonicType !== HarmonicType.Natural) {
				const harmonicFret = n.displayValue + n.harmonicPitch;
				accidental = sr.accidentalHelper.applyAccidentalForValue(n.beat, harmonicFret, isGrace, false);
				noteSteps = sr.accidentalHelper.getNoteStepsForValue(harmonicFret, false);
				const g = new AccidentalGlyph(0, sr.getScoreY(noteSteps), accidental, graceScale);
				g.colorOverride = color;
				g.renderer = this.renderer;
				accidentals.addGlyph(g);
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreBendGlyph.ts
	/**
	* @internal
	*/
	var ScoreBendGlyph = class extends ScoreHelperNotesBaseGlyph {
		_beat;
		_notes = [];
		_endNoteGlyph = null;
		_middleNoteGlyph = null;
		_container;
		checkForOverflow = false;
		constructor(container) {
			super(0, 0);
			this._beat = container.beat;
			this._container = container;
		}
		doLayout() {
			super.doLayout();
			this.width = 0;
		}
		getBoundingBoxTop() {
			return super.getBoundingBoxTop() - this._calculateMaxSlurHeight(BeamDirection.Up);
		}
		getBoundingBoxBottom() {
			return super.getBoundingBoxBottom() + this._calculateMaxSlurHeight(BeamDirection.Down);
		}
		doMultiVoiceLayout() {
			this._middleNoteGlyph?.doMultiVoiceLayout();
			this._endNoteGlyph?.doMultiVoiceLayout();
		}
		_calculateMaxSlurHeight(expectedDirection) {
			const direction = this.getTieDirection(this._beat, this.renderer);
			if (direction !== expectedDirection) return 0;
			let maxSlurHeight = 0;
			for (const note of this._notes) {
				if (note.isTieOrigin) continue;
				switch (note.bendType) {
					case BendType.Custom:
					case BendType.Prebend:
					case BendType.Hold: continue;
				}
				const width = this.renderer.getBeatContainer(this._beat).width * 2;
				let endY = 0;
				let endX = 0;
				switch (note.bendType) {
					case BendType.Bend:
					case BendType.PrebendBend:
						endY = this._endNoteGlyph.minStepsNote.glyph.getBoundingBoxTop();
						endX = width;
						break;
					case BendType.BendRelease:
						endY = this._middleNoteGlyph.minStepsNote.glyph.getBoundingBoxTop();
						endX = width / 2;
						break;
					case BendType.Release:
					case BendType.PrebendRelease:
						endY = this._endNoteGlyph.maxStepsNote.glyph.getBoundingBoxTop();
						endX = width;
						break;
				}
				const startY = this.renderer.getNoteY(note, NoteYPosition.Top);
				let slurHeight = Math.abs(TieGlyph.calculateBendSlurTopY(0, startY, endX, endY, direction === BeamDirection.Down, 1, this.renderer.smuflMetrics.tieHeight) - endY);
				if (note.bendStyle === BendStyle.Gradual) {
					const res = this.renderer.resources;
					const c = this.renderer.scoreRenderer.canvas;
					c.font = res.elementFonts.get(NotationElement.ScoreBendSlur);
					slurHeight += c.measureText("grad.").height;
				}
				if (slurHeight > maxSlurHeight) maxSlurHeight = slurHeight;
			}
			return maxSlurHeight;
		}
		addBends(note) {
			this._notes.push(note);
			if (note.isTieOrigin) return;
			const color = ElementStyleHelper.noteColor(this.renderer.resources, NoteSubElement.StandardNotationEffects, note);
			switch (note.bendType) {
				case BendType.Bend:
				case BendType.PrebendRelease:
				case BendType.PrebendBend:
					{
						let endGlyphs = this._endNoteGlyph;
						if (!endGlyphs) {
							endGlyphs = new BendNoteHeadGroupGlyph("postbend", note.beat, false);
							endGlyphs.renderer = this.renderer;
							this._endNoteGlyph = endGlyphs;
							this.addGlyph(endGlyphs);
						}
						const lastBendPoint = note.bendPoints[note.bendPoints.length - 1];
						endGlyphs.addGlyph(this._getBendNoteValue(note, lastBendPoint), lastBendPoint.value % 2 !== 0, color);
					}
					break;
				case BendType.Release:
					if (!note.isTieOrigin) {
						let endGlyphs = this._endNoteGlyph;
						if (!endGlyphs) {
							endGlyphs = new BendNoteHeadGroupGlyph("postbend", note.beat, false);
							endGlyphs.renderer = this.renderer;
							this._endNoteGlyph = endGlyphs;
							this.addGlyph(endGlyphs);
						}
						const lastBendPoint = note.bendPoints[note.bendPoints.length - 1];
						endGlyphs.addGlyph(this._getBendNoteValue(note, lastBendPoint), lastBendPoint.value % 2 !== 0, color);
					}
					break;
				case BendType.BendRelease:
					{
						let middleGlyphs = this._middleNoteGlyph;
						if (!middleGlyphs) {
							middleGlyphs = new BendNoteHeadGroupGlyph("middlebend", note.beat, false);
							this._middleNoteGlyph = middleGlyphs;
							middleGlyphs.renderer = this.renderer;
							this.addGlyph(middleGlyphs);
						}
						const middleBendPoint = note.bendPoints[1];
						middleGlyphs.addGlyph(this._getBendNoteValue(note, note.bendPoints[1]), middleBendPoint.value % 2 !== 0, color);
						let endGlyphs = this._endNoteGlyph;
						if (!endGlyphs) {
							endGlyphs = new BendNoteHeadGroupGlyph("postbend", note.beat, false);
							endGlyphs.renderer = this.renderer;
							this._endNoteGlyph = endGlyphs;
							this.addGlyph(endGlyphs);
						}
						const lastBendPoint = note.bendPoints[note.bendPoints.length - 1];
						endGlyphs.addGlyph(this._getBendNoteValue(note, lastBendPoint), lastBendPoint.value % 2 !== 0, color);
					}
					break;
			}
		}
		paint(cx, cy, canvas) {
			const startNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this._beat.voice.bar);
			const startX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(this._beat, BeatXPosition.MiddleNotes);
			let endBeatX = cx + startNoteRenderer.x;
			if (this._beat.isLastOfVoice) endBeatX += startNoteRenderer.getBeatX(this._beat, BeatXPosition.EndBeat);
			else endBeatX += startNoteRenderer.getBeatX(this._beat.nextBeat, BeatXPosition.PreNotes);
			endBeatX -= this.renderer.smuflMetrics.postNoteEffectPadding;
			if (this._endNoteGlyph) {
				const postBeatSize = this._endNoteGlyph.width - this._endNoteGlyph.onTimeX;
				endBeatX -= postBeatSize;
			}
			const middleX = (startX + endBeatX) / 2;
			if (this._middleNoteGlyph) {
				this._middleNoteGlyph.x = middleX - this._middleNoteGlyph.onTimeX;
				this._middleNoteGlyph.y = cy + startNoteRenderer.y;
				this._middleNoteGlyph.paint(0, 0, canvas);
			}
			if (this._endNoteGlyph) {
				this._endNoteGlyph.x = endBeatX - this._endNoteGlyph.onTimeX;
				this._endNoteGlyph.y = cy + startNoteRenderer.y;
				this._endNoteGlyph.paint(0, 0, canvas);
			}
			this._notes.sort((a, b) => {
				return b.displayValue - a.displayValue;
			});
			if (this.renderer.settings.notation.isNotationElementVisible(NotationElement.ScoreBendSlur)) this._paintSlurs(cx, cy, canvas, startNoteRenderer, startX, middleX, endBeatX);
		}
		_paintSlurs(cx, cy, canvas, startNoteRenderer, startX, middleX, endBeatX) {
			const directionBeat = this._beat.graceType === GraceType.BendGrace ? this._beat.nextBeat : this._beat;
			let direction = this._notes.length === 1 ? this.getTieDirection(directionBeat, startNoteRenderer) : BeamDirection.Up;
			const noteHeadHeight = this.renderer.smuflMetrics.glyphHeights.get(MusicFontSymbol.NoteheadBlack);
			canvas.font = this.renderer.resources.elementFonts.get(NotationElement.ScoreBendSlur);
			for (let i = 0; i < this._notes.length; i++) {
				const note = this._notes[i];
				const _ = ElementStyleHelper.note(canvas, NoteSubElement.StandardNotationEffects, note);
				try {
					if (i > 0 && i >= (this._notes.length / 2 | 0)) direction = BeamDirection.Down;
					let startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(note, NoteYPosition.Top);
					let heightOffset = noteHeadHeight * EngravingSettings.GraceScale * .5;
					if (direction === BeamDirection.Down) startY += noteHeadHeight;
					const slurText = note.bendStyle === BendStyle.Gradual ? "grad." : "";
					if (note.isTieOrigin) {
						const endNote = note.tieDestination;
						const endNoteRenderer = !endNote ? null : this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, endNote.beat.voice.bar);
						if (!endNoteRenderer || endNoteRenderer.staff !== startNoteRenderer.staff) {
							const endX = cx + startNoteRenderer.x + startNoteRenderer.width;
							const noteValueToDraw = note.tieDestination.displayValue;
							startNoteRenderer.accidentalHelper.applyAccidentalForValue(note.beat, noteValueToDraw, false, true);
							const endY = cy + startNoteRenderer.y + startNoteRenderer.getScoreY(startNoteRenderer.accidentalHelper.getNoteStepsForValue(noteValueToDraw, false));
							if (note.bendType === BendType.Hold || note.bendType === BendType.Prebend) TieGlyph.paintTie(canvas, 1, startX, startY, endX, endY, direction === BeamDirection.Down, this.renderer.smuflMetrics.tieHeight, this.renderer.smuflMetrics.slurMidpointThickness);
							else this.drawBendSlur(canvas, startX, startY, endX, endY, direction === BeamDirection.Down, slurText);
						} else {
							const endX = cx + endNoteRenderer.x + endNoteRenderer.getBeatX(endNote.beat, BeatXPosition.MiddleNotes);
							let endY = cy + endNoteRenderer.y + endNoteRenderer.getNoteY(endNote, NoteYPosition.Top);
							if (direction === BeamDirection.Down) endY += noteHeadHeight;
							if (note.bendType === BendType.Hold || note.bendType === BendType.Prebend) TieGlyph.paintTie(canvas, 1, startX, startY, endX, endY, direction === BeamDirection.Down, this.renderer.smuflMetrics.tieHeight, this.renderer.smuflMetrics.slurMidpointThickness);
							else this.drawBendSlur(canvas, startX, startY, endX, endY, direction === BeamDirection.Down, slurText);
						}
						switch (note.bendType) {
							case BendType.Prebend:
							case BendType.PrebendBend:
							case BendType.PrebendRelease:
								let preX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(note.beat, BeatXPosition.PreNotes);
								preX += this._container.prebendNoteHeadOffset;
								const preY = cy + startNoteRenderer.y + startNoteRenderer.getScoreY(startNoteRenderer.accidentalHelper.getNoteStepsForValue(note.displayValue - (note.bendPoints[0].value / 2 | 0), false)) + heightOffset;
								this.drawBendSlur(canvas, preX, preY, startX, startY, direction === BeamDirection.Down);
								break;
						}
					} else {
						if (direction === BeamDirection.Up) heightOffset = -heightOffset;
						let endValue = 0;
						let endY = 0;
						switch (note.bendType) {
							case BendType.Bend:
								endValue = this._getBendNoteValue(note, note.bendPoints[note.bendPoints.length - 1]);
								endY = this._endNoteGlyph.getNoteValueY(endValue) + heightOffset;
								this.drawBendSlur(canvas, startX, startY, endBeatX, endY, direction === BeamDirection.Down, slurText);
								break;
							case BendType.BendRelease:
								const middleValue = this._getBendNoteValue(note, note.bendPoints[1]);
								const middleY = this._middleNoteGlyph.getNoteValueY(middleValue) + heightOffset;
								this.drawBendSlur(canvas, startX, startY, middleX, middleY, direction === BeamDirection.Down, slurText);
								endValue = this._getBendNoteValue(note, note.bendPoints[note.bendPoints.length - 1]);
								endY = this._endNoteGlyph.getNoteValueY(endValue) + heightOffset;
								this.drawBendSlur(canvas, middleX, middleY, endBeatX, endY, direction === BeamDirection.Down, slurText);
								break;
							case BendType.Release:
								if (this.glyphs) {
									endValue = this._getBendNoteValue(note, note.bendPoints[note.bendPoints.length - 1]);
									endY = this.glyphs[0].getNoteValueY(endValue) + heightOffset;
									this.drawBendSlur(canvas, startX, startY, endBeatX, endY, direction === BeamDirection.Down, slurText);
								}
								break;
							case BendType.Prebend:
							case BendType.PrebendBend:
							case BendType.PrebendRelease:
								let preX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(note.beat, BeatXPosition.PreNotes);
								preX += this._container.prebendNoteHeadOffset;
								const preY = cy + startNoteRenderer.y + startNoteRenderer.getScoreY(startNoteRenderer.accidentalHelper.getNoteStepsForValue(note.displayValue - (note.bendPoints[0].value / 2 | 0), false)) + heightOffset;
								this.drawBendSlur(canvas, preX, preY, startX, startY, direction === BeamDirection.Down);
								if (this.glyphs) {
									endValue = this._getBendNoteValue(note, note.bendPoints[note.bendPoints.length - 1]);
									endY = this.glyphs[0].getNoteValueY(endValue) + heightOffset;
									this.drawBendSlur(canvas, startX, startY, endBeatX, endY, direction === BeamDirection.Down, slurText);
								}
								break;
						}
					}
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
		_getBendNoteValue(note, bendPoint) {
			return note.displayValueWithoutBend + (bendPoint.value / 2 | 0);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreLegatoGlyph.ts
	/**
	* @internal
	*/
	var ScoreLegatoGlyph = class extends TieGlyph {
		startBeat;
		endBeat;
		startBeatRenderer = null;
		endBeatRenderer = null;
		constructor(slurEffectId, startBeat, endBeat, forEnd) {
			super(slurEffectId, forEnd);
			this.startBeat = startBeat;
			this.endBeat = endBeat;
		}
		doLayout() {
			super.doLayout();
		}
		lookupStartBeatRenderer() {
			if (!this.startBeatRenderer) this.startBeatRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.startBeat.voice.bar);
			return this.startBeatRenderer;
		}
		lookupEndBeatRenderer() {
			if (!this.endBeatRenderer) this.endBeatRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.endBeat.voice.bar);
			return this.endBeatRenderer;
		}
		shouldDrawBendSlur() {
			return false;
		}
		calculateTieDirection() {
			if (this.startBeat.isRest) return BeamDirection.Up;
			switch (this.lookupStartBeatRenderer().getBeatDirection(this.startBeat)) {
				case BeamDirection.Up: return BeamDirection.Down;
				default: return BeamDirection.Up;
			}
		}
		calculateStartX() {
			const startBeatRenderer = this.lookupStartBeatRenderer();
			return startBeatRenderer.x + startBeatRenderer.getBeatX(this.startBeat, BeatXPosition.MiddleNotes);
		}
		calculateStartY() {
			const startBeatRenderer = this.lookupStartBeatRenderer();
			if (this.startBeat.isRest) switch (this.tieDirection) {
				case BeamDirection.Up: return startBeatRenderer.y + startBeatRenderer.getRestY(this.startBeat, NoteYPosition.Top);
				default: return startBeatRenderer.y + startBeatRenderer.getRestY(this.startBeat, NoteYPosition.Bottom);
			}
			switch (this.tieDirection) {
				case BeamDirection.Up: return startBeatRenderer.y + startBeatRenderer.getNoteY(this.startBeat.maxNote, NoteYPosition.Top);
				default: return startBeatRenderer.y + startBeatRenderer.getNoteY(this.startBeat.minNote, NoteYPosition.Bottom);
			}
		}
		calculateEndX() {
			const endBeatRenderer = this.lookupEndBeatRenderer();
			if (!endBeatRenderer) return this.calculateStartX() + this.renderer.smuflMetrics.leftHandTabTieWidth;
			const endBeamDirection = endBeatRenderer.getBeatDirection(this.endBeat);
			return endBeatRenderer.x + endBeatRenderer.getBeatX(this.endBeat, this.endBeat.duration > Duration.Whole && endBeamDirection === this.tieDirection ? BeatXPosition.Stem : BeatXPosition.MiddleNotes);
		}
		caclculateEndY() {
			const endBeatRenderer = this.lookupEndBeatRenderer();
			if (!endBeatRenderer) return this.calculateStartY();
			if (this.endBeat.isRest) switch (this.tieDirection) {
				case BeamDirection.Up: return endBeatRenderer.y + endBeatRenderer.getRestY(this.endBeat, NoteYPosition.Top);
				default: return endBeatRenderer.y + endBeatRenderer.getRestY(this.endBeat, NoteYPosition.Bottom);
			}
			const startBeamDirection = this.lookupStartBeatRenderer().getBeatDirection(this.startBeat);
			const endBeamDirection = endBeatRenderer.getBeatDirection(this.endBeat);
			if (startBeamDirection !== endBeamDirection && this.startBeat.graceType === GraceType.None) {
				if (endBeamDirection === this.tieDirection) switch (this.tieDirection) {
					case BeamDirection.Up: return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.maxNote, NoteYPosition.TopWithStem);
					default: return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.minNote, NoteYPosition.BottomWithStem);
				}
				switch (this.tieDirection) {
					case BeamDirection.Up: return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.maxNote, NoteYPosition.BottomWithStem);
					default: return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.minNote, NoteYPosition.TopWithStem);
				}
			}
			switch (this.tieDirection) {
				case BeamDirection.Up: return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.maxNote, NoteYPosition.Top);
				default: return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.minNote, NoteYPosition.Bottom);
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreSlideLineGlyph.ts
	/**
	* @internal
	*/
	var ScoreSlideLineGlyph = class extends Glyph {
		_outType;
		_inType;
		_startNote;
		_parent;
		checkForOverflow = false;
		constructor(inType, outType, startNote, parent) {
			super(0, 0);
			this._outType = outType;
			this._inType = inType;
			this._startNote = startNote;
			this._parent = parent;
		}
		doLayout() {
			this.width = 0;
		}
		paint(cx, cy, canvas) {
			this._paintSlideIn(cx, cy, canvas);
			this._drawSlideOut(cx, cy, canvas);
		}
		_paintSlideIn(cx, cy, canvas) {
			const startNoteRenderer = this.renderer;
			const sizeX = startNoteRenderer.smuflMetrics.simpleSlideWidth;
			let endX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Left) - startNoteRenderer.smuflMetrics.preNoteEffectPadding;
			const endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
			let startX = endX - sizeX;
			let startY = cy + startNoteRenderer.y;
			switch (this._inType) {
				case SlideInType.IntoFromBelow:
					startY += startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Bottom);
					break;
				case SlideInType.IntoFromAbove:
					startY += startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Top);
					break;
				default: return;
			}
			const accidentalsWidth = this._getAccidentalsWidth(startNoteRenderer, this._startNote.beat);
			startX -= accidentalsWidth;
			endX -= accidentalsWidth;
			this._paintSlideLine(canvas, false, startX, endX, startY, endY);
		}
		_getAccidentalsWidth(renderer, beat) {
			return renderer.getBeatContainer(beat).accidentalsWidth;
		}
		_drawSlideOut(cx, cy, canvas) {
			const startNoteRenderer = this.renderer;
			const sizeX = startNoteRenderer.smuflMetrics.simpleSlideWidth;
			const offsetX = startNoteRenderer.smuflMetrics.postNoteEffectPadding;
			let startX = 0;
			let startY = 0;
			let endX = 0;
			let endY = 0;
			let waves = false;
			switch (this._outType) {
				case SlideOutType.Shift:
				case SlideOutType.Legato:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(this._startNote.beat, BeatXPosition.PostNotes) + offsetX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					if (this._startNote.slideTarget) {
						const endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this._startNote.slideTarget.beat.voice.bar);
						if (!endNoteRenderer || endNoteRenderer.staff !== startNoteRenderer.staff) {
							endX = cx + startNoteRenderer.x + startNoteRenderer.width;
							if (this._startNote.slideTarget.realValue > this._startNote.realValue) endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Top);
							else endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Bottom);
						} else {
							endX = cx + endNoteRenderer.x + endNoteRenderer.getBeatX(this._startNote.slideTarget.beat, BeatXPosition.PreNotes) - offsetX;
							endY = cy + endNoteRenderer.y + endNoteRenderer.getNoteY(this._startNote.slideTarget, NoteYPosition.Center);
						}
					} else {
						endX = cx + startNoteRenderer.x + this._parent.x;
						endY = startY;
					}
					break;
				case SlideOutType.OutUp:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					endX = startX + sizeX;
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Top);
					break;
				case SlideOutType.OutDown:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					endX = startX + sizeX;
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Bottom);
					break;
				case SlideOutType.PickSlideUp:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX * 2;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Top);
					endX = cx + startNoteRenderer.x + startNoteRenderer.width;
					if (this._startNote.beat.nextBeat && this._startNote.beat.nextBeat.voice === this._startNote.beat.voice) endX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(this._startNote.beat.nextBeat, BeatXPosition.PreNotes);
					waves = true;
					break;
				case SlideOutType.PickSlideDown:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX * 2;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Bottom);
					endX = cx + startNoteRenderer.x + startNoteRenderer.width;
					if (this._startNote.beat.nextBeat && this._startNote.beat.nextBeat.voice === this._startNote.beat.voice) endX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(this._startNote.beat.nextBeat, BeatXPosition.PreNotes);
					waves = true;
					break;
				default: return;
			}
			this._paintSlideLine(canvas, waves, startX, endX, startY, endY);
		}
		_paintSlideLine(canvas, waves, startX, endX, startY, endY) {
			if (waves) {
				const glyph = new NoteVibratoGlyph(0, 0, VibratoType.Slight);
				glyph.renderer = this.renderer;
				glyph.doLayout();
				startY -= glyph.height / 2;
				endY -= glyph.height / 2;
				const b = endX - startX;
				const a = endY - startY;
				const c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
				glyph.width = b;
				const angle = Math.asin(a / c) * (180 / Math.PI);
				canvas.beginRotate(startX, startY, angle);
				glyph.paint(0, 0, canvas);
				canvas.endRotate();
			} else {
				canvas.beginPath();
				canvas.moveTo(startX, startY);
				canvas.lineTo(endX, endY);
				canvas.stroke();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreTieGlyph.ts
	/**
	* @internal
	*/
	var ScoreTieGlyph = class extends NoteTieGlyph {
		shouldDrawBendSlur() {
			return this.renderer.settings.notation.extendBendArrowsOnTiedNotes && !!this.startNote.bendOrigin && this.startNote.isTieOrigin;
		}
		calculateStartX() {
			if (this.isLeftHandTap) return this.calculateEndX() - this.renderer.smuflMetrics.leftHandTabTieWidth;
			return this.renderer.x + this.renderer.getBeatX(this.startNote.beat, BeatXPosition.PostNotes);
		}
		calculateEndX() {
			const endNoteRenderer = this.lookupEndBeatRenderer();
			if (!endNoteRenderer) return this.calculateStartX() + this.renderer.smuflMetrics.leftHandTabTieWidth;
			if (this.isLeftHandTap) return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Left);
			return endNoteRenderer.x + endNoteRenderer.getBeatX(this.endNote.beat, BeatXPosition.PreNotes);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/ScoreSlurGlyph.ts
	/**
	* @internal
	*/
	var ScoreSlurGlyph = class extends ScoreTieGlyph {
		_labels = null;
		getTieHeight(startX, _startY, endX, _endY) {
			return Math.log2(endX - startX + 1) * this.renderer.settings.notation.slurHeight / 2;
		}
		getSlurLabels() {
			if (this._labels === null) {
				this._labels = [];
				const slur = this.startNote.beat.effectSlur;
				if (slur !== null) {
					const notationSettings = this.renderer.settings.notation;
					for (const s of slur.segments) {
						const label = TieGlyphLabels.build(s, s.toNote.realValue >= s.fromNote.realValue);
						if (notationSettings.isNotationElementVisible(label.element)) this._labels.push(label);
					}
				}
			}
			return this._labels.length > 0 ? this._labels : null;
		}
		calculateStartX() {
			return this.renderer.x + (this._isStartCentered() ? this.renderer.getBeatX(this.startNote.beat, BeatXPosition.MiddleNotes) : this.renderer.getNoteX(this.startNote, NoteXPosition.Right));
		}
		calculateStartY() {
			if (this._isStartCentered()) switch (this.tieDirection) {
				case BeamDirection.Up: return this.renderer.y + this.renderer.getNoteY(this.startNote, NoteYPosition.Top);
				default: return this.renderer.y + this.renderer.getNoteY(this.startNote, NoteYPosition.Bottom);
			}
			return this.renderer.y + this.renderer.getNoteY(this.startNote, NoteYPosition.Center);
		}
		calculateEndX() {
			const endNoteRenderer = this.lookupEndBeatRenderer();
			if (!endNoteRenderer) return this.calculateStartX() + this.renderer.smuflMetrics.leftHandTabTieWidth;
			if (this._isEndCentered()) {
				if (this._isEndOnStem()) return endNoteRenderer.x + endNoteRenderer.getBeatX(this.endNote.beat, BeatXPosition.Stem);
				return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Center);
			}
			return endNoteRenderer.x + endNoteRenderer.getBeatX(this.endNote.beat, BeatXPosition.PreNotes);
		}
		caclculateEndY() {
			const endNoteRenderer = this.lookupEndBeatRenderer();
			if (!endNoteRenderer) return this.calculateStartY();
			if (this._isEndCentered()) {
				if (this._isEndOnStem()) switch (this.tieDirection) {
					case BeamDirection.Up: return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.TopWithStem);
					default: return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.BottomWithStem);
				}
				switch (this.tieDirection) {
					case BeamDirection.Up: return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Top);
					default: return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Bottom);
				}
			}
			return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Center);
		}
		_isStartCentered() {
			return this.startNote === this.startNote.beat.maxNote && this.tieDirection === BeamDirection.Up || this.startNote === this.startNote.beat.minNote && this.tieDirection === BeamDirection.Down;
		}
		_isEndCentered() {
			return this.startNote.beat.graceType === GraceType.None && (this.endNote === this.endNote.beat.maxNote && this.tieDirection === BeamDirection.Up || this.endNote === this.endNote.beat.minNote && this.tieDirection === BeamDirection.Down);
		}
		_isEndOnStem() {
			const startBeamDirection = this.lookupStartBeatRenderer().getBeatDirection(this.startNote.beat);
			const endBeatRenderer = this.lookupEndBeatRenderer();
			return startBeamDirection !== (endBeatRenderer ? endBeatRenderer.getBeatDirection(this.endNote.beat) : startBeamDirection) && this.startNote.beat.graceType === GraceType.None;
		}
	};
	//#endregion
	//#region src/rendering/ScoreBeatContainerGlyph.ts
	/**
	* @internal
	*/
	var ScoreBeatContainerGlyph = class extends BeatContainerGlyph {
		_bend = null;
		_effectSlur = null;
		_effectEndSlur = null;
		constructor(beat) {
			super(beat);
			this.preNotes = new ScoreBeatPreNotesGlyph();
			this.onNotes = new ScoreBeatGlyph();
		}
		get prebendNoteHeadOffset() {
			return this.preNotes.prebendNoteHeadOffset;
		}
		get accidentalsWidth() {
			const preNotes = this.preNotes;
			if (preNotes && preNotes.accidentals) return preNotes.accidentals.width;
			return 0;
		}
		doMultiVoiceLayout() {
			this.preNotes.x = 0;
			this.preNotes.doMultiVoiceLayout();
			this.onNotes.x = this.preNotes.x + this.preNotes.width;
			this.onNotes.doMultiVoiceLayout();
			this._bend?.doMultiVoiceLayout();
		}
		doLayout() {
			this._effectSlur = null;
			this._effectEndSlur = null;
			const sr = this.renderer;
			const beat = this.beat;
			const isGrace = beat.graceType !== GraceType.None;
			if (sr.hasFlag(beat)) {
				const direction = sr.getBeatDirection(beat);
				const scale = isGrace ? EngravingSettings.GraceScale : 1;
				const symbol = FlagGlyph.getSymbol(beat.duration, direction, isGrace);
				const flagWidth = sr.smuflMetrics.glyphWidths.get(symbol) * scale;
				this._flagStretch = flagWidth;
			} else if (isGrace) {
				const graceSpacing = sr.smuflMetrics.glyphWidths.get(MusicFontSymbol.Flag8thUp) * EngravingSettings.GraceScale;
				this._flagStretch = graceSpacing;
			}
			super.doLayout();
			if (this._bend) {
				this._bend.renderer = this.renderer;
				this._bend.doLayout();
				this.updateWidth();
			}
		}
		getBoundingBoxTop() {
			if (this._bend !== null) return ModelUtils.minBoundingBox(this._bend.getBoundingBoxTop(), super.getBoundingBoxTop());
			else return super.getBoundingBoxTop();
		}
		getBoundingBoxBottom() {
			if (this._bend !== null) return ModelUtils.maxBoundingBox(this._bend.getBoundingBoxBottom(), super.getBoundingBoxTop());
			else return super.getBoundingBoxBottom();
		}
		createTies(n) {
			if (!n.isVisible) return;
			if (n.isTieOrigin && !n.hasBend && !n.beat.hasWhammyBar && n.beat.graceType !== GraceType.BendGrace && n.tieDestination && n.tieDestination.isVisible) {
				const tie = new ScoreTieGlyph(`score.tie.${n.id}`, n, n.tieDestination, false);
				this.addTie(tie);
			}
			if (n.isTieDestination && !n.tieOrigin.hasBend && !n.beat.hasWhammyBar) {
				const tie = new ScoreTieGlyph(`score.tie.${n.tieOrigin.id}`, n.tieOrigin, n, true);
				this.addTie(tie);
			}
			if (n.slideInType !== SlideInType.None || n.slideOutType !== SlideOutType.None) {
				const l = new ScoreSlideLineGlyph(n.slideInType, n.slideOutType, n, this);
				this.addTie(l);
			}
			if (n.isSlurOrigin && n.slurDestination && n.slurDestination.isVisible) {
				const tie = new ScoreSlurGlyph(`score.slur.${n.id}`, n, n.slurDestination, false);
				this.addTie(tie);
			}
			if (n.isSlurDestination) {
				const tie = new ScoreSlurGlyph(`score.slur.${n.slurOrigin.id}`, n.slurOrigin, n, true);
				this.addTie(tie);
			}
			if (!this._effectSlur && n.isEffectSlurOrigin && n.effectSlurDestination) {
				const effectSlur = new ScoreSlurGlyph(`score.slur.effect.${n.beat.id}`, n, n.effectSlurDestination, false);
				this._effectSlur = effectSlur;
				this.addTie(effectSlur);
			}
			if (!this._effectEndSlur && n.beat.isEffectSlurDestination && n.beat.effectSlurOrigin) {
				const direction = this.renderer.getBeatDirection(n.beat);
				const startNote = direction === BeamDirection.Up ? n.beat.effectSlurOrigin.minNote : n.beat.effectSlurOrigin.maxNote;
				const endNote = direction === BeamDirection.Up ? n.beat.minNote : n.beat.maxNote;
				const effectEndSlur = new ScoreSlurGlyph(`score.slur.effect.${startNote.beat.id}`, startNote, endNote, true);
				this._effectEndSlur = effectEndSlur;
				this.addTie(effectEndSlur);
			}
			if (n.hasBend) {
				if (!this._bend) {
					const bend = new ScoreBendGlyph(this);
					this._bend = bend;
					bend.renderer = this.renderer;
					this.addTie(bend);
				}
				this._bend.addBends(n);
			}
			if (this.beat.isLegatoOrigin) {
				if (!this.beat.previousBeat || !this.beat.previousBeat.isLegatoOrigin) {
					let destination = this.beat.nextBeat;
					while (destination.nextBeat && destination.nextBeat.isLegatoDestination) destination = destination.nextBeat;
					this.addTie(new ScoreLegatoGlyph(`score.legato.${this.beat.id}`, this.beat, destination, false));
				}
			} else if (this.beat.isLegatoDestination) {
				if (!this.beat.isLegatoOrigin) {
					let origin = this.beat.previousBeat;
					while (origin.previousBeat && origin.previousBeat.isLegatoOrigin) origin = origin.previousBeat;
					this.addTie(new ScoreLegatoGlyph(`score.legato.${origin.id}`, origin, this.beat, true));
				}
			}
		}
		_flagStretch = 0;
		get postBeatStretch() {
			return super.postBeatStretch + this._flagStretch;
		}
		updateWidth() {
			super.updateWidth();
			this.width += this._flagStretch;
		}
	};
	//#endregion
	//#region src/rendering/ScoreBarRenderer.ts
	/**
	* This BarRenderer renders a bar using standard music notation.
	* @internal
	*/
	var ScoreBarRenderer = class ScoreBarRenderer extends LineBarRenderer {
		static StaffId = "score";
		static _sharpKsSteps = [
			-1,
			2,
			-2,
			1,
			4,
			0,
			3
		];
		static _flatKsSteps = [
			3,
			0,
			4,
			1,
			5,
			2,
			6
		];
		accidentalHelper;
		constructor(renderer, bar) {
			super(renderer, bar);
			this.accidentalHelper = new AccidentalHelper(this);
		}
		get repeatsBarSubElement() {
			return BarSubElement.StandardNotationRepeats;
		}
		get barNumberBarSubElement() {
			return BarSubElement.StandardNotationBarNumber;
		}
		get barLineBarSubElement() {
			return BarSubElement.StandardNotationBarLines;
		}
		get staffLineBarSubElement() {
			return BarSubElement.StandardNotationStaffLine;
		}
		get lineSpacing() {
			return this.smuflMetrics.oneStaffSpace;
		}
		get heightLineCount() {
			return Math.max(5, this.bar.staff.standardNotationLineCount);
		}
		get drawnLineCount() {
			return this.bar.staff.standardNotationLineCount;
		}
		/**
		* Gets the relative y position of the given steps relative to first line.
		* @param steps the amount of steps while 2 steps are one line
		* @returns
		*/
		getScoreY(steps) {
			return super.getLineY(steps / 2);
		}
		/**
		* Gets the height of an element that spans the given amount of steps.
		* @param steps the amount of steps while 2 steps are one line
		* @param correction
		* @returns
		*/
		getScoreHeight(steps) {
			return super.getLineHeight(steps / 2);
		}
		calculateOverflows(rendererTop, rendererBottom) {
			super.calculateOverflows(rendererTop, rendererBottom);
			if (this.bar.isEmpty) return;
			this.calculateBeamingOverflows(rendererTop, rendererBottom);
		}
		get flagsSubElement() {
			return BeatSubElement.StandardNotationFlags;
		}
		get beamsSubElement() {
			return BeatSubElement.StandardNotationBeams;
		}
		get tupletSubElement() {
			return BeatSubElement.StandardNotationTuplet;
		}
		getFlagTopY(beat, direction) {
			const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
			if (beat.isRest) return this.getRestY(beat, position);
			else return this.voiceContainer.getHighestNoteY(beat, position);
		}
		getFlagBottomY(beat, direction) {
			const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
			if (beat.isRest) return this.getRestY(beat, position);
			else return this.voiceContainer.getLowestNoteY(beat, position);
		}
		getBeamDirection(helper) {
			return this._beamDirections.has(helper) ? this._beamDirections.get(helper) : BeamDirection.Up;
		}
		centerStaffStemY(direction) {
			if (this.bar.staff.standardNotationLineCount === Staff.DefaultStandardNotationLineCount) return this.getScoreY(this.bar.staff.standardNotationLineCount - 1);
			if (direction === BeamDirection.Up) return this.getScoreY(this.bar.staff.standardNotationLineCount * 2);
			return this.getScoreY(0);
		}
		get middleYPosition() {
			return this.getScoreY(this.bar.staff.standardNotationLineCount - 1);
		}
		applyLayoutingInfo() {
			const result = super.applyLayoutingInfo();
			if (result && this.bar.isMultiVoice) {
				const top = this.getScoreY(-2);
				const bottom = this.getScoreY(this.heightLineCount * 2);
				const minMax = this.helpers.collisionHelper.getBeatMinMaxY();
				if (minMax[0] < top) this.registerOverflowTop(Math.abs(minMax[0]));
				if (minMax[1] > bottom) this.registerOverflowBottom(Math.abs(minMax[1]) - bottom);
			}
			return result;
		}
		getMinLineOfBeat(beat) {
			return this.accidentalHelper.getMinSteps(beat) / 2;
		}
		getMaxLineOfBeat(beat) {
			return this.accidentalHelper.getMaxSteps(beat) / 2;
		}
		createLinePreBeatGlyphs() {
			let hasClef = false;
			if (this.isFirstOfStaff || this.bar.clef !== this.bar.previousBar.clef || this.bar.clefOttava !== this.bar.previousBar.clefOttava) {
				let offset = 0;
				switch (this.bar.clef) {
					case Clef.Neutral:
						offset = this.bar.staff.standardNotationLineCount - 1;
						break;
					case Clef.F4:
						offset = 2;
						break;
					case Clef.C3:
						offset = 4;
						break;
					case Clef.C4:
						offset = 2;
						break;
					case Clef.G2:
						offset = 6;
						break;
				}
				this.createStartSpacing();
				this.addPreBeatGlyph(new ClefGlyph(0, this.getScoreY(offset), this.bar.clef, this.bar.clefOttava));
				this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.preBeatGlyphSpacing));
				hasClef = true;
			}
			if (hasClef || this.index === 0 && this.bar.keySignature !== KeySignature.C || this.bar.previousBar && this.bar.keySignature !== this.bar.previousBar.keySignature) {
				this.createStartSpacing();
				this._createKeySignatureGlyphs();
			}
			if (!this.bar.previousBar || this.bar.previousBar && this.bar.masterBar.timeSignatureNumerator !== this.bar.previousBar.masterBar.timeSignatureNumerator || this.bar.previousBar && this.bar.masterBar.timeSignatureDenominator !== this.bar.previousBar.masterBar.timeSignatureDenominator || this.bar.previousBar && this.bar.masterBar.isFreeTime && this.bar.masterBar.isFreeTime !== this.bar.previousBar.masterBar.isFreeTime) {
				this.createStartSpacing();
				this._createTimeSignatureGlyphs();
			}
		}
		_createKeySignatureGlyphs() {
			let offsetClef = 0;
			const currentKey = this.bar.keySignature;
			const previousKey = !this.bar.previousBar ? 0 : this.bar.previousBar.keySignature;
			switch (this.bar.clef) {
				case Clef.Neutral:
					offsetClef = 0;
					break;
				case Clef.G2:
					offsetClef = 1;
					break;
				case Clef.F4:
					offsetClef = 3;
					break;
				case Clef.C3:
					offsetClef = 2;
					break;
				case Clef.C4:
					offsetClef = 0;
					break;
			}
			const glyph = new KeySignatureGlyph();
			glyph.gap = this.smuflMetrics.accidentalPadding;
			glyph.renderer = this;
			const newLines = /* @__PURE__ */ new Map();
			const newGlyphs = [];
			if (ModelUtils.keySignatureIsSharp(currentKey)) for (let i = 0; i < Math.abs(currentKey); i++) {
				const step = ScoreBarRenderer._sharpKsSteps[i] + offsetClef;
				newGlyphs.push(new AccidentalGlyph(0, this.getScoreY(step), AccidentalType.Sharp, 1));
				newLines.set(step, true);
			}
			else for (let i = 0; i < Math.abs(currentKey); i++) {
				const step = ScoreBarRenderer._flatKsSteps[i] + offsetClef;
				newGlyphs.push(new AccidentalGlyph(0, this.getScoreY(step), AccidentalType.Flat, 1));
				newLines.set(step, true);
			}
			if (this.bar.keySignature === KeySignature.C) {
				const naturalizeSymbols = Math.abs(previousKey);
				const previousKeyPositions = ModelUtils.keySignatureIsSharp(previousKey) ? ScoreBarRenderer._sharpKsSteps : ScoreBarRenderer._flatKsSteps;
				for (let i = 0; i < naturalizeSymbols; i++) {
					const step = previousKeyPositions[i] + offsetClef;
					if (!newLines.has(step)) glyph.addGlyph(new AccidentalGlyph(0, this.getScoreY(previousKeyPositions[i] + offsetClef), AccidentalType.Natural, 1));
				}
			}
			for (const newGlyph of newGlyphs) glyph.addGlyph(newGlyph);
			this.addPreBeatGlyph(glyph);
			if (!glyph.isEmpty) this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.preBeatGlyphSpacing));
		}
		_createTimeSignatureGlyphs() {
			const lines = this.bar.staff.standardNotationLineCount - 1;
			this.addPreBeatGlyph(new ScoreTimeSignatureGlyph(0, this.getScoreY(lines), this.bar.masterBar.timeSignatureNumerator, this.bar.masterBar.timeSignatureDenominator, this.bar.masterBar.timeSignatureCommon, this.bar.masterBar.isFreeTime));
			this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.preBeatGlyphSpacing));
		}
		createVoiceGlyphs(v) {
			super.createVoiceGlyphs(v);
			for (const b of v.beats) this.addBeatGlyph(new ScoreBeatContainerGlyph(b));
		}
		getNoteLine(note) {
			return this.accidentalHelper.getNoteSteps(note) / 2;
		}
		getNoteSteps(n) {
			return this.accidentalHelper.getNoteSteps(n);
		}
		_beamDirections = /* @__PURE__ */ new Map();
		completeBeamingHelper(helper) {
			const direction = this._calculateBeamDirection(helper);
			this._beamDirections.set(helper, direction);
		}
		_calculateBeamDirection(helper) {
			if (!helper.voice) return BeamDirection.Up;
			if (helper.preferredBeamDirection !== null) return helper.preferredBeamDirection;
			if (helper.voice.index > 0) return this._invertBeamDirection(helper, BeamDirection.Down);
			if (helper.voice.bar.isMultiVoice) return this._invertBeamDirection(helper, BeamDirection.Up);
			if (helper.beats[0].graceType !== GraceType.None) return this._invertBeamDirection(helper, BeamDirection.Up);
			if (helper.beats.length === 1 && helper.beats[0].slashed) return this._invertBeamDirection(helper, BeamDirection.Down);
			if (helper.highestNoteInHelper && helper.lowestNoteInHelper) {
				const avg = (this._getNoteCenterYBeforeLayouting(helper.highestNoteInHelper) + this._getNoteCenterYBeforeLayouting(helper.lowestNoteInHelper)) / 2;
				return this._invertBeamDirection(helper, this.middleYPosition < avg ? BeamDirection.Up : BeamDirection.Down);
			}
			return this._invertBeamDirection(helper, BeamDirection.Up);
		}
		_getNoteCenterYBeforeLayouting(note) {
			const steps = AccidentalHelper.computeStepsWithoutAccidentals(this.bar, note);
			return this.getScoreY(steps);
		}
		_invertBeamDirection(helper, direction) {
			if (!helper.invertBeamDirection) return direction;
			switch (direction) {
				case BeamDirection.Down: return BeamDirection.Up;
				default: return BeamDirection.Down;
			}
		}
		paintBeamingStem(beat, _cy, x, topY, bottomY, canvas) {
			const _ = ElementStyleHelper.beat(canvas, BeatSubElement.StandardNotationStem, beat);
			try {
				canvas.fillRect(x, topY, this.smuflMetrics.stemThickness, bottomY - topY);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
	};
	//#endregion
	//#region src/rendering/ScoreBarRendererFactory.ts
	/**
	* This Factory produces ScoreBarRenderer instances
	* @internal
	*/
	var ScoreBarRendererFactory = class extends BarRendererFactory {
		get staffId() {
			return ScoreBarRenderer.StaffId;
		}
		create(renderer, bar) {
			return new ScoreBarRenderer(renderer, bar);
		}
		canCreate(track, staff) {
			return super.canCreate(track, staff) && staff.showStandardNotation;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/SlashRestGlyph.ts
	/**
	* @internal
	*/
	var SlashRestGlyph = class extends ScoreRestGlyph {
		paint(cx, cy, canvas) {
			super.internalPaint(cx, cy, canvas, BeatSubElement.SlashRests);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/SlashBeatGlyph.ts
	/**
	* @internal
	*/
	var SlashBeatGlyph = class extends BeatOnNoteGlyphBase {
		_tremoloPicking;
		_stemLengthExtension = 0;
		noteHeads = null;
		deadSlapped = null;
		restGlyph = null;
		get effectElement() {
			return BeatSubElement.SlashEffects;
		}
		getNoteX(_note, requestedPosition) {
			let g = null;
			if (this.noteHeads) g = this.noteHeads;
			else if (this.deadSlapped) g = this.deadSlapped;
			if (g) {
				let pos = g.x;
				switch (requestedPosition) {
					case NoteXPosition.Left: break;
					case NoteXPosition.Center:
						pos += g.width / 2;
						break;
					case NoteXPosition.Right:
						pos += g.width;
						break;
				}
				return pos;
			}
			return 0;
		}
		buildBoundingsLookup(beatBounds, cx, cy) {
			if (this.noteHeads && this.container.beat.notes.length > 0) {
				const noteBounds = new NoteBounds();
				noteBounds.note = this.container.beat.notes[0];
				noteBounds.noteHeadBounds = new Bounds();
				noteBounds.noteHeadBounds.x = cx + this.x + this.noteHeads.x;
				noteBounds.noteHeadBounds.y = cy + this.y + this.noteHeads.y - this.noteHeads.height / 2;
				noteBounds.noteHeadBounds.w = this.width;
				noteBounds.noteHeadBounds.h = this.height;
				beatBounds.addNote(noteBounds);
			}
		}
		getLowestNoteY(requestedPosition) {
			return this._internalGetNoteY(requestedPosition);
		}
		getHighestNoteY(requestedPosition) {
			return this._internalGetNoteY(requestedPosition);
		}
		getRestY(requestedPosition) {
			const g = this.restGlyph;
			if (g) switch (requestedPosition) {
				case NoteYPosition.TopWithStem: return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
				case NoteYPosition.Top: return g.getBoundingBoxTop();
				case NoteYPosition.Center:
				case NoteYPosition.StemUp:
				case NoteYPosition.StemDown: return g.getBoundingBoxTop() + g.height / 2;
				case NoteYPosition.Bottom: return g.getBoundingBoxBottom();
				case NoteYPosition.BottomWithStem: return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
			}
			return 0;
		}
		getNoteY(_note, requestedPosition) {
			return this._internalGetNoteY(requestedPosition);
		}
		_internalGetNoteY(requestedPosition) {
			let g = null;
			let symbol = MusicFontSymbol.None;
			let hasStem = false;
			if (this.noteHeads) {
				g = this.noteHeads;
				symbol = SlashNoteHeadGlyph.getSymbol(this.container.beat.duration);
				hasStem = true;
			} else if (this.deadSlapped) g = this.deadSlapped;
			if (g) {
				let pos = this.y + g.y;
				const sr = this.renderer;
				const beat = this.container.beat;
				const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
				switch (requestedPosition) {
					case NoteYPosition.TopWithStem:
						if (hasStem) {
							pos -= (sr.smuflMetrics.stemUp.has(symbol) ? sr.smuflMetrics.stemUp.get(symbol).bottomY : 0) * scale;
							pos -= sr.smuflMetrics.getStemLength(beat.duration, sr.hasFlag(beat)) * scale;
							pos -= this._stemLengthExtension;
						} else pos -= g.height / 2;
						return pos;
					case NoteYPosition.Top:
						pos -= g.height / 2;
						break;
					case NoteYPosition.Center: break;
					case NoteYPosition.Bottom:
						pos += g.height / 2;
						break;
					case NoteYPosition.BottomWithStem:
						if (hasStem) {
							pos -= (sr.smuflMetrics.stemDown.has(symbol) ? sr.smuflMetrics.stemDown.get(symbol).topY : -sr.smuflMetrics.glyphHeights.get(symbol) / 2) * scale;
							pos += sr.smuflMetrics.getStemLength(beat.duration, sr.hasFlag(beat)) * scale;
							pos += this._stemLengthExtension;
						} else pos += g.height / 2;
						return pos;
					case NoteYPosition.StemUp:
						pos -= this.renderer.smuflMetrics.stemUp.has(symbol) ? this.renderer.smuflMetrics.stemUp.get(symbol).bottomY : 0;
						break;
					case NoteYPosition.StemDown:
						pos -= this.renderer.smuflMetrics.stemDown.has(symbol) ? this.renderer.smuflMetrics.stemDown.get(symbol).topY : 0;
						break;
				}
				return pos;
			}
			return 0;
		}
		doLayout() {
			const sr = this.renderer;
			const glyphY = sr.getLineY(0);
			if (this.container.beat.deadSlapped) {
				const deadSlapped = new DeadSlappedBeatGlyph();
				deadSlapped.renderer = this.renderer;
				deadSlapped.doLayout();
				this.deadSlapped = deadSlapped;
				this.addEffect(deadSlapped);
			} else if (!this.container.beat.isEmpty) if (!this.container.beat.isRest) {
				const noteHeadGlyph = new SlashNoteHeadGlyph(0, glyphY, this.container.beat);
				this.noteHeads = noteHeadGlyph;
				noteHeadGlyph.beat = this.container.beat;
				this.addNormal(noteHeadGlyph);
				if (this.container.beat.isTremolo) {
					this._tremoloPicking = new TremoloPickingGlyph(0, 0, this.container.beat.tremoloPicking);
					this._tremoloPicking.renderer = this.renderer;
					this._tremoloPicking.doLayout();
					this._alignTremoloPickingGlyph();
				}
			} else {
				const restGlyph = new SlashRestGlyph(0, glyphY, this.container.beat.duration);
				this.restGlyph = restGlyph;
				restGlyph.beat = this.container.beat;
				this.addNormal(restGlyph);
			}
			if (this.container.beat.dots > 0) for (let i = 0; i < this.container.beat.dots; i++) this.addEffect(new AugmentationDotGlyph(0, glyphY - sr.getLineHeight(.5)));
			super.doLayout();
			if (this.container.beat.isEmpty) {
				this.onTimeX = this.width / 2;
				this.stemX = this.onTimeX;
			} else if (this.restGlyph) {
				this.onTimeX = this.restGlyph.x + this.restGlyph.width / 2;
				this.stemX = this.onTimeX;
			} else if (this.noteHeads) {
				this.onTimeX = this.noteHeads.x + this.noteHeads.width / 2;
				this.stemX = this.noteHeads.x + this.noteHeads.stemX;
			} else if (this.deadSlapped) {
				this.onTimeX = this.deadSlapped.x + this.deadSlapped.width / 2;
				this.stemX = this.onTimeX;
			}
			this.middleX = this.onTimeX;
			const tremolo = this._tremoloPicking;
			if (tremolo) tremolo.x = this.container.beat.duration < Duration.Half ? this.width / 2 : this.stemX;
		}
		_alignTremoloPickingGlyph() {
			const g = this._tremoloPicking;
			g.alignTremoloPickingGlyph(BeamDirection.Up, this._internalGetNoteY(NoteYPosition.TopWithStem), this._internalGetNoteY(NoteYPosition.Center), this.container.beat.duration);
			this._stemLengthExtension = g.stemExtensionHeight;
			let tremoloX = this.stemX;
			if (this.container.beat.duration < Duration.Half) tremoloX = this.width / 2;
			g.x = tremoloX;
		}
		paint(cx, cy, canvas) {
			super.paint(cx, cy, canvas);
			const tremolo = this._tremoloPicking;
			if (tremolo) tremolo.paint(cx + this.x, cy + this.y, canvas);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/SlashTieGlyph.ts
	/**
	* @internal
	*/
	var SlashTieGlyph = class extends NoteTieGlyph {
		calculateTieDirection() {
			return BeamDirection.Down;
		}
		getStartNotePosition() {
			return NoteXPosition.Right;
		}
		getEndNotePosition() {
			return NoteXPosition.Left;
		}
	};
	//#endregion
	//#region src/rendering/SlashBeatContainerGlyph.ts
	/**
	* @internal
	*/
	var SlashBeatContainerGlyph = class extends BeatContainerGlyph {
		_tiedNoteTie = null;
		constructor(beat) {
			super(beat);
			this.preNotes = new BeatGlyphBase();
			this.onNotes = new SlashBeatGlyph();
		}
		doLayout() {
			const sr = this.renderer;
			const beat = this.beat;
			const isGrace = beat.graceType !== GraceType.None;
			if (sr.hasFlag(beat)) {
				const direction = sr.getBeatDirection(beat);
				const scale = isGrace ? EngravingSettings.GraceScale : 1;
				const symbol = FlagGlyph.getSymbol(beat.duration, direction, isGrace);
				const flagWidth = sr.smuflMetrics.glyphWidths.get(symbol) * scale;
				this._flagStretch = flagWidth;
			} else if (isGrace) {
				const graceSpacing = sr.smuflMetrics.glyphWidths.get(MusicFontSymbol.Flag8thUp) * EngravingSettings.GraceScale;
				this._flagStretch = graceSpacing;
			}
			super.doLayout();
		}
		createTies(n) {
			if (!n.isVisible) return;
			if (!this._tiedNoteTie && n.isTieOrigin && n.tieDestination.isVisible) {
				const tie = new SlashTieGlyph("slash.tie", n, n.tieDestination, false);
				this._tiedNoteTie = tie;
				this.addTie(tie);
			}
			if (!this._tiedNoteTie && n.isTieDestination) {
				const tie = new SlashTieGlyph("slash.tie", n.tieOrigin, n, true);
				this._tiedNoteTie = tie;
				this.addTie(tie);
			}
		}
		_flagStretch = 0;
		get postBeatStretch() {
			return super.postBeatStretch + this._flagStretch;
		}
		updateWidth() {
			super.updateWidth();
			this.width += this._flagStretch;
		}
	};
	//#endregion
	//#region src/rendering/SlashBarRenderer.ts
	/**
	* This BarRenderer renders a bar using Slash Rhythm notation
	* @internal
	*/
	var SlashBarRenderer = class extends LineBarRenderer {
		static StaffId = "slash";
		simpleWhammyOverflow = 0;
		_isOnlySlash;
		constructor(renderer, bar) {
			super(renderer, bar);
			this._isOnlySlash = !bar.staff.showTablature && !bar.staff.showStandardNotation;
			this.helpers.preferredBeamDirection = BeamDirection.Up;
		}
		get repeatsBarSubElement() {
			return BarSubElement.SlashRepeats;
		}
		get barNumberBarSubElement() {
			return BarSubElement.SlashBarNumber;
		}
		get barLineBarSubElement() {
			return BarSubElement.SlashBarLines;
		}
		get staffLineBarSubElement() {
			return BarSubElement.SlashStaffLine;
		}
		get lineSpacing() {
			return this.smuflMetrics.oneStaffSpace;
		}
		get heightLineCount() {
			return 5;
		}
		get drawnLineCount() {
			return 1;
		}
		get bottomGlyphOverflow() {
			return 0;
		}
		get flagsSubElement() {
			return BeatSubElement.SlashFlags;
		}
		get beamsSubElement() {
			return BeatSubElement.SlashBeams;
		}
		get tupletSubElement() {
			return BeatSubElement.SlashTuplet;
		}
		doLayout() {
			super.doLayout();
			if (this.voiceContainer.tupletGroups.size > 0) this.registerOverflowTop(this.tupletSize);
		}
		getNoteLine(_note) {
			return 0;
		}
		getFlagTopY(beat, direction) {
			const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
			if (beat.notes.length > 0) return this.getNoteY(beat.notes[0], position);
			else return this.getRestY(beat, position);
		}
		getFlagBottomY(beat, direction) {
			const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
			if (beat.notes.length > 0) return this.getNoteY(beat.notes[0], position);
			else return this.getRestY(beat, position);
		}
		getBeamDirection(_helper) {
			return BeamDirection.Up;
		}
		createLinePreBeatGlyphs() {
			if (this._isOnlySlash && (!this.bar.previousBar || this.bar.previousBar && this.bar.masterBar.timeSignatureNumerator !== this.bar.previousBar.masterBar.timeSignatureNumerator || this.bar.previousBar && this.bar.masterBar.timeSignatureDenominator !== this.bar.previousBar.masterBar.timeSignatureDenominator || this.bar.previousBar && this.bar.masterBar.isFreeTime && this.bar.masterBar.isFreeTime !== this.bar.previousBar.masterBar.isFreeTime)) {
				this.createStartSpacing();
				this._createTimeSignatureGlyphs();
			}
		}
		_createTimeSignatureGlyphs() {
			this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.oneStaffSpace));
			const masterBar = this.bar.masterBar;
			const g = new ScoreTimeSignatureGlyph(0, this.getLineY(0), masterBar.timeSignatureNumerator, masterBar.timeSignatureDenominator, masterBar.timeSignatureCommon, masterBar.isFreeTime && (masterBar.previousMasterBar == null || masterBar.isFreeTime !== masterBar.previousMasterBar.isFreeTime));
			g.barSubElement = BarSubElement.SlashTimeSignature;
			this.addPreBeatGlyph(g);
		}
		createVoiceGlyphs(v) {
			if (v.index > 0) return;
			super.createVoiceGlyphs(v);
			for (const b of v.beats) this.addBeatGlyph(new SlashBeatContainerGlyph(b));
		}
		calculateOverflows(rendererTop, rendererBottom) {
			super.calculateOverflows(rendererTop, rendererBottom);
			if (this.bar.isEmpty) return;
			this.calculateBeamingOverflows(rendererTop, rendererBottom);
		}
		shouldPaintBeamingHelper(h) {
			return super.shouldPaintBeamingHelper(h) && h.voice.index === 0;
		}
		paintBeamingStem(beat, _cy, x, topY, bottomY, canvas) {
			const _ = ElementStyleHelper.beat(canvas, BeatSubElement.SlashStem, beat);
			try {
				canvas.fillRect(x, topY, this.smuflMetrics.stemThickness, bottomY - topY);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement) {
			if (h.voice?.index === 0) super.paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement);
		}
	};
	//#endregion
	//#region src/rendering/SlashBarRendererFactory.ts
	/**
	* This Factory produces SlashBarRenderer instances
	* @internal
	*/
	var SlashBarRendererFactory = class extends BarRendererFactory {
		get staffId() {
			return SlashBarRenderer.StaffId;
		}
		create(renderer, bar) {
			return new SlashBarRenderer(renderer, bar);
		}
		canCreate(track, staff) {
			return super.canCreate(track, staff) && staff.showSlash;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/NoteNumberGlyph.ts
	/**
	* @internal
	*/
	var NoteNumberGlyph = class extends Glyph {
		_note;
		_noteString = null;
		_trillNoteString = null;
		_trillNoteStringWidth = 0;
		isEmpty = false;
		noteStringWidth = 0;
		constructor(x, y, note) {
			super(x, y);
			this._note = note;
		}
		get _padding() {
			return this.renderer.lineSpacing * .25;
		}
		getBoundingBoxTop() {
			return this.y - this.height / 2 - this._padding;
		}
		getBoundingBoxBottom() {
			return this.y + this.height / 2;
		}
		doLayout() {
			const n = this._note;
			let fret = n.fret - n.beat.voice.bar.staff.transpositionPitch;
			if (n.harmonicType === HarmonicType.Natural && n.harmonicValue !== 0) fret = n.harmonicValue - n.beat.voice.bar.staff.transpositionPitch;
			if (!n.isTieDestination) {
				this._noteString = n.isDead ? "x" : fret.toString();
				if (n.isGhost) this._noteString = `(${this._noteString})`;
				else if (n.harmonicType === HarmonicType.Natural) {
					const i = this._noteString.indexOf(String.fromCharCode(46));
					if (i >= 0) this._noteString = this._noteString.substr(0, i + 2);
					this._noteString = `<${this._noteString}>`;
				}
			} else if (n.beat.index === 0 && this.renderer.settings.notation.notationMode === NotationMode.GuitarPro || (n.bendType === BendType.Bend || n.bendType === BendType.BendRelease) && this.renderer.settings.notation.isNotationElementVisible(NotationElement.TabNotesOnTiedBends)) this._noteString = `(${(n.tieOrigin.fret - n.beat.voice.bar.staff.transpositionPitch).toString()})`;
			else this._noteString = "";
			if (n.isTrill) this._trillNoteString = `(${(n.trillFret - n.beat.voice.bar.staff.transpositionPitch).toString()})`;
			else if (!ModelUtils.isAlmostEqualTo(n.harmonicValue, 0)) switch (n.harmonicType) {
				case HarmonicType.Artificial:
				case HarmonicType.Pinch:
				case HarmonicType.Tap:
				case HarmonicType.Semi:
				case HarmonicType.Feedback:
					let s = (fret + n.harmonicValue).toString();
					const i = s.indexOf(String.fromCharCode(46));
					if (i >= 0) s = s.substr(0, i + 2);
					this._trillNoteString = `<${s}>`;
					break;
				default:
					this._trillNoteString = "";
					break;
			}
			else this._trillNoteString = "";
			this.isEmpty = !this._noteString;
			if (!this.isEmpty) {
				this.renderer.scoreRenderer.canvas.font = this.renderer.resources.tablatureFont;
				const hasTrill = !!this._trillNoteString;
				this.noteStringWidth = this.renderer.scoreRenderer.canvas.measureText(this._noteString + (hasTrill ? " " : "")).width;
				this.width = this.noteStringWidth;
				this.height = this.renderer.scoreRenderer.canvas.font.size;
				if (hasTrill) {
					this.renderer.scoreRenderer.canvas.font = this.renderer.resources.graceFont;
					this._trillNoteStringWidth = 3 + this.renderer.scoreRenderer.canvas.measureText(this._trillNoteString).width;
					this.width += this._trillNoteStringWidth;
				}
			}
		}
		paint(cx, cy, canvas) {
			if (this.isEmpty) return;
			const textWidth = this.noteStringWidth + this._trillNoteStringWidth;
			const x = cx + this.x + (this.width - textWidth) / 2;
			const y = cy + this.y;
			this.paintTrill(x, y, canvas);
			const _ = ElementStyleHelper.note(canvas, NoteSubElement.GuitarTabFretNumber, this._note);
			try {
				canvas.fillText(this._noteString, x, y);
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		paintTrill(x, cy, canvas) {
			const _ = ElementStyleHelper.note(canvas, NoteSubElement.GuitarTabFretNumber, this._note);
			try {
				const prevFont = this.renderer.scoreRenderer.canvas.font;
				this.renderer.scoreRenderer.canvas.font = this.renderer.resources.graceFont;
				canvas.fillText(this._trillNoteString, x + this.noteStringWidth, cy);
				this.renderer.scoreRenderer.canvas.font = prevFont;
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		buildBoundingsLookup(beatBounds, cx, cy) {
			const noteBounds = new NoteBounds();
			noteBounds.note = this._note;
			noteBounds.noteHeadBounds = new Bounds();
			noteBounds.noteHeadBounds.x = cx + this.x;
			noteBounds.noteHeadBounds.y = cy + this.y - this.height / 2;
			noteBounds.noteHeadBounds.w = this.width;
			noteBounds.noteHeadBounds.h = this.height;
			beatBounds.addNote(noteBounds);
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabNoteChordGlyph.ts
	/**
	* @internal
	*/
	var TabNoteChordGlyph = class extends Glyph {
		_notes = [];
		_deadSlapped = null;
		_isGrace;
		beat;
		maxStringNote = null;
		minStringNote = null;
		beatEffects = /* @__PURE__ */ new Map();
		notesPerString = /* @__PURE__ */ new Map();
		noteStringWidth = 0;
		constructor(x, y, isGrace) {
			super(x, y);
			this._isGrace = isGrace;
		}
		buildBoundingsLookup(beatBounds, cx, cy) {
			for (const note of this._notes) note.buildBoundingsLookup(beatBounds, cx + this.x, cy + this.y);
		}
		getNoteX(note, requestedPosition) {
			if (this.notesPerString.has(note.string)) {
				const n = this.notesPerString.get(note.string);
				let pos = this.x + n.x;
				switch (requestedPosition) {
					case NoteXPosition.Left: break;
					case NoteXPosition.Center:
						pos += n.noteStringWidth / 2;
						break;
					case NoteXPosition.Right:
						pos += n.width;
						break;
				}
				return pos;
			}
			return 0;
		}
		getLowestNoteY(requestedPosition) {
			return this.maxStringNote ? this.getNoteY(this.maxStringNote, requestedPosition) : 0;
		}
		getHighestNoteY(requestedPosition) {
			return this.minStringNote ? this.getNoteY(this.minStringNote, requestedPosition) : 0;
		}
		getNoteY(note, requestedPosition) {
			if (this.notesPerString.has(note.string)) {
				const n = this.notesPerString.get(note.string);
				let pos = this.y + n.y;
				switch (requestedPosition) {
					case NoteYPosition.Top:
						pos -= n.height / 2;
						break;
					case NoteYPosition.StemUp:
						pos = this.y + n.getBoundingBoxTop();
						break;
					case NoteYPosition.Center: break;
					case NoteYPosition.Bottom:
						pos += n.height / 2;
						break;
					case NoteYPosition.StemDown:
						pos = this.y + n.getBoundingBoxBottom();
						break;
					case NoteYPosition.TopWithStem:
						pos = -this.renderer.settings.notation.rhythmHeight;
						pos -= this.calculateTremoloHeightForStem();
						break;
					case NoteYPosition.BottomWithStem:
						pos = this.renderer.height + this.renderer.settings.notation.rhythmHeight;
						pos += this.calculateTremoloHeightForStem();
						break;
				}
				return pos;
			}
			return 0;
		}
		calculateTremoloHeightForStem() {
			const beat = this.beat;
			if (!beat.isTremolo) return 0;
			if (beat.duration <= Duration.Quarter) return 0;
			const symbol = TremoloPickingGlyph._getSymbol(beat.tremoloPicking);
			const smufl = this.renderer.smuflMetrics;
			return smufl.glyphHeights.has(symbol) ? smufl.glyphHeights.get(symbol) : 0;
		}
		doLayout() {
			let w = 0;
			if (this.beat.deadSlapped) {
				this._deadSlapped = new DeadSlappedBeatGlyph();
				this._deadSlapped.renderer = this.renderer;
				this._deadSlapped.doLayout();
				w = this._deadSlapped.width;
				this.noteStringWidth = w;
			} else {
				let noteStringWidth = 0;
				for (let i = 0, j = this._notes.length; i < j; i++) {
					const g = this._notes[i];
					g.renderer = this.renderer;
					g.doLayout();
					if (g.width > w) w = g.width;
					if (g.noteStringWidth > noteStringWidth) noteStringWidth = g.noteStringWidth;
				}
				this.noteStringWidth = noteStringWidth;
				const tabHeight = this.renderer.resources.tablatureFont.size;
				let minEffectY = NaN;
				let maxEffectY = NaN;
				let effectY = this.getNoteY(this.minStringNote, NoteYPosition.Center) + tabHeight / 2;
				const effectSpacing = this.renderer.smuflMetrics.onNoteEffectPadding;
				for (const g of this.beatEffects.values()) {
					g.y += effectY;
					g.x += this.width / 2;
					g.renderer = this.renderer;
					g.doLayout();
					effectY += g.height + effectSpacing;
					if (Number.isNaN(minEffectY) || minEffectY > effectY) minEffectY = effectY;
					if (Number.isNaN(maxEffectY) || maxEffectY < effectY) maxEffectY = effectY;
				}
				if (!Number.isNaN(minEffectY)) this.renderer.registerBeatEffectOverflows(minEffectY, maxEffectY);
			}
			this.width = w;
		}
		addNoteGlyph(noteGlyph, note) {
			this._notes.push(noteGlyph);
			this.notesPerString.set(note.string, noteGlyph);
			if (!this.minStringNote || note.string < this.minStringNote.string) this.minStringNote = note;
			if (!this.maxStringNote || note.string > this.maxStringNote.string) this.maxStringNote = note;
		}
		paint(cx, cy, canvas) {
			cx += this.x;
			cy += this.y;
			if (this.beat.deadSlapped) this._deadSlapped?.paint(cx, cy, canvas);
			else {
				const res = this.renderer.resources;
				const oldBaseLine = canvas.textBaseline;
				canvas.textBaseline = TextBaseline.Middle;
				canvas.font = this._isGrace ? res.graceFont : res.tablatureFont;
				const notes = this._notes;
				const w = this.width;
				for (const g of notes) {
					g.renderer = this.renderer;
					g.width = w;
					g.paint(cx, cy, canvas);
				}
				canvas.textBaseline = oldBaseLine;
				const _ = ElementStyleHelper.beat(canvas, BeatSubElement.GuitarTabEffects, this.beat);
				try {
					for (const g of this.beatEffects.values()) g.paint(cx, cy, canvas);
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabRestGlyph.ts
	/**
	* @internal
	*/
	var TabRestGlyph = class extends MusicFontGlyph {
		_isVisibleRest;
		constructor(x, y, isVisibleRest, duration) {
			super(x, y, 1, ScoreRestGlyph.getSymbol(duration));
			this._isVisibleRest = isVisibleRest;
		}
		doLayout() {
			super.doLayout();
		}
		paint(cx, cy, canvas) {
			if (this._isVisibleRest) {
				const _ = ElementStyleHelper.beat(canvas, BeatSubElement.GuitarTabRests, this.beat);
				try {
					super.paint(cx, cy, canvas);
				} finally {
					_?.[Symbol.dispose]?.();
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabBeatGlyph.ts
	/**
	* @internal
	*/
	var TabBeatGlyph = class extends BeatOnNoteGlyphBase {
		slash = null;
		noteNumbers = null;
		restGlyph = null;
		get effectElement() {
			return BeatSubElement.GuitarTabEffects;
		}
		getNoteX(note, requestedPosition) {
			if (this.slash) {
				let pos = this.slash.x;
				switch (requestedPosition) {
					case NoteXPosition.Left: break;
					case NoteXPosition.Center:
						pos += this.slash.width / 2;
						break;
					case NoteXPosition.Right:
						pos += this.slash.width;
						break;
				}
				return pos;
			}
			return this.noteNumbers ? this.noteNumbers.getNoteX(note, requestedPosition) : 0;
		}
		getNoteY(note, requestedPosition) {
			return this.noteNumbers ? this.noteNumbers.getNoteY(note, requestedPosition) : 0;
		}
		getRestY(requestedPosition) {
			const g = this.restGlyph;
			if (g) switch (requestedPosition) {
				case NoteYPosition.TopWithStem: return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
				case NoteYPosition.Top: return g.getBoundingBoxTop();
				case NoteYPosition.Center:
				case NoteYPosition.StemUp:
				case NoteYPosition.StemDown: return g.getBoundingBoxTop() + g.height / 2;
				case NoteYPosition.Bottom: return g.getBoundingBoxTop();
				case NoteYPosition.BottomWithStem: return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
			}
			return 0;
		}
		getLowestNoteY(requestedPosition) {
			return this.noteNumbers ? this.noteNumbers.getLowestNoteY(requestedPosition) : 0;
		}
		getHighestNoteY(requestedPosition) {
			return this.noteNumbers ? this.noteNumbers.getHighestNoteY(requestedPosition) : 0;
		}
		buildBoundingsLookup(beatBounds, cx, cy) {
			if (this.noteNumbers) this.noteNumbers.buildBoundingsLookup(beatBounds, cx + this.x, cy + this.y);
		}
		doLayout() {
			const tabRenderer = this.renderer;
			const centeredEffectGlyphs = [];
			if (!this.container.beat.isRest) {
				const isGrace = this.renderer.settings.notation.smallGraceTabNotes && this.container.beat.graceType !== GraceType.None;
				let beatEffects;
				if (this.container.beat.slashed && !this.container.beat.notes.some((x) => x.isTieDestination)) {
					const line = Math.floor((this.renderer.bar.staff.tuning.length - 1) / 2);
					const slashNoteHead = new SlashNoteHeadGlyph(0, tabRenderer.getLineY(line), this.container.beat);
					slashNoteHead.noteHeadElement = NoteSubElement.GuitarTabFretNumber;
					slashNoteHead.effectElement = BeatSubElement.GuitarTabEffects;
					this.slash = slashNoteHead;
					slashNoteHead.beat = this.container.beat;
					this.addNormal(slashNoteHead);
					beatEffects = slashNoteHead.beatEffects;
				} else {
					const tabNoteNumbers = new TabNoteChordGlyph(0, 0, isGrace);
					this.noteNumbers = tabNoteNumbers;
					tabNoteNumbers.beat = this.container.beat;
					for (const note of this.container.beat.notes) if (note.isVisible) this._createNoteGlyph(note);
					this.addNormal(tabNoteNumbers);
					beatEffects = tabNoteNumbers.beatEffects;
				}
				if (this.container.beat.isTremolo && !beatEffects.has("tremolo")) {
					const glyph = new TremoloPickingGlyph(0, 0, this.container.beat.tremoloPicking);
					glyph.offsetY = this.renderer.smuflMetrics.glyphTop.get(glyph.symbol);
					beatEffects.set("tremolo", glyph);
					centeredEffectGlyphs.push(glyph);
				}
				if (this.container.beat.dots > 0 && tabRenderer.rhythmMode !== TabRhythmMode.Hidden) {
					const y = this.getNoteY(this.container.beat.maxNote, NoteYPosition.BottomWithStem);
					for (let i = 0; i < this.container.beat.dots; i++) this.addEffect(new AugmentationDotGlyph(0, y));
				}
			} else {
				const line = Math.floor((this.renderer.bar.staff.tuning.length - 1) / 2);
				const y = tabRenderer.getLineY(line);
				const restGlyph = new TabRestGlyph(0, y, tabRenderer.showRests, this.container.beat.duration);
				this.restGlyph = restGlyph;
				restGlyph.beat = this.container.beat;
				this.addNormal(restGlyph);
				if (this.container.beat.dots > 0 && tabRenderer.showRests) for (let i = 0; i < this.container.beat.dots; i++) this.addEffect(new AugmentationDotGlyph(0, y));
			}
			if (this.isEmpty) return;
			let w = 0;
			for (let i = 0, j = this.glyphs.length; i < j; i++) {
				const g = this.glyphs[i];
				g.x = w;
				g.renderer = this.renderer;
				g.doLayout();
				w += g.width;
			}
			this.width = w;
			this.computedWidth = w;
			if (this.container.beat.isEmpty) this.onTimeX = this.width / 2;
			else if (this.restGlyph) this.onTimeX = this.restGlyph.x + this.restGlyph.width / 2;
			else if (this.noteNumbers) this.onTimeX = this.noteNumbers.x + this.noteNumbers.noteStringWidth / 2;
			else if (this.slash) this.onTimeX = this.slash.x + this.slash.width / 2;
			this.middleX = this.onTimeX;
			this.stemX = this.middleX;
			for (const g of centeredEffectGlyphs) g.x = this.onTimeX;
		}
		_createNoteGlyph(n) {
			const tr = this.renderer;
			const noteNumberGlyph = new NoteNumberGlyph(0, 0, n);
			const l = tr.getNoteLine(n);
			noteNumberGlyph.y = tr.getLineY(l);
			noteNumberGlyph.renderer = this.renderer;
			noteNumberGlyph.doLayout();
			this.noteNumbers.addNoteGlyph(noteNumberGlyph, n);
			const topY = noteNumberGlyph.getBoundingBoxTop();
			const bottomY = noteNumberGlyph.getBoundingBoxBottom();
			this.renderer.collisionHelper.reserveBeatSlot(this.container.beat, topY, bottomY);
			const minString = tr.minString;
			const maxString = tr.maxString;
			if (Number.isNaN(minString) || minString < n.string) tr.minString = l;
			if (Number.isNaN(maxString) || maxString > n.string) tr.maxString = l;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabBrushGlyph.ts
	/**
	* @internal
	*/
	var TabBrushGlyph = class extends Glyph {
		_beat;
		_noteVibratoGlyph;
		constructor(beat) {
			super(0, 0);
			this._beat = beat;
		}
		doLayout() {
			this.width = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.ArrowheadBlackDown);
			if (this._beat.brushType === BrushType.ArpeggioUp) {
				const glyph = new NoteVibratoGlyph(0, 0, VibratoType.Slight, true);
				glyph.renderer = this.renderer;
				glyph.doLayout();
				this._noteVibratoGlyph = glyph;
			} else if (this._beat.brushType === BrushType.ArpeggioDown) {
				const glyph = new NoteVibratoGlyph(0, 0, VibratoType.Slight, true);
				glyph.renderer = this.renderer;
				glyph.doLayout();
				this._noteVibratoGlyph = glyph;
			}
		}
		paint(cx, cy, canvas) {
			const tabBarRenderer = this.renderer;
			const startY = cy + this.x + tabBarRenderer.getNoteY(this._beat.maxStringNote, NoteYPosition.Top);
			const endY = cy + this.y + tabBarRenderer.getNoteY(this._beat.minStringNote, NoteYPosition.Bottom);
			const arrowX = cx + this.x + this.width / 2;
			const arrowSize = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.ArrowheadBlackDown);
			if (this._beat.brushType !== BrushType.None) {
				if (this._beat.brushType === BrushType.BrushUp || this._beat.brushType === BrushType.BrushDown) {
					canvas.beginPath();
					canvas.moveTo(arrowX, startY);
					canvas.lineTo(arrowX, endY);
					canvas.stroke();
				} else if (this._beat.brushType === BrushType.ArpeggioUp) {
					const glyph = this._noteVibratoGlyph;
					const lineStartY = startY;
					const lineEndY = endY - arrowSize;
					glyph.width = Math.abs(lineEndY - lineStartY);
					canvas.beginRotate(cx + this.x, lineEndY, -90);
					glyph.paint(0, (this.width - glyph.height) / 2, canvas);
					canvas.endRotate();
				} else if (this._beat.brushType === BrushType.ArpeggioDown) {
					const glyph = this._noteVibratoGlyph;
					const lineStartY = startY + arrowSize;
					glyph.width = Math.abs(endY - lineStartY);
					canvas.beginRotate(cx + this.x, lineStartY, 90);
					glyph.paint(0, -(this.width - glyph.height / 2), canvas);
					canvas.endRotate();
				}
				if (this._beat.brushType === BrushType.BrushUp || this._beat.brushType === BrushType.ArpeggioUp) {
					canvas.beginPath();
					canvas.moveTo(arrowX, endY);
					canvas.lineTo(arrowX + arrowSize / 2, endY - arrowSize);
					canvas.lineTo(arrowX - arrowSize / 2, endY - arrowSize);
					canvas.closePath();
					canvas.fill();
				} else {
					canvas.beginPath();
					canvas.moveTo(arrowX, startY);
					canvas.lineTo(arrowX + arrowSize / 2, startY + arrowSize);
					canvas.lineTo(arrowX - arrowSize / 2, startY + arrowSize);
					canvas.closePath();
					canvas.fill();
				}
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabBeatPreNotesGlyph.ts
	/**
	* @internal
	*/
	var TabBeatPreNotesGlyph = class extends BeatGlyphBase {
		doLayout() {
			if (this.container.beat.brushType !== BrushType.None && !this.container.beat.isRest) {
				this.addEffect(new TabBrushGlyph(this.container.beat));
				this.addNormal(new SpacingGlyph(0, 0, this.renderer.smuflMetrics.preNoteEffectPadding));
			}
			super.doLayout();
		}
		get effectElement() {
			return BeatSubElement.GuitarTabEffects;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabSlideLineGlyph.ts
	/**
	* @internal
	*/
	var TabSlideLineGlyph = class extends Glyph {
		_inType;
		_outType;
		_startNote;
		_parent;
		checkForOverflow = false;
		constructor(inType, outType, startNote, parent) {
			super(0, 0);
			this._inType = inType;
			this._outType = outType;
			this._startNote = startNote;
			this._parent = parent;
		}
		doLayout() {
			this.width = 0;
		}
		paint(cx, cy, canvas) {
			this._paintSlideIn(cx, cy, canvas);
			this._paintSlideOut(cx, cy, canvas);
		}
		_paintSlideIn(cx, cy, canvas) {
			const startNoteRenderer = this.renderer;
			const sizeX = this.renderer.smuflMetrics.simpleSlideWidth;
			const sizeY = this.renderer.smuflMetrics.simpleSlideHeight;
			let startX = 0;
			let startY = 0;
			let endX = 0;
			let endY = 0;
			const offsetX = this.renderer.smuflMetrics.preNoteEffectPadding;
			switch (this._inType) {
				case SlideInType.IntoFromBelow:
					endX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Left) - offsetX;
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) - sizeY;
					startX = endX - sizeX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) + sizeY;
					break;
				case SlideInType.IntoFromAbove:
					endX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Left) - offsetX;
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) + sizeY;
					startX = endX - sizeX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) - sizeY;
					break;
				default: return;
			}
			this._paintSlideLine(canvas, false, startX, endX, startY, endY);
		}
		_paintSlideOut(cx, cy, canvas) {
			const startNoteRenderer = this.renderer;
			const sizeX = this.renderer.smuflMetrics.simpleSlideWidth;
			const sizeY = this.renderer.smuflMetrics.simpleSlideHeight;
			let startX = 0;
			let startY = 0;
			let endX = 0;
			let endY = 0;
			let waves = false;
			const offsetX = this.renderer.smuflMetrics.postNoteEffectPadding;
			switch (this._outType) {
				case SlideOutType.Shift:
				case SlideOutType.Legato:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(this._startNote.beat, BeatXPosition.PostNotes) + offsetX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					if (this._startNote.slideTarget) {
						const endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this._startNote.slideTarget.beat.voice.bar);
						if (!endNoteRenderer || endNoteRenderer.staff !== startNoteRenderer.staff) {
							endX = cx + startNoteRenderer.x + startNoteRenderer.width;
							endY = startY;
						} else {
							endX = cx + endNoteRenderer.x + endNoteRenderer.getBeatX(this._startNote.slideTarget.beat, BeatXPosition.OnNotes) - offsetX;
							endY = cy + endNoteRenderer.y + endNoteRenderer.getNoteY(this._startNote.slideTarget, NoteYPosition.Center);
						}
						if (this._startNote.slideTarget.fret > this._startNote.fret) {
							startY += sizeY;
							endY -= sizeY;
						} else {
							startY -= sizeY;
							endY += sizeY;
						}
					} else {
						endX = cx + startNoteRenderer.x + this._parent.x;
						endY = startY;
					}
					break;
				case SlideOutType.OutUp:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) + sizeY;
					endX = startX + sizeX;
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) - sizeY;
					break;
				case SlideOutType.OutDown:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) - sizeY;
					endX = startX + sizeX;
					endY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center) + sizeY;
					break;
				case SlideOutType.PickSlideDown:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX * 2;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					endX = cx + startNoteRenderer.x + startNoteRenderer.width;
					endY = startY + sizeY * 3;
					if (this._startNote.beat.nextBeat && this._startNote.beat.nextBeat.voice === this._startNote.beat.voice) endX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(this._startNote.beat.nextBeat, BeatXPosition.PreNotes);
					waves = true;
					break;
				case SlideOutType.PickSlideUp:
					startX = cx + startNoteRenderer.x + startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right) + offsetX * 2;
					startY = cy + startNoteRenderer.y + startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Center);
					endX = cx + startNoteRenderer.x + startNoteRenderer.width;
					endY = startY - sizeY * 3;
					if (this._startNote.beat.nextBeat && this._startNote.beat.nextBeat.voice === this._startNote.beat.voice) endX = cx + startNoteRenderer.x + startNoteRenderer.getBeatX(this._startNote.beat.nextBeat, BeatXPosition.PreNotes);
					waves = true;
					break;
				default: return;
			}
			this._paintSlideLine(canvas, waves, startX, endX, startY, endY);
		}
		_paintSlideLine(canvas, waves, startX, endX, startY, endY) {
			if (waves) {
				const glyph = new NoteVibratoGlyph(0, 0, VibratoType.Slight);
				glyph.renderer = this.renderer;
				glyph.doLayout();
				startY -= glyph.height / 2;
				endY -= glyph.height / 2;
				const b = endX - startX;
				const a = endY - startY;
				const c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
				glyph.width = b;
				const angle = Math.asin(a / c) * (180 / Math.PI);
				canvas.beginRotate(startX, startY, angle);
				glyph.paint(0, 0, canvas);
				canvas.endRotate();
			} else {
				canvas.beginPath();
				canvas.moveTo(startX, startY);
				canvas.lineTo(endX, endY);
				canvas.stroke();
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabBeatContainerGlyph.ts
	/**
	* @internal
	*/
	var TabBeatContainerGlyph = class extends BeatContainerGlyph {
		_bend = null;
		_effectSlurs = [];
		constructor(beat) {
			super(beat);
			this.preNotes = new TabBeatPreNotesGlyph();
			this.onNotes = new TabBeatGlyph();
		}
		drawBeamHelperAsFlags(helper) {
			return helper.hasFlag(this.renderer.drawBeamHelperAsFlags(helper), this.beat);
		}
		doLayout() {
			this._effectSlurs = [];
			super.doLayout();
			if (this._bend) {
				this._bend.renderer = this.renderer;
				this._bend.doLayout();
				this.updateWidth();
			}
		}
		createTies(n) {
			if (!n.isVisible) return;
			const renderer = this.renderer;
			if (n.isTieOrigin && renderer.showTiedNotes && n.tieDestination.isVisible) {
				const tie = new TabTieGlyph(`tab.tie.${n.id}`, n, n.tieDestination, false);
				this.addTie(tie);
			}
			if (n.isTieDestination && renderer.showTiedNotes) {
				const tie = new TabTieGlyph(`tab.tie.${n.tieOrigin.id}`, n.tieOrigin, n, true);
				this.addTie(tie);
			}
			if (n.isLeftHandTapped && !n.isHammerPullDestination) {
				const tapSlur = new TabTieGlyph(`tab.tie.leftHandTap.${n.id}`, n, n, false);
				this.addTie(tapSlur);
			}
			if (n.isEffectSlurOrigin && n.effectSlurDestination) {
				let expanded = false;
				for (const slur of this._effectSlurs) if (slur.tryExpand(n, n.effectSlurDestination, false, false)) {
					expanded = true;
					break;
				}
				if (!expanded) {
					const effectSlur = new TabSlurGlyph(`tab.slur.effect.${n.id}`, n, n.effectSlurDestination, false, false);
					this._effectSlurs.push(effectSlur);
					this.addTie(effectSlur);
				}
			}
			if (n.isEffectSlurDestination && n.effectSlurOrigin) {
				let expanded = false;
				for (const slur of this._effectSlurs) if (slur.tryExpand(n.effectSlurOrigin, n, false, true)) {
					expanded = true;
					break;
				}
				if (!expanded) {
					const effectSlur = new TabSlurGlyph(`tab.slur.effect.${n.effectSlurOrigin.id}`, n.effectSlurOrigin, n, false, true);
					this._effectSlurs.push(effectSlur);
					this.addTie(effectSlur);
				}
			}
			if (n.slideInType !== SlideInType.None || n.slideOutType !== SlideOutType.None) {
				const l = new TabSlideLineGlyph(n.slideInType, n.slideOutType, n, this);
				this.addTie(l);
			}
			if (n.hasBend) {
				if (!this._bend) {
					const bend = new TabBendGlyph();
					this._bend = bend;
					bend.renderer = this.renderer;
					this.addTie(bend);
				}
				this._bend.addBends(n);
			}
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabClefGlyph.ts
	/**
	* @internal
	*/
	var TabClefGlyph = class extends MusicFontGlyph {
		constructor(x, y) {
			super(x, y, 1, MusicFontSymbol.SixStringTabClef);
		}
		doLayout() {
			this.symbol = this.renderer.bar.staff.tuning.length <= 4 ? MusicFontSymbol.FourStringTabClef : MusicFontSymbol.SixStringTabClef;
			this.center = true;
			super.doLayout();
			this.width = this.renderer.smuflMetrics.glyphWidths.get(MusicFontSymbol.GClef);
			this.offsetX = this.width / 2;
		}
	};
	//#endregion
	//#region src/rendering/glyphs/TabTimeSignatureGlyph.ts
	/**
	* @internal
	*/
	var TabTimeSignatureGlyph = class extends TimeSignatureGlyph {
		doLayout() {
			this.barSubElement = BarSubElement.GuitarTabsTimeSignature;
			super.doLayout();
		}
		get commonScale() {
			return 1;
		}
		get numberScale() {
			if (this.renderer.bar.staff.tuning.length <= 4) return EngravingSettings.GraceScale;
			return 1;
		}
	};
	//#endregion
	//#region src/rendering/TabBarRenderer.ts
	/**
	* This BarRenderer renders a bar using guitar tablature notation
	* @internal
	*/
	var TabBarRenderer = class extends LineBarRenderer {
		static StaffId = "tab";
		_hasTuplets = false;
		showTimeSignature = false;
		showRests = false;
		showTiedNotes = false;
		_showMultiBarRest = false;
		get showMultiBarRest() {
			return this._showMultiBarRest;
		}
		get repeatsBarSubElement() {
			return BarSubElement.GuitarTabsRepeats;
		}
		get barNumberBarSubElement() {
			return BarSubElement.GuitarTabsBarNumber;
		}
		get barLineBarSubElement() {
			return BarSubElement.GuitarTabsBarLines;
		}
		get staffLineBarSubElement() {
			return BarSubElement.GuitarTabsStaffLine;
		}
		get lineSpacing() {
			return this.smuflMetrics.tabLineSpacing;
		}
		get heightLineCount() {
			return this.bar.staff.tuning.length;
		}
		get drawnLineCount() {
			return this.bar.staff.tuning.length;
		}
		get rhythmMode() {
			let mode = this.settings.notation.rhythmMode;
			if (mode === TabRhythmMode.Automatic) mode = this.bar.staff.showStandardNotation ? TabRhythmMode.Hidden : TabRhythmMode.ShowWithBars;
			return mode;
		}
		getNoteLine(note) {
			return this.bar.staff.tuning.length - note.string;
		}
		minString = NaN;
		maxString = NaN;
		collectSpaces(spaces) {
			if (this.additionalMultiRestBars) return;
			const padding = this.smuflMetrics.staffLineThickness;
			const tuning = this.bar.staff.tuning;
			for (const voice of this.voiceContainer.beatGlyphs.values()) for (const bg of voice) {
				const notes = bg.onNotes;
				const noteNumbers = notes.noteNumbers;
				if (noteNumbers) {
					for (const [str, noteNumber] of noteNumbers.notesPerString) if (!noteNumber.isEmpty) spaces[tuning.length - str].push(new Float32Array([this.beatGlyphsStart + bg.x + notes.x + noteNumbers.x - padding, noteNumbers.width + padding * 2]));
				}
			}
		}
		doLayout() {
			if (!(this.bar.staff.showStandardNotation && this.scoreRenderer.layout.profile.has(ScoreBarRenderer.StaffId))) {
				this.showTimeSignature = true;
				this.showRests = true;
				this.showTiedNotes = true;
				this._showMultiBarRest = true;
			}
			super.doLayout();
			if (this.minString === 0) this.registerOverflowTop(this.lineSpacing / 2);
			if (this.maxString === this.bar.staff.tuning.length - 1) this.registerOverflowBottom(this.lineSpacing / 2);
			if (this.rhythmMode !== TabRhythmMode.Hidden) {
				this._hasTuplets = this.voiceContainer.tupletGroups.size > 0;
				if (this._hasTuplets) this.registerOverflowBottom(this.settings.notation.rhythmHeight + this.tupletSize);
			}
		}
		createLinePreBeatGlyphs() {
			if (this.isFirstOfStaff) {
				const center = (this.bar.staff.tuning.length - 1) / 2;
				this.createStartSpacing();
				this.addPreBeatGlyph(new TabClefGlyph(0, this.getLineY(center)));
			}
			if (this.showTimeSignature && (!this.bar.previousBar || this.bar.previousBar && this.bar.masterBar.timeSignatureNumerator !== this.bar.previousBar.masterBar.timeSignatureNumerator || this.bar.previousBar && this.bar.masterBar.timeSignatureDenominator !== this.bar.previousBar.masterBar.timeSignatureDenominator || this.bar.previousBar && this.bar.masterBar.isFreeTime && this.bar.masterBar.isFreeTime !== this.bar.previousBar.masterBar.isFreeTime)) {
				this.createStartSpacing();
				this._createTimeSignatureGlyphs();
			}
		}
		_createTimeSignatureGlyphs() {
			this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.oneStaffSpace));
			const lines = (this.bar.staff.tuning.length + 1) / 2 - 1;
			this.addPreBeatGlyph(new TabTimeSignatureGlyph(0, this.getLineY(lines), this.bar.masterBar.timeSignatureNumerator, this.bar.masterBar.timeSignatureDenominator, this.bar.masterBar.timeSignatureCommon, this.bar.masterBar.isFreeTime));
		}
		createVoiceGlyphs(v) {
			super.createVoiceGlyphs(v);
			for (const b of v.beats) this.addBeatGlyph(new TabBeatContainerGlyph(b));
		}
		get flagsSubElement() {
			return BeatSubElement.GuitarTabFlags;
		}
		get beamsSubElement() {
			return BeatSubElement.GuitarTabBeams;
		}
		get tupletSubElement() {
			return BeatSubElement.GuitarTabTuplet;
		}
		paintBeams(cx, cy, canvas, flagsElement, beamsElement) {
			if (this.rhythmMode !== TabRhythmMode.Hidden) super.paintBeams(cx, cy, canvas, flagsElement, beamsElement);
		}
		paintTuplets(cx, cy, canvas, beatElement, bracketsAsArcs = false) {
			if (this.rhythmMode !== TabRhythmMode.Hidden) super.paintTuplets(cx, cy, canvas, beatElement, bracketsAsArcs);
		}
		drawBeamHelperAsFlags(h) {
			return super.drawBeamHelperAsFlags(h) || this.rhythmMode === TabRhythmMode.ShowWithBeams;
		}
		getFlagTopY(beat, direction) {
			const maxNote = beat.maxStringNote;
			const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
			if (maxNote) return this.getNoteY(maxNote, position);
			else return this.getRestY(beat, position);
		}
		getFlagBottomY(beat, direction) {
			const maxNote = beat.minStringNote;
			const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
			if (maxNote) return this.getNoteY(maxNote, position);
			else return this.getRestY(beat, position);
		}
		getBeamDirection(_helper) {
			return BeamDirection.Down;
		}
		shouldPaintFlag(beat) {
			if (!super.shouldPaintFlag(beat)) return false;
			if (beat.graceType !== GraceType.None) return false;
			return true;
		}
		paintBeamingStem(beat, cy, x, topY, bottomY, canvas) {
			if (bottomY < topY) {
				const t = bottomY;
				bottomY = topY;
				topY = t;
			}
			const _ = ElementStyleHelper.beat(canvas, BeatSubElement.GuitarTabStem, beat);
			try {
				let holes = [];
				if (this.helpers.collisionHelper.reservedLayoutAreasByDisplayTime.has(beat.displayStart)) {
					holes = this.helpers.collisionHelper.reservedLayoutAreasByDisplayTime.get(beat.displayStart).slots.slice();
					holes.sort((a, b) => a.topY - b.topY);
				}
				if (holes.length === 1) {
					canvas.fillRect(x, topY, this.smuflMetrics.stemThickness, bottomY - topY);
					return;
				}
				const bottomYRelative = bottomY - cy;
				const bottomHole = holes[holes.length - 1];
				canvas.fillRect(x, cy + bottomHole.bottomY, this.smuflMetrics.stemThickness, bottomYRelative - bottomHole.bottomY);
				for (let i = holes.length - 1; i > 0; i--) {
					const bottomHoleY = holes[i].topY;
					const topHoleY = holes[i - 1].bottomY;
					if (topHoleY < bottomHoleY) canvas.fillRect(x, cy + topHoleY, this.smuflMetrics.stemThickness, bottomHoleY - topHoleY);
				}
			} finally {
				_?.[Symbol.dispose]?.();
			}
		}
		calculateOverflows(rendererTop, rendererBottom) {
			super.calculateOverflows(rendererTop, rendererBottom);
			if (this.bar.isEmpty) return;
			if (this.rhythmMode !== TabRhythmMode.Hidden) this.calculateBeamingOverflows(rendererTop, rendererBottom);
		}
	};
	//#endregion
	//#region src/rendering/TabBarRendererFactory.ts
	/**
	* This Factory produces TabBarRenderer instances
	* @internal
	*/
	var TabBarRendererFactory = class extends BarRendererFactory {
		get staffId() {
			return TabBarRenderer.StaffId;
		}
		constructor(effectBands) {
			super(effectBands);
			this.hideOnPercussionTrack = true;
		}
		canCreate(track, staff) {
			return staff.showTablature && staff.tuning.length > 0 && super.canCreate(track, staff);
		}
		create(renderer, bar) {
			return new TabBarRenderer(renderer, bar);
		}
	};
	//#endregion
	//#region src/Environment.ts
	/**
	* A factory for custom layout engines.
	* @internal
	*/
	var LayoutEngineFactory = class {
		/**
		* Whether the layout is considered "vertical" (affects mainly scrolling behavior).
		*/
		vertical;
		/**
		* Creates a new layout instance.
		*/
		createLayout;
		constructor(vertical, createLayout) {
			this.vertical = vertical;
			this.createLayout = createLayout;
		}
	};
	/**
	* A factory for custom render engines.
	* Note for Web: To use a custom engine in workers you have to ensure the engine and registration to the environment are
	* also done in the background worker files (e.g. when bundling)
	* @public
	*/
	var RenderEngineFactory = class {
		/**
		* Whether the layout supports background workers.
		*/
		supportsWorkers;
		createCanvas;
		constructor(supportsWorkers, canvas) {
			this.supportsWorkers = supportsWorkers;
			this.createCanvas = canvas;
		}
	};
	/**
	* This public class represents the global alphaTab environment where
	* alphaTab looks for information like available layout engines
	* staves etc.
	* This public class represents the global alphaTab environment where
	* alphaTab looks for information like available layout engines
	* staves etc.
	* @partial
	* @public
	*/
	var Environment = class Environment {
		/**
		* The scaling factor to use when rending raster graphics for sharper rendering on high-dpi displays.
		* @internal
		*/
		static highDpiFactor = 1;
		/**
		* @target web
		*/
		static _globalThis = void 0;
		/**
		* @target web
		* @internal
		*/
		static get globalThis() {
			if (Environment._globalThis === void 0) {
				try {
					Environment._globalThis = globalThis;
				} catch {}
				if (typeof Environment._globalThis === "undefined") Environment._globalThis = self;
				if (typeof Environment._globalThis === "undefined") Environment._globalThis = global;
				if (typeof Environment._globalThis === "undefined") Environment._globalThis = window;
				if (typeof Environment._globalThis === "undefined") Environment._globalThis = Function("return this")();
			}
			return Environment._globalThis;
		}
		/**
		* @target web
		* @internal
		* @partial
		*/
		static getGlobalWorkerScope() {
			return Environment.globalThis;
		}
		/**
		* @target web
		*/
		static webPlatform = Environment._detectWebPlatform();
		/**
		* @target web
		*/
		static isWebPackBundled = Environment._detectWebPack();
		/**
		* @target web
		*/
		static isViteBundled = Environment._detectVite();
		/**
		* @target web
		*/
		static scriptFile = Environment._detectScriptFile();
		/**
		* @target web
		*/
		static fontDirectory = Environment._detectFontDirectory();
		/**
		* @target web
		*/
		static get isRunningInWorker() {
			return "WorkerGlobalScope" in Environment.globalThis;
		}
		/**
		* @target web
		*/
		static get isRunningInAudioWorklet() {
			return "AudioWorkletGlobalScope" in Environment.globalThis;
		}
		/**
		* @target web
		*/
		static _detectScriptFile() {
			if (!Environment.isRunningInWorker && Environment.globalThis.ALPHATAB_ROOT) {
				let scriptFile = Environment.globalThis.ALPHATAB_ROOT;
				scriptFile = Environment.ensureFullUrl(scriptFile);
				scriptFile = Environment._appendScriptName(scriptFile);
				return scriptFile;
			}
			try {
				const importUrl = {}.url;
				if (importUrl && importUrl.indexOf("file://") === -1) return importUrl;
			} catch {}
			if ("document" in Environment.globalThis && document.currentScript && document.currentScript instanceof HTMLScriptElement) return document.currentScript.src;
			return null;
		}
		/**
		* @target web
		* @internal
		*/
		static ensureFullUrl(relativeUrl) {
			if (!relativeUrl) return "";
			if (!relativeUrl.startsWith("http") && !relativeUrl.startsWith("https") && !relativeUrl.startsWith("file")) {
				let root = "";
				const location = Environment.globalThis.location;
				root += location.protocol?.toString();
				root += "//".toString();
				if (location.hostname) root += location.hostname?.toString();
				if (location.port) {
					root += ":".toString();
					root += location.port?.toString();
				}
				if (!relativeUrl.startsWith("/")) {
					const directory = location.pathname.split("/").slice(0, -1).join("/");
					if (directory.length > 0) {
						if (!directory.startsWith("/")) root += "/".toString();
						root += directory?.toString();
					}
				}
				if (!relativeUrl.startsWith("/")) root += "/".toString();
				root += relativeUrl?.toString();
				return root;
			}
			return relativeUrl;
		}
		static _appendScriptName(url) {
			if (url && !url.endsWith(".js")) {
				if (!url.endsWith("/")) url += "/";
				url += "alphaTab.js";
			}
			return url;
		}
		/**
		* @target web
		*/
		static _detectFontDirectory() {
			if (!Environment.isRunningInWorker && Environment.globalThis.ALPHATAB_FONT) return Environment.ensureFullUrl(Environment.globalThis.ALPHATAB_FONT);
			const scriptFile = Environment.scriptFile;
			if (scriptFile) {
				const lastSlash = scriptFile.lastIndexOf(String.fromCharCode(47));
				if (lastSlash >= 0) return `${scriptFile.substr(0, lastSlash)}/font/`;
			}
			return null;
		}
		/**
		* @target web
		*/
		static _registerJQueryPlugin() {
			if (!Environment.isRunningInWorker && Environment.globalThis && "jQuery" in Environment.globalThis) {
				const jquery = Environment.globalThis.jQuery;
				const api = new JQueryAlphaTab();
				jquery.fn.alphaTab = function(method) {
					const args = Array.prototype.slice.call(arguments, 1);
					if (this.length === 1) return api.exec(this[0], method, args);
					return this.each((_i, e) => {
						api.exec(e, method, args);
					});
				};
				jquery.alphaTab = { restore: JQueryAlphaTab.restore };
				jquery.fn.alphaTab.fn = api;
			}
		}
		static renderEngines = Environment._createDefaultRenderEngines();
		/**
		* @internal
		*/
		static layoutEngines = Environment._createDefaultLayoutEngines();
		/**
		* @internal
		*/
		static staveProfiles = Environment._createDefaultStaveProfiles();
		static getRenderEngineFactory(engine) {
			if (!engine || !Environment.renderEngines.has(engine)) return Environment.renderEngines.get("default");
			return Environment.renderEngines.get(engine);
		}
		/**
		* @internal
		*/
		static getLayoutEngineFactory(layoutMode) {
			if (!layoutMode || !Environment.layoutEngines.has(layoutMode)) return Environment.layoutEngines.get(LayoutMode.Page);
			return Environment.layoutEngines.get(layoutMode);
		}
		/**
		* Gets all default ScoreImporters
		* @returns
		*/
		static buildImporters() {
			return [
				new Gp3To5Importer(),
				new GpxImporter(),
				new Gp7To8Importer(),
				new MusicXmlImporter(),
				new CapellaImporter(),
				new AlphaTexImporter()
			];
		}
		static _createDefaultRenderEngines() {
			const renderEngines = /* @__PURE__ */ new Map();
			renderEngines.set("svg", new RenderEngineFactory(true, () => {
				return new CssFontSvgCanvas();
			}));
			renderEngines.set("default", renderEngines.get("svg"));
			renderEngines.set("skia", new RenderEngineFactory(true, () => {
				return new SkiaCanvas();
			}));
			Environment._createPlatformSpecificRenderEngines(renderEngines);
			return renderEngines;
		}
		/**
		* Enables the usage of alphaSkia as rendering backend.
		* @param musicFontData The raw binary data of the music font.
		* @param alphaSkia The alphaSkia module.
		*/
		static enableAlphaSkia(musicFontData, alphaSkia) {
			SkiaCanvas.enable(musicFontData, alphaSkia);
		}
		/**
		* Registers a new custom font for the usage in the alphaSkia rendering backend.
		* @param fontData The raw binary data of the font.
		* @returns The font info under which the font was registered.
		*/
		static registerAlphaSkiaCustomFont(fontData) {
			return SkiaCanvas.registerFont(fontData);
		}
		/**
		* @target web
		* @partial
		*/
		static _createPlatformSpecificRenderEngines(renderEngines) {
			renderEngines.set("html5", new RenderEngineFactory(false, () => {
				return new Html5Canvas();
			}));
		}
		/**
		* @internal
		*/
		static defaultRenderers = [
			new SlashBarRendererFactory([
				{
					effect: new TempoEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new TripletFeelEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new MarkerEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new DirectionsEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new FreeTimeEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new TextEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new BeatTimerEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new ChordsEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new AlternateEndingsEffectInfo(),
					mode: EffectBandMode.SharedTop,
					order: 1e3
				}
			]),
			new ScoreBarRendererFactory([
				{
					effect: new CapoEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new FermataEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new BeatBarreEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new NoteOrnamentEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new RasgueadoEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new WahPedalEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new WhammyBarEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new SimpleDipWhammyBarEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new TrillEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new OttaviaEffectInfo(true),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new LeftHandTapEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new TapEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new WideBeatVibratoEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new SlightBeatVibratoEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new WideNoteVibratoEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new SlightNoteVibratoEffectInfo(false),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new FadeEffectInfo(),
					mode: EffectBandMode.OwnedTop,
					shouldCreate: (staff) => !staff.showTablature
				},
				{
					effect: new LetRingEffectInfo(),
					mode: EffectBandMode.OwnedTop,
					shouldCreate: (staff) => !staff.showTablature
				},
				{
					effect: new PickStrokeEffectInfo(),
					mode: EffectBandMode.OwnedTop,
					shouldCreate: (staff) => !staff.showTablature
				},
				{
					effect: new PickSlideEffectInfo(),
					mode: EffectBandMode.OwnedTop,
					shouldCreate: (staff) => !staff.showTablature
				},
				{
					effect: new GolpeEffectInfo(GolpeType.Finger),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new GolpeEffectInfo(GolpeType.Thumb),
					mode: EffectBandMode.OwnedBottom
				},
				{
					effect: new CrescendoEffectInfo(),
					mode: EffectBandMode.SharedBottom
				},
				{
					effect: new DynamicsEffectInfo(),
					mode: EffectBandMode.SharedBottom
				},
				{
					effect: new SustainPedalEffectInfo(),
					mode: EffectBandMode.SharedBottom
				}
			]),
			new NumberedBarRendererFactory([{
				effect: new NumberedBarKeySignatureEffectInfo(),
				mode: EffectBandMode.OwnedTop,
				order: 1e3
			}]),
			new TabBarRendererFactory([
				{
					effect: new LyricsEffectInfo(),
					mode: EffectBandMode.SharedTop
				},
				{
					effect: new TabWhammyEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new TrillEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new WideBeatVibratoEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new SlightBeatVibratoEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new WideNoteVibratoEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new SlightNoteVibratoEffectInfo(true),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new TapEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new FadeEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new HarmonicsEffectInfo(HarmonicType.Natural),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new HarmonicsEffectInfo(HarmonicType.Artificial),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new HarmonicsEffectInfo(HarmonicType.Pinch),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new HarmonicsEffectInfo(HarmonicType.Tap),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new HarmonicsEffectInfo(HarmonicType.Semi),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new HarmonicsEffectInfo(HarmonicType.Feedback),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new LetRingEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new FingeringEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new PalmMuteEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new PickStrokeEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new PickSlideEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new LeftHandTapEffectInfo(),
					mode: EffectBandMode.OwnedTop
				},
				{
					effect: new GolpeEffectInfo(GolpeType.Finger),
					mode: EffectBandMode.OwnedTop,
					shouldCreate: (staff) => !staff.showStandardNotation
				},
				{
					effect: new GolpeEffectInfo(GolpeType.Thumb),
					mode: EffectBandMode.OwnedBottom,
					shouldCreate: (staff) => !staff.showStandardNotation
				}
			])
		];
		static _createDefaultStaveProfiles() {
			const staveProfiles = /* @__PURE__ */ new Map();
			staveProfiles.set(StaveProfile.Default, new Set([
				SlashBarRenderer.StaffId,
				ScoreBarRenderer.StaffId,
				NumberedBarRenderer.StaffId,
				TabBarRenderer.StaffId
			]));
			staveProfiles.set(StaveProfile.ScoreTab, new Set([
				SlashBarRenderer.StaffId,
				ScoreBarRenderer.StaffId,
				NumberedBarRenderer.StaffId,
				TabBarRenderer.StaffId
			]));
			staveProfiles.set(StaveProfile.Score, new Set([ScoreBarRenderer.StaffId]));
			staveProfiles.set(StaveProfile.Tab, new Set([TabBarRenderer.StaffId]));
			staveProfiles.set(StaveProfile.TabMixed, new Set([TabBarRenderer.StaffId]));
			return staveProfiles;
		}
		static _createDefaultLayoutEngines() {
			const engines = /* @__PURE__ */ new Map();
			engines.set(LayoutMode.Page, new LayoutEngineFactory(true, (r) => {
				return new PageViewLayout(r);
			}));
			engines.set(LayoutMode.Horizontal, new LayoutEngineFactory(false, (r) => {
				return new HorizontalScreenLayout(r);
			}));
			engines.set(LayoutMode.Parchment, new LayoutEngineFactory(true, (r) => {
				return new ParchmentLayout(r);
			}));
			return engines;
		}
		/**
		* @target web
		*/
		static initializeMain(createWebWorker, createAudioWorklet) {
			if (Environment.isRunningInWorker || Environment.isRunningInAudioWorklet) return;
			if (Environment.webPlatform === WebPlatform.Browser || Environment.webPlatform === WebPlatform.BrowserModule) {
				Environment._registerJQueryPlugin();
				Environment.highDpiFactor = window.devicePixelRatio;
			}
			BrowserUiFacade.createAlphaTabWebWorker = (s) => createWebWorker(s, "alphaTab Renderer");
			BrowserUiFacade.createAlphaSynthWebWorker = (s) => createWebWorker(s, "alphaSynth Worker");
			BrowserUiFacade.createAlphaSynthAudioWorklet = createAudioWorklet;
		}
		/**
		* @target web
		* @internal
		*/
		static get alphaTabWorker() {
			return Environment.globalThis.Worker;
		}
		/**
		* @target web
		* @internal
		*/
		static get alphaTabUrl() {
			return Environment.globalThis.URL;
		}
		/**
		* @target web
		*/
		static initializeWorker() {
			if (!Environment.isRunningInWorker) throw new AlphaTabError(AlphaTabErrorType.General, "Not running in worker, cannot run worker initialization");
			AlphaTabWebWorker.init();
			AlphaSynthWebWorker.init();
		}
		/**
		* @target web
		*/
		static initializeAudioWorklet() {
			if (!Environment.isRunningInAudioWorklet) throw new AlphaTabError(AlphaTabErrorType.General, "Not running in audio worklet, cannot run worklet initialization");
			AlphaSynthWebWorklet.init();
		}
		/**
		* @target web
		*/
		static _detectWebPack() {
			try {
				if (typeof __webpack_require__ === "function") {
					if (typeof __ALPHATAB_WEBPACK__ !== "boolean") Logger.warning("WebPack", `Detected bundling with WebPack but @coderline/alphatab-webpack was not used! To ensure alphaTab works as expected use our bundler plugins. Learn more at https://www.alphatab.net/docs/getting-started/installation-webpack`);
					return true;
				}
			} catch {}
			return false;
		}
		/**
		* @target web
		*/
		static _detectVite() {
			try {
				if (typeof __BASE__ === "string") {
					if (typeof __ALPHATAB_VITE__ !== "boolean") Logger.warning("Vite", `Detected bundling with Vite but @coderline/alphatab-vite was not used! To ensure alphaTab works as expected use our bundler plugins. Learn more at https://www.alphatab.net/docs/getting-started/installation-vite`);
					return true;
				}
			} catch {}
			return false;
		}
		/**
		* @target web
		*/
		static _detectWebPlatform() {
			if (!(typeof Environment.globalThis.Window !== "undefined" && Environment.globalThis instanceof Environment.globalThis.Window)) try {
				if (Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]") return WebPlatform.NodeJs;
			} catch {}
			try {
				const url = {}.url;
				if (url && typeof url === "string" && !url.startsWith("file://")) return WebPlatform.BrowserModule;
			} catch {}
			return WebPlatform.Browser;
		}
		/**
		* Prints the environment information for easier troubleshooting.
		* @param force Whether to force printing.
		*/
		static printEnvironmentInfo(force = true) {
			const printer = force ? (message) => {
				Logger.log.debug("VersionInfo", message);
			} : (message) => {
				Logger.debug("VersionInfo", message);
			};
			VersionInfo.print(printer);
			printer(`High DPI: ${Environment.highDpiFactor}`);
			Environment._printPlatformInfo(printer);
		}
		/**
		* @target web
		* @partial
		*/
		static _printPlatformInfo(print) {
			print(`Platform: ${WebPlatform[Environment.webPlatform]}`);
			print(`WebPack: ${Environment.isWebPackBundled}`);
			print(`Vite: ${Environment.isViteBundled}`);
			if (Environment.webPlatform !== WebPlatform.NodeJs) {
				print(`Browser: ${navigator.userAgent}`);
				print(`Window Size: ${window.outerWidth}x${window.outerHeight}`);
				print(`Screen Size: ${window.screen.width}x${window.screen.height}`);
			}
		}
		/**
		* Prepares the given object to be sent to workers. Web Frameworks like Vue might
		* create proxy objects for all objects used. This code handles the necessary unwrapping.
		* @internal
		* @target web
		* @partial
		*/
		static prepareForPostMessage(object) {
			if (!object) return object;
			if (typeof object === "object") {
				const unwrapped = object.__v_raw;
				if (unwrapped) return Environment.prepareForPostMessage(unwrapped);
			}
			return object;
		}
		/**
		* @internal
		* @target web
		* @partial
		*/
		static quoteJsonString(text) {
			return JSON.stringify(text);
		}
		/**
		* @internal
		* @target web
		* @partial
		*/
		static sortDescending(array) {
			array.sort((a, b) => b - a);
		}
	};
	//#endregion
	//#region src/CoreSettings.ts
	/**
	* Lists the known file formats for font files.
	* @target web
	* @public
	*/
	var FontFileFormat = /* @__PURE__ */ function(FontFileFormat) {
		/**
		* .eot
		*/
		FontFileFormat[FontFileFormat["EmbeddedOpenType"] = 0] = "EmbeddedOpenType";
		/**
		* .woff
		*/
		FontFileFormat[FontFileFormat["Woff"] = 1] = "Woff";
		/**
		* .woff2
		*/
		FontFileFormat[FontFileFormat["Woff2"] = 2] = "Woff2";
		/**
		* .otf
		*/
		FontFileFormat[FontFileFormat["OpenType"] = 3] = "OpenType";
		/**
		* .ttf
		*/
		FontFileFormat[FontFileFormat["TrueType"] = 4] = "TrueType";
		/**
		* .svg
		*/
		FontFileFormat[FontFileFormat["Svg"] = 5] = "Svg";
		return FontFileFormat;
	}({});
	/**
	* All main settings of alphaTab controlling rather general aspects of its behavior.
	* @json
	* @json_declaration
	* @public
	*/
	var CoreSettings = class {
		/**
		* The full URL to the alphaTab JavaScript file.
		* @remarks
		* AlphaTab needs to know the full URL to the script file it is contained in to launch the web workers. AlphaTab will do its best to auto-detect
		* this path but in case it fails, this setting can be used to explicitly define it. Altenatively also a global variable `ALPHATAB_ROOT` can
		* be defined before initializing. Please be aware that bundling alphaTab together with other scripts might cause errors
		* in case those scripts are not suitable for web workers. e.g. if there is a script bundled together with alphaTab that accesses the DOM,
		* this will cause an error when alphaTab starts this script as worker.
		* @defaultValue Absolute url to JavaScript file containing alphaTab. (auto detected)
		* @category Core - JavaScript Specific
		* @target web
		* @since 0.9.6
		*/
		scriptFile = null;
		/**
		* The full URL to the alphaTab font directory.
		* @remarks
		* AlphaTab will generate some dynamic CSS that is needed for displaying the music symbols correctly. For this it needs to know
		* where the Web Font files of [Bravura](https://github.com/steinbergmedia/bravura) are. Normally alphaTab expects
		* them to be in a `font` subfolder beside the script file. If this is not the case, this setting must be used to configure the path.
		* Alternatively also a global variable `ALPHATAB_FONT` can be set on the page before initializing alphaTab.
		* 
		* Use {@link smuflFontSources} for more flexible font configuration.
		* @defaultValue `"${AlphaTabScriptFolder}/font/"`
		* @category Core - JavaScript Specific
		* @target web
		* @since 0.9.6
		*/
		fontDirectory = null;
		/**
		* Defines the URLs from which to load the SMuFL compliant font files.
		* @remarks
		* These sources will be used to load and register the webfonts on the page so
		* they are available for rendering the music sheet. The sources can be set to any 
		* CSS compatible URL which can be passed into `url()`.
		* See https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src#url
		* 
		* If you customize the SmuFL font used in alphaTab, you will also need to provide 
		* the respective SMuFL Metadata information to alphaTab. 
		* Set the metadata via {@link EngravingSettings.fillFromSmufl} on the rendering resources.
		* 
		* @defaultValue Bravura files located at {@link fontDirectory} .
		* @category Core - JavaScript Specific
		* @target web
		* @since 1.6.0
		*/
		smuflFontSources = null;
		/**
		* Builds the default SMuFL font sources for the usage with alphaTab in cases
		* where no custom {@link smuflFontSources} are provided.
		* @param fontDirectory The {@link CoreSettings.fontDirectory} configured.
		* @target web
		*/
		static buildDefaultSmuflFontSources(fontDirectory) {
			const map = /* @__PURE__ */ new Map();
			const prefix = fontDirectory ?? "";
			map.set(2, `${prefix}Bravura.woff2`);
			map.set(1, `${prefix}Bravura.woff`);
			map.set(3, `${prefix}Bravura.otf`);
			return map;
		}
		/**
		* The full URL to the input file to be loaded.
		* @remarks
		* AlphaTab can automatically load and render a file after initialization. This eliminates the need of manually calling
		* one of the load methods which are available. alphaTab will automatically initiate an `XMLHttpRequest` after initialization
		* to load and display the provided url of this setting. Note that this setting is only interpreted once on initialization.
		* @defaultValue `null`
		* @category Core - JavaScript Specific
		* @target web
		* @since 0.9.6
		*/
		file = null;
		/**
		* Whether the contents of the DOM element should be loaded as alphaTex.
		* @target web
		* @remarks
		* This setting allows you to fill alphaTex code into the DOM element and make alphaTab automatically
		* load it when initializing. Note that this setting is only interpreted once on initialization.
		* @defaultValue `false`
		* @category Core - JavaScript Specific
		* @since 0.9.6
		* @example
		* JavaScript
		* ```html
		* <div id="alphaTab">\title "Simple alphaTex init" . 3.3*4</div>
		* <script>
		* const api = new alphaTab.AlphaTabApi(document.getElementById('alphaTab'), { core: { tex: true }});
		* <\/script>
		* ```
		*/
		tex = false;
		/**
		* The tracks to display for the initally loaded file.
		* @json_raw
		* @remarks
		* This setting can be used in combinition with the {@link file} or {@link tex} option. It controls which of the tracks
		* of the initially loaded file should be displayed.
		* @defaultValue `null`
		* @category Core - JavaScript Specific
		* @target web
		* @since 0.9.6
		*/
		tracks = null;
		/**
		* Enables lazy loading of the rendered music sheet chunks.
		* @remarks
		* AlphaTab renders the music sheet in smaller sub-chunks to have fast UI feedback. Not all of those sub-chunks are immediately
		* appended to the DOM due to performance reasons. AlphaTab tries to detect which elements are visible on the screen, and only
		* appends those elements to the DOM. This reduces the load of the browser heavily but is not working for all layouts and use cases.
		* This setting set to false, ensures that all rendered items are instantly appended to the DOM.
		* The lazy rendering of partial might not be available on all platforms.
		* @defaultValue `true`
		* @category Core
		* @since 0.9.6
		*/
		enableLazyLoading = true;
		/**
		* The engine which should be used to render the the tablature.
		* @remarks
		* AlphaTab can use various render engines to draw the music notation. The available render engines is specific to the platform. Please refer to the table below to find out which engines are available on which platform.
		* - `default`- Platform specific default engine
		* - `html5`- Uses HTML5 canvas elements to render the music notation (browser only)
		* - `svg`- Outputs SVG strings (all platforms, default for web)
		* - `skia` - Uses [Skia](https://skia.org/) for rendering (all non-browser platforms via [alphaSkia](https://github.com/CoderLine/alphaSkia), default for non-web)
		* - `gdi` - Uses [GDI+](https://docs.microsoft.com/en-us/dotnet/framework/winforms/advanced/graphics-and-drawing-in-windows-forms) for rendering (only on .net)
		* - `android` - Uses [android.graphics.Canvas](https://developer.android.com/reference/android/graphics/Canvas) for rendering (only on Android)
		* @defaultValue `"default"`
		* @category Core
		* @since 0.9.6
		*/
		engine = "default";
		/**
		* The log level to use within alphaTab
		* @remarks
		* AlphaTab internally does quite a bit of logging for debugging and informational purposes. The log level of alphaTab can be controlled via this setting.
		* @defaultValue `LogLevel.Info`
		* @category Core
		* @since 0.9.6
		*/
		logLevel = LogLevel.Info;
		/**
		* Whether the rendering should be done in a worker if possible.
		* @remarks
		* AlphaTab normally tries to render the music sheet asynchronously in a worker. This reduces the load on the UI side and avoids hanging. However sometimes it might be more desirable to have
		* a synchronous rendering behavior. This setting can be set to false to synchronously render the music sheet on the UI side.
		* @defaultValue `true`
		* @category Core
		* @since 0.9.6
		*/
		useWorkers = true;
		/**
		* Whether in the {@link BoundsLookup} also the position and area of each individual note is provided.
		* @remarks
		* AlphaTab collects the position of the rendered music notation elements during the rendering process. This way some level of interactivity can be provided like the feature that seeks to the corresponding position when clicking on a beat.
		* By default the position of the individual notes is not collected due to performance reasons. If access to note position information is needed, this setting can enable it.
		* @defaultValue `false`
		* @category Core
		* @since 0.9.6
		* @example
		* JavaScript
		* ```js
		* const settings = new alphaTab.model.Settings();
		* settings.core.includeNoteBounds = true;
		* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'), settings);
		* api.renderFinished.on(() => {
		*     const lookup = api.renderer.boundsLookup;
		*     const x = 100;
		*     const y = 100;
		*     const beat = lookup.getBeatAtPos(x, y);
		*     const note = lookup.getNoteAtPos(beat, x, y);
		* });
		* ```
		*/
		includeNoteBounds = false;
		/**
		* @target web
		*/
		constructor() {
			this.scriptFile = Environment.scriptFile;
			this.fontDirectory = Environment.fontDirectory;
		}
	};
	//#endregion
	//#region src/importer/alphaTex/_barrel.ts
	var _barrel_exports$8 = /* @__PURE__ */ __exportAll({
		AlphaTexAccidentalMode: () => AlphaTexAccidentalMode,
		AlphaTexDiagnosticBag: () => AlphaTexDiagnosticBag,
		AlphaTexDiagnosticCode: () => AlphaTexDiagnosticCode,
		AlphaTexDiagnosticsSeverity: () => AlphaTexDiagnosticsSeverity,
		AlphaTexLexer: () => AlphaTexLexer,
		AlphaTexNodeType: () => AlphaTexNodeType,
		AlphaTexParseMode: () => AlphaTexParseMode,
		AlphaTexParser: () => AlphaTexParser,
		AlphaTexStaffNoteKind: () => AlphaTexStaffNoteKind,
		AlphaTexVoiceMode: () => AlphaTexVoiceMode,
		ArgumentListParseTypesMode: () => ArgumentListParseTypesMode
	});
	//#endregion
	//#region src/importer/_barrel.ts
	var _barrel_exports$1 = /* @__PURE__ */ __exportAll({
		AlphaTexErrorWithDiagnostics: () => AlphaTexErrorWithDiagnostics,
		AlphaTexImporter: () => AlphaTexImporter,
		ScoreImporter: () => ScoreImporter,
		ScoreLoader: () => ScoreLoader,
		UnsupportedFormatError: () => UnsupportedFormatError,
		alphaTex: () => _barrel_exports$8
	});
	//#endregion
	//#region src/io/_barrel.ts
	var _barrel_exports$2 = /* @__PURE__ */ __exportAll({
		ByteBuffer: () => ByteBuffer,
		IOHelper: () => IOHelper
	});
	//#endregion
	//#region src/exporter/ScoreExporter.ts
	/**
	* This is the base class for creating new song exporters which
	* enable writing scores to a binary datasink.
	* @public
	*/
	var ScoreExporter = class {
		data;
		settings;
		/**
		* Initializes the importer with the given data and settings.
		*/
		init(data, settings) {
			this.data = data;
			this.settings = settings;
		}
		/**
		* Exports the given score to a binary buffer.
		* @param score The score to serialize
		* @param settings  The settings to use during serialization
		* @returns A byte buffer with the serialized score.
		*/
		export(score, settings = null) {
			const writable = ByteBuffer.withCapacity(1024);
			this.init(writable, settings ?? new Settings());
			this.writeScore(score);
			return writable.toArray();
		}
	};
	//#endregion
	//#region src/exporter/AlphaTexExporter.ts
	/**
	* A small helper to write formatted alphaTex code to a string buffer.
	* @internal
	*/
	var AlphaTexWriter = class {
		tex = "";
		isStartOfLine = true;
		indentString = "";
		currentIndent = 0;
		indent() {
			if (this.indentString.length > 0) this.currentIndent++;
		}
		outdent() {
			if (this.indentString.length > 0) this.currentIndent--;
		}
		_preWrite() {
			if (this.isStartOfLine && this.indentString.length > 0) for (let i = 0; i < this.currentIndent; i++) this.tex += this.indentString;
			this.isStartOfLine = false;
		}
		write(text) {
			this._preWrite();
			this.tex += text;
			this.isStartOfLine = false;
		}
		writeString(text) {
			this._preWrite();
			this.tex += Environment.quoteJsonString(text);
		}
		writeLine(text) {
			this._preWrite();
			if (text !== void 0) this.tex += text;
			if (this.indentString.length > 0) this.tex += "\n";
			else if (!this.tex.endsWith(" ")) this.tex += " ";
			this.isStartOfLine = true;
		}
	};
	/**
	* @internal
	*/
	var AlphaTexPrinter = class {
		_writer;
		_comments = false;
		get tex() {
			return this._writer.tex;
		}
		constructor(settings) {
			const writer = new AlphaTexWriter();
			this._comments = settings.exporter.comments;
			writer.indentString = settings.exporter.indent > 0 ? " ".repeat(settings.exporter.indent) : "";
			this._writer = writer;
		}
		writeScoreNode(node) {
			this._writeComments(node.leadingComments);
			for (const b of node.bars) this._writeBar(b);
			this._writeComments(node.trailingComments);
		}
		_writeBar(bar) {
			this._writeComments(bar.leadingComments);
			this._writeMetaDataList(bar.metaData);
			this._writer.indent();
			for (const beat of bar.beats) this._writeBeat(beat);
			this._writer.outdent();
			this._writeComments(bar.trailingComments);
			this._writeToken(bar.pipe, true);
		}
		_writeBeat(beat) {
			this._writeComments(beat.leadingComments);
			if (beat.durationChange) this._writeDurationChange(beat.durationChange);
			if (beat.rest) this._writeValue(beat.rest);
			else if (beat.notes) this._writeNotes(beat.notes);
			this._writeToken(beat.durationDot, false);
			this._writeValue(beat.durationValue);
			this._writeToken(beat.beatMultiplier, false);
			this._writeValue(beat.beatMultiplierValue);
			if (beat.beatEffects) this._writeProperties(beat.beatEffects, false);
			this._writeComments(beat.trailingComments);
			this._writer.writeLine();
		}
		_writeNotes(notes) {
			this._writeComments(notes.leadingComments);
			this._writeToken(notes.openParenthesis, false);
			let first = true;
			for (const n of notes.notes) {
				if (!first) this._writer.write(" ");
				this._writeNote(n);
				first = false;
			}
			this._writeToken(notes.closeParenthesis, false);
			this._writeComments(notes.trailingComments);
		}
		_writeNote(n) {
			this._writeComments(n.leadingComments);
			this._writeValue(n.noteValue);
			this._writeToken(n.noteStringDot, false);
			this._writeValue(n.noteString);
			if (n.noteEffects) this._writeProperties(n.noteEffects, false);
			this._writeComments(n.trailingComments);
		}
		_writeDurationChange(durationChange) {
			this._writeComments(durationChange.leadingComments);
			this._writeToken(durationChange.colon, false);
			this._writeValue(durationChange.value);
			if (durationChange.properties) {
				this._writer.write(" ");
				this._writeProperties(durationChange.properties, false);
			}
			this._writeComments(durationChange.trailingComments);
			this._writer.write(" ");
		}
		_writeMetaDataList(metaData) {
			for (const m of metaData) this._writeMetaData(m);
		}
		_trackIndex = 0;
		_staffIndex = 0;
		_voiceIndex = 0;
		_writeMetaData(m) {
			switch (m.tag.tag.text) {
				case "track":
					if (this._staffIndex > 0) this._writer.outdent();
					if (this._trackIndex > 0) this._writer.outdent();
					break;
				case "staff":
					if (this._staffIndex > 0) this._writer.outdent();
					break;
				case "voice":
					if (this._voiceIndex > 0) this._writer.outdent();
					break;
			}
			this._writeComments(m.leadingComments);
			this._writeToken(m.tag.prefix, false);
			this._writeValue(m.tag.tag);
			let newLineAfterMeta = true;
			if (m.propertiesBeforeArguments) {
				if (m.properties) {
					this._writer.write(" ");
					this._writeProperties(m.properties, false);
				}
				if (m.arguments) {
					this._writer.write(" ");
					this._writeValues(m.arguments);
				}
			} else {
				if (m.arguments) {
					this._writer.write(" ");
					this._writeValues(m.arguments);
				}
				if (m.properties) {
					this._writer.write(" ");
					this._writeProperties(m.properties, true);
					newLineAfterMeta = false;
				}
			}
			if (m.trailingComments) {
				this._writer.write(" ");
				this._writeComments(m.trailingComments);
			}
			switch (m.tag.tag.text) {
				case "track":
					this._trackIndex++;
					this._staffIndex = 0;
					this._voiceIndex = 0;
					this._writer.indent();
					break;
				case "staff":
					this._staffIndex++;
					this._voiceIndex = 0;
					this._writer.indent();
					break;
				case "voice":
					this._voiceIndex++;
					this._writer.indent();
					break;
			}
			if (newLineAfterMeta) this._writer.writeLine();
		}
		_writeProperties(properties, indent) {
			this._writeComments(properties.leadingComments);
			this._writeToken(properties.openBrace, indent);
			if (indent) this._writer.indent();
			let first = true;
			for (const p of properties.properties) {
				if (!first && !indent) this._writer.write(" ");
				this._writeProperty(p);
				first = false;
				if (indent) this._writer.writeLine();
			}
			if (indent) this._writer.outdent();
			this._writeToken(properties.closeBrace, indent);
			this._writeComments(properties.trailingComments);
		}
		_writeProperty(p) {
			this._writeComments(p.leadingComments);
			this._writeValue(p.property);
			if (p.arguments) {
				this._writer.write(" ");
				this._writeValues(p.arguments);
			}
			this._writeComments(p.trailingComments);
		}
		_writeValues(values) {
			this._writeComments(values.leadingComments);
			this._writeToken(values.openParenthesis, false);
			let first = true;
			for (const v of values.arguments) {
				if (!first) this._writer.write(" ");
				this._writeValue(v);
				first = false;
			}
			this._writeToken(values.closeParenthesis, false);
			this._writeComments(values.trailingComments);
		}
		_writeValue(v) {
			if (!v) return;
			this._writeComments(v.leadingComments);
			switch (v.nodeType) {
				case AlphaTexNodeType.Ident:
					this._writer.write(v.text);
					break;
				case AlphaTexNodeType.Arguments:
					this._writeValues(v);
					break;
				case AlphaTexNodeType.Number:
					this._writer.write(v.value.toString());
					break;
				case AlphaTexNodeType.String:
					this._writer.writeString(v.text);
					break;
			}
			this._writeComments(v.trailingComments);
		}
		_writeToken(tokenNode, newLine) {
			if (tokenNode) {
				this._writeComments(tokenNode.leadingComments);
				switch (tokenNode.nodeType) {
					case AlphaTexNodeType.Dot:
						this._writer.write(".");
						break;
					case AlphaTexNodeType.Backslash:
						this._writer.write("\\");
						break;
					case AlphaTexNodeType.DoubleBackslash:
						this._writer.write("\\\\");
						break;
					case AlphaTexNodeType.Pipe:
						this._writer.write("|");
						break;
					case AlphaTexNodeType.LBrace:
						this._writer.write("{");
						break;
					case AlphaTexNodeType.RBrace:
						this._writer.write("}");
						break;
					case AlphaTexNodeType.LParen:
						this._writer.write("(");
						break;
					case AlphaTexNodeType.RParen:
						this._writer.write(")");
						break;
					case AlphaTexNodeType.Colon:
						this._writer.write(":");
						break;
					case AlphaTexNodeType.Asterisk:
						this._writer.write("*");
						break;
				}
				this._writeComments(tokenNode.trailingComments);
				if (newLine) this._writer.writeLine();
			}
		}
		_writeComments(comments) {
			if (!this._comments || !comments) return;
			for (const c of comments) {
				let txt = c.text;
				if (!txt.startsWith(" ")) txt = ` ${txt}`;
				if (c.multiLine) {
					if (!txt.endsWith(" ")) txt += " ";
					this._writer.write(`/*${txt}*/`);
				} else this._writer.writeLine(`//${txt}`);
			}
		}
	};
	/**
	* This ScoreExporter can write alphaTex strings.
	* @public
	*/
	var AlphaTexExporter = class extends ScoreExporter {
		_handler = AlphaTex1LanguageHandler.instance;
		get name() {
			return "alphaTex";
		}
		exportToString(score, settings = null) {
			this.settings = settings ?? new Settings();
			return this.scoreToAlphaTexString(score);
		}
		writeScore(score) {
			const raw = IOHelper.stringToBytes(this.scoreToAlphaTexString(score));
			this.data.write(raw, 0, raw.length);
		}
		scoreToAlphaTexString(score) {
			const printer = new AlphaTexPrinter(this.settings);
			printer.writeScoreNode(this._score(score));
			return printer.tex;
		}
		_score(data) {
			const score = {
				nodeType: AlphaTexNodeType.Score,
				bars: []
			};
			for (const t of data.tracks) this._track(score, t);
			if (score.bars.length === 0) score.bars.push({
				nodeType: AlphaTexNodeType.Bar,
				metaData: this._handler.buildScoreMetaDataNodes(data),
				beats: []
			});
			else score.bars[0].metaData = this._handler.buildScoreMetaDataNodes(data).concat(score.bars[0].metaData);
			score.bars.push({
				nodeType: AlphaTexNodeType.Bar,
				metaData: this._handler.buildSyncPointNodes(data),
				beats: []
			});
			return score;
		}
		_track(score, data) {
			for (const s of data.staves) this._staff(score, s);
		}
		_staff(score, data) {
			const voiceCount = Math.max(...data.filledVoices) + 1;
			if (data.bars.length === 0) {
				const bar = {
					nodeType: AlphaTexNodeType.Bar,
					metaData: this._handler.buildBarMetaDataNodes(data, void 0, 0, false),
					beats: [],
					pipe: void 0
				};
				score.bars.push(bar);
			} else for (let v = 0; v < voiceCount; v++) this._voice(score, v, data, voiceCount > 1);
		}
		_voice(score, v, data, isMultiVoice) {
			for (const bar of data.bars) this._bar(score, bar, v, isMultiVoice);
		}
		_bar(score, data, voiceIndex, isMultiVoice) {
			const bar = {
				nodeType: AlphaTexNodeType.Bar,
				metaData: this._handler.buildBarMetaDataNodes(data.staff, data, voiceIndex, isMultiVoice),
				beats: [],
				pipe: void 0
			};
			if (!data.isEmpty) {
				const voice = data.voices[voiceIndex];
				if (voice.isEmpty) bar.trailingComments = [{
					multiLine: false,
					text: `Bar ${data.index + 1} / Voice ${voiceIndex + 1} no contents`
				}];
				else {
					for (const b of voice.beats) bar.beats.push(this._beat(b));
					if (bar.beats.length > 0) {
						bar.beats[0].leadingComments ??= [];
						bar.beats[0].leadingComments.unshift({
							multiLine: false,
							text: `Bar ${data.index + 1} / Voice ${voiceIndex + 1} contents`
						});
					}
				}
			} else bar.trailingComments = [{
				multiLine: false,
				text: `Bar ${data.index + 1} / Voice ${voiceIndex + 1} no contents`
			}];
			if (data.index < data.staff.bars.length - 1) bar.pipe = { nodeType: AlphaTexNodeType.Pipe };
			score.bars.push(bar);
		}
		_beat(data) {
			const beat = {
				nodeType: AlphaTexNodeType.Beat,
				durationChange: void 0,
				notes: void 0,
				rest: void 0,
				beatEffects: void 0
			};
			if (data.isRest) beat.rest = {
				nodeType: AlphaTexNodeType.Ident,
				text: "r"
			};
			else beat.notes = this._notes(data.notes);
			beat.durationDot = { nodeType: AlphaTexNodeType.Dot };
			beat.durationValue = {
				nodeType: AlphaTexNodeType.Number,
				value: data.duration
			};
			beat.beatEffects = this._beatEffects(data);
			return beat;
		}
		_beatEffects(data) {
			const properties = this._handler.buildBeatEffects(data);
			return properties.length > 0 ? {
				nodeType: AlphaTexNodeType.Props,
				openBrace: { nodeType: AlphaTexNodeType.LBrace },
				properties,
				closeBrace: { nodeType: AlphaTexNodeType.RBrace }
			} : void 0;
		}
		_notes(data) {
			const notes = {
				nodeType: AlphaTexNodeType.NoteList,
				openParenthesis: void 0,
				notes: [],
				closeParenthesis: void 0
			};
			if (data.length === 0 || data.length > 1) {
				notes.openParenthesis = { nodeType: AlphaTexNodeType.LParen };
				notes.closeParenthesis = { nodeType: AlphaTexNodeType.RParen };
			}
			for (const n of data) notes.notes.push(this._note(n));
			return notes;
		}
		_note(data) {
			const note = {
				nodeType: AlphaTexNodeType.Note,
				noteValue: {
					nodeType: AlphaTexNodeType.Ident,
					text: ""
				}
			};
			if (data.isPercussion) note.noteValue = {
				nodeType: AlphaTexNodeType.String,
				text: PercussionMapper.getArticulationName(data)
			};
			else if (data.isPiano) note.noteValue = {
				nodeType: AlphaTexNodeType.Ident,
				text: Tuning.getTextForTuning(data.realValueWithoutHarmonic, true)
			};
			else if (data.isStringed) {
				note.noteValue = {
					nodeType: AlphaTexNodeType.Number,
					value: data.fret
				};
				note.noteStringDot = { nodeType: AlphaTexNodeType.Dot };
				const stringNumber = data.beat.voice.bar.staff.tuning.length - data.string + 1;
				note.noteString = {
					nodeType: AlphaTexNodeType.Number,
					value: stringNumber
				};
			} else throw new Error("What kind of note");
			note.noteEffects = this._noteEffects(data);
			return note;
		}
		_noteEffects(data) {
			const properties = this._handler.buildNoteEffects(data);
			return properties.length > 0 ? {
				nodeType: AlphaTexNodeType.Props,
				openBrace: { nodeType: AlphaTexNodeType.LBrace },
				properties,
				closeBrace: { nodeType: AlphaTexNodeType.RBrace }
			} : void 0;
		}
	};
	//#endregion
	//#region src/exporter/GpifSoundMapper.ts
	/**
	* @internal
	*/
	var GpifMidiProgramInfo = class {
		icon = 10;
		instrumentSetName;
		instrumentSetType;
		constructor(icon, instrumentSetName, instrumentSetType = null) {
			this.icon = icon;
			this.instrumentSetName = instrumentSetName;
			if (!instrumentSetType) {
				const parts = instrumentSetName.split(" ");
				parts[0] = parts[0].substr(0, 1).toLowerCase() + parts[0].substr(1);
				this.instrumentSetType = parts.join("");
			} else this.instrumentSetType = instrumentSetType;
		}
	};
	/**
	* @internal
	*/
	var GpifInstrumentSet = class GpifInstrumentSet {
		lineCount = 0;
		name = "";
		type = "";
		elements = [];
		static create(name, type, lineCount, elements) {
			const insturmentSet = new GpifInstrumentSet();
			insturmentSet.name = name;
			insturmentSet.type = type;
			insturmentSet.lineCount = lineCount;
			insturmentSet.elements = elements;
			return insturmentSet;
		}
	};
	/**
	* @internal
	*/
	var GpifInstrumentElement = class {
		name;
		type;
		soundbankName;
		articulations;
		constructor(name, type, soundbankName, articulations) {
			this.name = name;
			this.type = type;
			this.soundbankName = soundbankName;
			this.articulations = articulations;
		}
	};
	/**
	* @internal
	*/
	var GpifInstrumentArticulation = class GpifInstrumentArticulation {
		name;
		staffLine;
		noteHeads;
		techniqueSymbol;
		techniqueSymbolPlacement;
		inputMidiNumbers;
		outputMidiNumber;
		outputRSESound;
		constructor(name, staffLine, noteHeads, techniqueSymbol, techniqueSymbolPlacement, inputMidiNumbers, outputMidiNumber, outputRSESound) {
			this.name = name;
			this.staffLine = staffLine;
			this.noteHeads = noteHeads;
			this.techniqueSymbol = techniqueSymbol;
			this.techniqueSymbolPlacement = techniqueSymbolPlacement;
			this.inputMidiNumbers = inputMidiNumbers;
			this.outputMidiNumber = outputMidiNumber;
			this.outputRSESound = outputRSESound;
		}
		static template(name, inputMidiNumbers, outputRSESound) {
			return new GpifInstrumentArticulation(name, 0, [], MusicFontSymbol.None, TechniqueSymbolPlacement.Outside, inputMidiNumbers, 0, outputRSESound);
		}
	};
	/**
	* A helper which provides the RSE Soundbank and MIDI mapping
	* details for exporting Guitar Pro files from the alphaTab model.
	* @internal
	*/
	var GpifSoundMapper = class GpifSoundMapper {
		static _midiProgramInfoLookup = new Map([
			[0, new GpifMidiProgramInfo(10, "Acoustic Piano")],
			[1, new GpifMidiProgramInfo(10, "Acoustic Piano")],
			[2, new GpifMidiProgramInfo(10, "Electric Piano")],
			[3, new GpifMidiProgramInfo(10, "Acoustic Piano")],
			[4, new GpifMidiProgramInfo(10, "Electric Piano")],
			[5, new GpifMidiProgramInfo(10, "Electric Piano")],
			[6, new GpifMidiProgramInfo(10, "Harpsichord")],
			[7, new GpifMidiProgramInfo(10, "Harpsichord")],
			[8, new GpifMidiProgramInfo(17, "Celesta")],
			[9, new GpifMidiProgramInfo(17, "Vibraphone")],
			[10, new GpifMidiProgramInfo(17, "Vibraphone")],
			[11, new GpifMidiProgramInfo(17, "Vibraphone")],
			[12, new GpifMidiProgramInfo(17, "Xylophone")],
			[13, new GpifMidiProgramInfo(17, "Xylophone")],
			[14, new GpifMidiProgramInfo(17, "Vibraphone")],
			[15, new GpifMidiProgramInfo(8, "Banjo")],
			[16, new GpifMidiProgramInfo(10, "Electric Organ")],
			[17, new GpifMidiProgramInfo(10, "Electric Organ")],
			[18, new GpifMidiProgramInfo(10, "Electric Organ")],
			[19, new GpifMidiProgramInfo(10, "Electric Organ")],
			[20, new GpifMidiProgramInfo(10, "Electric Organ")],
			[21, new GpifMidiProgramInfo(10, "Electric Organ")],
			[22, new GpifMidiProgramInfo(15, "Recorder")],
			[23, new GpifMidiProgramInfo(10, "Electric Organ")],
			[24, new GpifMidiProgramInfo(23, "Nylon Guitar")],
			[25, new GpifMidiProgramInfo(1, "Steel Guitar")],
			[26, new GpifMidiProgramInfo(1, "Electric Guitar")],
			[27, new GpifMidiProgramInfo(4, "Electric Guitar")],
			[28, new GpifMidiProgramInfo(4, "Electric Guitar")],
			[29, new GpifMidiProgramInfo(4, "Electric Guitar")],
			[30, new GpifMidiProgramInfo(1, "Electric Guitar")],
			[31, new GpifMidiProgramInfo(1, "Electric Guitar")],
			[32, new GpifMidiProgramInfo(5, "Acoustic Bass")],
			[33, new GpifMidiProgramInfo(5, "Electric Bass")],
			[34, new GpifMidiProgramInfo(5, "Electric Bass")],
			[35, new GpifMidiProgramInfo(5, "Acoustic Bass")],
			[36, new GpifMidiProgramInfo(5, "Electric Bass")],
			[37, new GpifMidiProgramInfo(5, "Electric Bass")],
			[38, new GpifMidiProgramInfo(12, "Synth Bass")],
			[39, new GpifMidiProgramInfo(12, "Synth Bass")],
			[40, new GpifMidiProgramInfo(11, "Violin")],
			[41, new GpifMidiProgramInfo(11, "Viola")],
			[42, new GpifMidiProgramInfo(11, "Cello")],
			[43, new GpifMidiProgramInfo(11, "Contrabass")],
			[44, new GpifMidiProgramInfo(11, "Violin")],
			[45, new GpifMidiProgramInfo(11, "Violin")],
			[46, new GpifMidiProgramInfo(10, "Harp")],
			[47, new GpifMidiProgramInfo(20, "Timpani")],
			[48, new GpifMidiProgramInfo(11, "Violin")],
			[49, new GpifMidiProgramInfo(11, "Violin")],
			[50, new GpifMidiProgramInfo(11, "Violin")],
			[51, new GpifMidiProgramInfo(11, "Violin")],
			[52, new GpifMidiProgramInfo(16, "Voice")],
			[53, new GpifMidiProgramInfo(16, "Voice")],
			[54, new GpifMidiProgramInfo(16, "Voice")],
			[55, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[56, new GpifMidiProgramInfo(13, "Trumpet")],
			[57, new GpifMidiProgramInfo(13, "Trombone")],
			[58, new GpifMidiProgramInfo(13, "Tuba")],
			[59, new GpifMidiProgramInfo(13, "Trumpet")],
			[60, new GpifMidiProgramInfo(13, "French Horn")],
			[61, new GpifMidiProgramInfo(13, "Trumpet")],
			[62, new GpifMidiProgramInfo(13, "Trumpet")],
			[63, new GpifMidiProgramInfo(13, "Trumpet")],
			[64, new GpifMidiProgramInfo(14, "Saxophone")],
			[65, new GpifMidiProgramInfo(14, "Saxophone")],
			[66, new GpifMidiProgramInfo(14, "Saxophone")],
			[67, new GpifMidiProgramInfo(14, "Saxophone")],
			[68, new GpifMidiProgramInfo(14, "Oboe")],
			[69, new GpifMidiProgramInfo(14, "English Horn")],
			[70, new GpifMidiProgramInfo(14, "Bassoon")],
			[71, new GpifMidiProgramInfo(14, "Clarinet")],
			[72, new GpifMidiProgramInfo(14, "Piccolo")],
			[73, new GpifMidiProgramInfo(15, "Flute")],
			[74, new GpifMidiProgramInfo(15, "Recorder")],
			[75, new GpifMidiProgramInfo(15, "Flute")],
			[76, new GpifMidiProgramInfo(15, "Recorder")],
			[77, new GpifMidiProgramInfo(15, "Flute")],
			[78, new GpifMidiProgramInfo(15, "Recorder")],
			[79, new GpifMidiProgramInfo(15, "Flute")],
			[80, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[81, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[82, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[83, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[84, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[85, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[86, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[87, new GpifMidiProgramInfo(12, "Lead Synthesizer")],
			[88, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[89, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[90, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[91, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[92, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[93, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[94, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[95, new GpifMidiProgramInfo(12, "Pad Synthesizer")],
			[96, new GpifMidiProgramInfo(21, "Pad Synthesizer")],
			[97, new GpifMidiProgramInfo(21, "Pad Synthesizer")],
			[98, new GpifMidiProgramInfo(21, "Pad Synthesizer")],
			[99, new GpifMidiProgramInfo(21, "Pad Synthesizer")],
			[100, new GpifMidiProgramInfo(21, "Lead Synthesizer")],
			[101, new GpifMidiProgramInfo(21, "Lead Synthesizer")],
			[102, new GpifMidiProgramInfo(21, "Lead Synthesizer")],
			[103, new GpifMidiProgramInfo(21, "Trumpet")],
			[104, new GpifMidiProgramInfo(4, "Banjo")],
			[105, new GpifMidiProgramInfo(8, "Banjo")],
			[106, new GpifMidiProgramInfo(7, "Ukulele")],
			[107, new GpifMidiProgramInfo(8, "Banjo")],
			[108, new GpifMidiProgramInfo(17, "Xylophone")],
			[109, new GpifMidiProgramInfo(14, "Bassoon")],
			[110, new GpifMidiProgramInfo(11, "Violin")],
			[111, new GpifMidiProgramInfo(15, "Flute")],
			[112, new GpifMidiProgramInfo(17, "Xylophone")],
			[113, new GpifMidiProgramInfo(19, "Celesta")],
			[114, new GpifMidiProgramInfo(17, "Vibraphone")],
			[115, new GpifMidiProgramInfo(19, "Xylophone")],
			[116, new GpifMidiProgramInfo(20, "Xylophone")],
			[117, new GpifMidiProgramInfo(20, "Xylophone")],
			[118, new GpifMidiProgramInfo(20, "Xylophone")],
			[119, new GpifMidiProgramInfo(19, "Celesta")],
			[120, new GpifMidiProgramInfo(21, "Steel Guitar")],
			[121, new GpifMidiProgramInfo(21, "Recorder")],
			[122, new GpifMidiProgramInfo(21, "Recorder")],
			[123, new GpifMidiProgramInfo(21, "Recorder")],
			[124, new GpifMidiProgramInfo(21, "Recorder")],
			[125, new GpifMidiProgramInfo(21, "Recorder")],
			[126, new GpifMidiProgramInfo(21, "Recorder")],
			[127, new GpifMidiProgramInfo(21, "Timpani")]
		]);
		static _drumInstrumentSet = GpifInstrumentSet.create("Drums", "drumKit", 5, [
			new GpifInstrumentElement("Snare", "snare", "Master-Snare", [
				GpifInstrumentArticulation.template("Snare (hit)", [38], "stick.hit.hit"),
				GpifInstrumentArticulation.template("Snare (side stick)", [37], "stick.hit.sidestick"),
				GpifInstrumentArticulation.template("Snare (rim shot)", [91], "stick.hit.rimshot")
			]),
			new GpifInstrumentElement("Charley", "hiHat", "Master-Hihat", [
				GpifInstrumentArticulation.template("Hi-Hat (closed)", [42], "stick.hit.closed"),
				GpifInstrumentArticulation.template("Hi-Hat (half)", [92], "stick.hit.half"),
				GpifInstrumentArticulation.template("Hi-Hat (open)", [46], "stick.hit.open"),
				GpifInstrumentArticulation.template("Pedal Hi-Hat (hit)", [44], "pedal.hit.pedal")
			]),
			new GpifInstrumentElement("Acoustic Kick Drum", "kickDrum", "AcousticKick-Percu", [GpifInstrumentArticulation.template("Kick (hit)", [35], "pedal.hit.hit")]),
			new GpifInstrumentElement("Kick Drum", "kickDrum", "Master-Kick", [GpifInstrumentArticulation.template("Kick (hit)", [36], "pedal.hit.hit")]),
			new GpifInstrumentElement("Tom Very High", "tom", "Master-Tom05", [GpifInstrumentArticulation.template("High Floor Tom (hit)", [50], "stick.hit.hit")]),
			new GpifInstrumentElement("Tom High", "tom", "Master-Tom04", [GpifInstrumentArticulation.template("High Tom (hit)", [48], "stick.hit.hit")]),
			new GpifInstrumentElement("Tom Medium", "tom", "Master-Tom03", [GpifInstrumentArticulation.template("Mid Tom (hit)", [47], "stick.hit.hit")]),
			new GpifInstrumentElement("Tom Low", "tom", "Master-Tom02", [GpifInstrumentArticulation.template("Low Tom (hit)", [45], "stick.hit.hit")]),
			new GpifInstrumentElement("Tom Very Low", "tom", "Master-Tom01", [GpifInstrumentArticulation.template("Very Low Tom (hit)", [43], "stick.hit.hit")]),
			new GpifInstrumentElement("Ride", "ride", "Master-Ride", [
				GpifInstrumentArticulation.template("Ride (edge)", [93], "stick.hit.edge"),
				GpifInstrumentArticulation.template("Ride (middle)", [51], "stick.hit.mid"),
				GpifInstrumentArticulation.template("Ride (bell)", [53], "stick.hit.bell"),
				GpifInstrumentArticulation.template("Ride (choke)", [94], "stick.hit.choke")
			]),
			new GpifInstrumentElement("Splash", "splash", "Master-Splash", [GpifInstrumentArticulation.template("Splash (hit)", [55], "stick.hit.hit"), GpifInstrumentArticulation.template("Splash (choke)", [95], "stick.hit.choke")]),
			new GpifInstrumentElement("China", "china", "Master-China", [GpifInstrumentArticulation.template("China (hit)", [52], "stick.hit.hit"), GpifInstrumentArticulation.template("China (choke)", [96], "stick.hit.choke")]),
			new GpifInstrumentElement("Crash High", "crash", "Master-Crash02", [GpifInstrumentArticulation.template("Crash high (hit)", [49], "stick.hit.hit"), GpifInstrumentArticulation.template("Crash high (choke)", [97], "stick.hit.choke")]),
			new GpifInstrumentElement("Crash Medium", "crash", "Master-Crash01", [GpifInstrumentArticulation.template("Crash medium (hit)", [57], "stick.hit.hit"), GpifInstrumentArticulation.template("Crash medium (choke)", [98], "stick.hit.choke")]),
			new GpifInstrumentElement("Cowbell Low", "cowbell", "CowbellBig-Percu", [GpifInstrumentArticulation.template("Cowbell low (hit)", [99], "stick.hit.hit"), GpifInstrumentArticulation.template("Cowbell low (tip)", [100], "stick.hit.tip")]),
			new GpifInstrumentElement("Cowbell Medium", "cowbell", "CowbellMid-Percu", [GpifInstrumentArticulation.template("Cowbell medium (hit)", [56], "stick.hit.hit"), GpifInstrumentArticulation.template("Cowbell medium (tip)", [101], "stick.hit.tip")]),
			new GpifInstrumentElement("Cowbell High", "cowbell", "CowbellSmall-Percu", [GpifInstrumentArticulation.template("Cowbell high (hit)", [102], "stick.hit.hit"), GpifInstrumentArticulation.template("Cowbell high (tip)", [103], "stick.hit.tip")]),
			new GpifInstrumentElement("Woodblock Low", "woodblock", "WoodblockLow-Percu", [GpifInstrumentArticulation.template("Woodblock low (hit)", [77], "stick.hit.hit")]),
			new GpifInstrumentElement("Woodblock High", "woodblock", "WoodblockHigh-Percu", [GpifInstrumentArticulation.template("Woodblock high (hit)", [76], "stick.hit.hit")]),
			new GpifInstrumentElement("Bongo High", "bongo", "BongoHigh-Percu", [
				GpifInstrumentArticulation.template("Bongo High (hit)", [60], "hand.hit.hit"),
				GpifInstrumentArticulation.template("Bongo High (mute)", [104], "hand.hit.mute"),
				GpifInstrumentArticulation.template("Bongo High (slap)", [105], "hand.hit.slap")
			]),
			new GpifInstrumentElement("Bongo Low", "bongo", "BongoLow-Percu", [
				GpifInstrumentArticulation.template("Bongo Low (hit)", [61], "hand.hit.hit"),
				GpifInstrumentArticulation.template("Bongo Low (mute)", [106], "hand.hit.mute"),
				GpifInstrumentArticulation.template("Bongo Low (slap)", [107], "hand.hit.slap")
			]),
			new GpifInstrumentElement("Timbale Low", "timbale", "TimbaleLow-Percu", [GpifInstrumentArticulation.template("Timbale low (hit)", [66], "stick.hit.hit")]),
			new GpifInstrumentElement("Timbale High", "timbale", "TimbaleHigh-Percu", [GpifInstrumentArticulation.template("Timbale high (hit)", [65], "stick.hit.hit")]),
			new GpifInstrumentElement("Agogo Low", "agogo", "AgogoLow-Percu", [GpifInstrumentArticulation.template("Agogo low (hit)", [68], "stick.hit.hit")]),
			new GpifInstrumentElement("Agogo High", "agogo", "AgogoHigh-Percu", [GpifInstrumentArticulation.template("Agogo high (hit)", [67], "stick.hit.hit")]),
			new GpifInstrumentElement("Conga Low", "conga", "CongaLow-Percu", [
				GpifInstrumentArticulation.template("Conga low (hit)", [64], "hand.hit.hit"),
				GpifInstrumentArticulation.template("Conga low (slap)", [108], "hand.hit.slap"),
				GpifInstrumentArticulation.template("Conga low (mute)", [109], "hand.hit.mute")
			]),
			new GpifInstrumentElement("Conga High", "conga", "CongaHigh-Percu", [
				GpifInstrumentArticulation.template("Conga high (hit)", [63], "hand.hit.hit"),
				GpifInstrumentArticulation.template("Conga high (slap)", [110], "hand.hit.slap"),
				GpifInstrumentArticulation.template("Conga high (mute)", [62], "hand.hit.mute")
			]),
			new GpifInstrumentElement("Whistle Low", "whistle", "WhistleLow-Percu", [GpifInstrumentArticulation.template("Whistle low (hit)", [72], "blow.hit.hit")]),
			new GpifInstrumentElement("Whistle High", "whistle", "WhistleHigh-Percu", [GpifInstrumentArticulation.template("Whistle high (hit)", [71], "blow.hit.hit")]),
			new GpifInstrumentElement("Guiro", "guiro", "Guiro-Percu", [GpifInstrumentArticulation.template("Guiro (hit)", [73], "stick.hit.hit"), GpifInstrumentArticulation.template("Guiro (scrap-return)", [74], "stick.scrape.return")]),
			new GpifInstrumentElement("Surdo", "surdo", "Surdo-Percu", [GpifInstrumentArticulation.template("Surdo (hit)", [86], "brush.hit.hit"), GpifInstrumentArticulation.template("Surdo (mute)", [87], "brush.hit.mute")]),
			new GpifInstrumentElement("Tambourine", "tambourine", "Tambourine-Percu", [
				GpifInstrumentArticulation.template("Tambourine (hit)", [54], "hand.hit.hit"),
				GpifInstrumentArticulation.template("Tambourine (return)", [111], "hand.hit.return"),
				GpifInstrumentArticulation.template("Tambourine (roll)", [112], "hand.hit.roll"),
				GpifInstrumentArticulation.template("Tambourine (hand)", [113], "hand.hit.handhit")
			]),
			new GpifInstrumentElement("Cuica", "cuica", "Cuica-Percu", [GpifInstrumentArticulation.template("Cuica (open)", [79], "hand.hit.hit"), GpifInstrumentArticulation.template("Cuica (mute)", [78], "hand.hit.mute")]),
			new GpifInstrumentElement("Vibraslap", "vibraslap", "Vibraslap-Percu", [GpifInstrumentArticulation.template("Vibraslap (hit)", [58], "hand.hit.hit")]),
			new GpifInstrumentElement("Triangle", "triangle", "Triangle-Percu", [GpifInstrumentArticulation.template("Triangle (hit)", [81], "stick.hit.hit"), GpifInstrumentArticulation.template("Triangle (mute)", [80], "stick.hit.mute")]),
			new GpifInstrumentElement("Grancassa", "grancassa", "Grancassa-Percu", [GpifInstrumentArticulation.template("Grancassa (hit)", [114], "mallet.hit.hit")]),
			new GpifInstrumentElement("Piatti", "piatti", "Piatti-Percu", [GpifInstrumentArticulation.template("Piatti (hit)", [115], "hand.hit.hit"), GpifInstrumentArticulation.template("Piatti (hand)", [116], "hand.hit.hit")]),
			new GpifInstrumentElement("Cabasa", "cabasa", "Cabasa-Percu", [GpifInstrumentArticulation.template("Cabasa (hit)", [69], "hand.hit.hit"), GpifInstrumentArticulation.template("Cabasa (return)", [117], "hand.hit.return")]),
			new GpifInstrumentElement("Castanets", "castanets", "Castanets-Percu", [GpifInstrumentArticulation.template("Castanets (hit)", [85], "hand.hit.hit")]),
			new GpifInstrumentElement("Claves", "claves", "Claves-Percu", [GpifInstrumentArticulation.template("Claves (hit)", [75], "stick.hit.hit")]),
			new GpifInstrumentElement("Left Maraca", "maraca", "Maracas-Percu", [GpifInstrumentArticulation.template("Left Maraca (hit)", [70], "hand.hit.hit"), GpifInstrumentArticulation.template("Left Maraca (return)", [118], "hand.hit.return")]),
			new GpifInstrumentElement("Right Maraca", "maraca", "Maracas-Percu", [GpifInstrumentArticulation.template("Right Maraca (hit)", [119], "hand.hit.hit"), GpifInstrumentArticulation.template("Right Maraca (return)", [120], "hand.hit.return")]),
			new GpifInstrumentElement("Shaker", "shaker", "ShakerStudio-Percu", [GpifInstrumentArticulation.template("Shaker (hit)", [82], "hand.hit.hit"), GpifInstrumentArticulation.template("Shaker (return)", [122], "hand.hit.return")]),
			new GpifInstrumentElement("Bell Tree", "bellTree", "BellTree-Percu", [GpifInstrumentArticulation.template("Bell Tree (hit)", [84], "stick.hit.hit"), GpifInstrumentArticulation.template("Bell Tree (return)", [123], "stick.hit.return")]),
			new GpifInstrumentElement("Jingle Bell", "jingleBell", "JingleBell-Percu", [GpifInstrumentArticulation.template("Jingle Bell (hit)", [83], "stick.hit.hit")]),
			new GpifInstrumentElement("Tinkle Bell", "jingleBell", "JingleBell-Percu", [GpifInstrumentArticulation.template("Tinkle Bell (hit)", [83], "stick.hit.hit")]),
			new GpifInstrumentElement("Golpe", "unpitched", "Golpe-Percu", [GpifInstrumentArticulation.template("Golpe (thumb)", [124], "thumb.hit.body"), GpifInstrumentArticulation.template("Golpe (finger)", [125], "finger4.hit.body")]),
			new GpifInstrumentElement("Hand Clap", "handClap", "GroupHandClap-Percu", [GpifInstrumentArticulation.template("Hand Clap (hit)", [39], "hand.hit.hit")]),
			new GpifInstrumentElement("Electric Snare", "snare", "ElectricSnare-Percu", [GpifInstrumentArticulation.template("Electric Snare (hit)", [40], "stick.hit.hit")]),
			new GpifInstrumentElement("Sticks", "snare", "Stick-Percu", [GpifInstrumentArticulation.template("Snare (side stick)", [31], "stick.hit.sidestick")]),
			new GpifInstrumentElement("Very Low Floor Tom", "tom", "LowFloorTom-Percu", [GpifInstrumentArticulation.template("Low Floor Tom (hit)", [41], "stick.hit.hit")]),
			new GpifInstrumentElement("Ride Cymbal 2", "ride", "Ride-Percu", [
				GpifInstrumentArticulation.template("Ride (edge)", [59], "stick.hit.edge"),
				GpifInstrumentArticulation.template("Ride (middle)", [126], "stick.hit.mid"),
				GpifInstrumentArticulation.template("Ride (bell)", [127], "stick.hit.bell"),
				GpifInstrumentArticulation.template("Ride (choke)", [29], "stick.hit.choke")
			]),
			new GpifInstrumentElement("Reverse Cymbal", "crash", "Reverse-Cymbal", [GpifInstrumentArticulation.template("Reverse Cymbal (hit)", [30], "stick.hit.hit")]),
			new GpifInstrumentElement("Metronome", "snare", "Metronome-Percu", [GpifInstrumentArticulation.template("Metronome (hit)", [33], "stick.hit.sidestick"), GpifInstrumentArticulation.template("Metronome (bell)", [34], "stick.hit.hit")])
		]);
		static _elementByArticulation = void 0;
		static _articulationsById = void 0;
		static _initLookups() {
			const set = GpifSoundMapper._drumInstrumentSet;
			const elementByArticulation = /* @__PURE__ */ new Map();
			const articulationsById = /* @__PURE__ */ new Map();
			for (const element of set.elements) for (const articulation of element.articulations) for (const midi of articulation.inputMidiNumbers) {
				const gpId = `${element.name}.${midi}`;
				elementByArticulation.set(gpId, element);
				articulationsById.set(gpId, articulation);
			}
			GpifSoundMapper._elementByArticulation = elementByArticulation;
			GpifSoundMapper._articulationsById = articulationsById;
			return elementByArticulation;
		}
		static getIconId(playbackInfo) {
			if (playbackInfo.primaryChannel === 9) return 18;
			if (GpifSoundMapper._midiProgramInfoLookup.has(playbackInfo.program)) return GpifSoundMapper._midiProgramInfoLookup.get(playbackInfo.program).icon;
			return 1;
		}
		static buildInstrumentSet(track) {
			if (track.percussionArticulations.length > 0 || track.isPercussion) return GpifSoundMapper._buildPercussionInstrumentSet(track);
			else return GpifSoundMapper._buildPitchedInstrumentSet(track);
		}
		static _pitchedElement = new GpifInstrumentElement("Pitched", "pitched", "", [new GpifInstrumentArticulation("", 0, [
			MusicFontSymbol.NoteheadBlack,
			MusicFontSymbol.NoteheadHalf,
			MusicFontSymbol.NoteheadWhole
		], MusicFontSymbol.None, TechniqueSymbolPlacement.Outside, [], 0, "")]);
		static _buildPitchedInstrumentSet(track) {
			const instrumentSet = new GpifInstrumentSet();
			instrumentSet.lineCount = track.staves[0].standardNotationLineCount;
			const programInfo = GpifSoundMapper._midiProgramInfoLookup.has(track.playbackInfo.program) ? GpifSoundMapper._midiProgramInfoLookup.get(track.playbackInfo.program) : GpifSoundMapper._midiProgramInfoLookup.get(0);
			instrumentSet.name = programInfo.instrumentSetName;
			instrumentSet.type = programInfo.instrumentSetType;
			const element = new GpifInstrumentElement(GpifSoundMapper._pitchedElement.name, GpifSoundMapper._pitchedElement.type, GpifSoundMapper._pitchedElement.soundbankName, [GpifSoundMapper._pitchedElement.articulations[0]]);
			instrumentSet.elements.push(element);
			return instrumentSet;
		}
		static _buildPercussionInstrumentSet(track) {
			if (!GpifSoundMapper._elementByArticulation) GpifSoundMapper._initLookups();
			const instrumentSet = new GpifInstrumentSet();
			instrumentSet.lineCount = track.staves[0].standardNotationLineCount;
			instrumentSet.name = "Drums";
			instrumentSet.type = "drumKit";
			const articulations = track.percussionArticulations.length > 0 ? track.percussionArticulations : Array.from(PercussionMapper.instrumentArticulations.values());
			let element = void 0;
			for (const articulation of articulations) {
				const gpifArticulation = new GpifInstrumentArticulation(articulation.elementType, articulation.staffLine, [
					articulation.noteHeadDefault,
					articulation.noteHeadHalf,
					articulation.noteHeadWhole
				], articulation.techniqueSymbol, articulation.techniqueSymbolPlacement, [articulation.id], articulation.outputMidiNumber, "");
				const gpId = articulation.uniqueId;
				if (GpifSoundMapper._articulationsById.has(gpId)) {
					const knownArticulation = GpifSoundMapper._articulationsById.get(gpId);
					gpifArticulation.inputMidiNumbers = knownArticulation.inputMidiNumbers;
					gpifArticulation.name = knownArticulation.name;
					gpifArticulation.outputRSESound = knownArticulation.outputRSESound;
				}
				if (GpifSoundMapper._elementByArticulation.has(gpId)) {
					const knownElement = GpifSoundMapper._elementByArticulation.get(gpId);
					if (!element || element.name !== articulation.elementType) {
						element = new GpifInstrumentElement(knownElement.name, knownElement.type, knownElement.soundbankName, []);
						instrumentSet.elements.push(element);
					}
				} else if (!element || element.name !== articulation.elementType) {
					element = new GpifInstrumentElement(articulation.elementType, articulation.elementType, "", []);
					instrumentSet.elements.push(element);
				}
				element.articulations.push(gpifArticulation);
			}
			return instrumentSet;
		}
	};
	//#endregion
	//#region src/exporter/GpifWriter.ts
	/**
	* This class can write a score.gpif XML from a given score model.
	* @internal
	*/
	var GpifWriter = class GpifWriter {
		static _sampleRate = 44100;
		_rhythmIdLookup = /* @__PURE__ */ new Map();
		writeXml(score) {
			const xmlDocument = new XmlDocument();
			this._rhythmIdLookup = /* @__PURE__ */ new Map();
			this._writeDom(xmlDocument, score);
			return xmlDocument.toFormattedString("", true);
		}
		_writeDom(parent, score) {
			const gpif = parent.addElement("GPIF");
			gpif.addElement("GPVersion").innerText = "8.1.3";
			const gpRevision = gpif.addElement("GPRevision");
			gpRevision.attributes.set("required", "12024");
			gpRevision.attributes.set("recommended", "13000");
			gpRevision.innerText = "13007";
			const encoding = gpif.addElement("Encoding");
			encoding.addElement("EncodingDescription").innerText = "GP8";
			const alphaTabComment = new XmlNode();
			alphaTabComment.nodeType = XmlNodeType.Comment;
			alphaTabComment.value = `Written by alphaTab ${VersionInfo.version} (${VersionInfo.commit})`;
			encoding.addChild(alphaTabComment);
			this._writeScoreNode(gpif, score);
			this._writeMasterTrackNode(gpif, score);
			this._writeBackingTrackNode(gpif, score);
			this._writeAudioTracksNode(gpif, score);
			this._writeTracksNode(gpif, score);
			this._writeMasterBarsNode(gpif, score);
			this._writeAssets(gpif, score);
			const bars = gpif.addElement("Bars");
			const voices = gpif.addElement("Voices");
			const beats = gpif.addElement("Beats");
			const notes = gpif.addElement("Notes");
			const rhythms = gpif.addElement("Rhythms");
			for (const tracks of score.tracks) for (const staff of tracks.staves) for (const bar of staff.bars) {
				this._writeBarNode(bars, bar);
				for (const voice of bar.voices) {
					this._writeVoiceNode(voices, voice);
					for (const beat of voice.beats) {
						this._writeBeatNode(beats, beat, rhythms);
						for (const note of beat.notes) this._writeNoteNode(notes, note);
					}
				}
			}
		}
		_writeAssets(parent, score) {
			if (!score.backingTrack?.rawAudioFile) return;
			const asset = parent.addElement("Assets").addElement("Asset");
			asset.attributes.set("id", this._backingTrackAssetId);
			this.backingTrackAssetFileName = "Content/Assets/backing-track";
			asset.addElement("EmbeddedFilePath").setCData(this.backingTrackAssetFileName);
		}
		_backingTrackAssetId;
		_backingTrackFramePadding;
		backingTrackAssetFileName;
		_writeBackingTrackNode(parent, score) {
			if (!score.backingTrack?.rawAudioFile) return;
			const backingTrackNode = parent.addElement("BackingTrack");
			const backingTrackAssetId = "0";
			this._backingTrackAssetId = backingTrackAssetId;
			backingTrackNode.addElement("IconId").innerText = "21";
			backingTrackNode.addElement("Color").innerText = "0 0 0";
			backingTrackNode.addElement("Name").setCData("Audio Track");
			backingTrackNode.addElement("ShortName").setCData("a.track");
			backingTrackNode.addElement("PlaybackState").innerText = "Default";
			backingTrackNode.addElement("Enabled").innerText = "true";
			backingTrackNode.addElement("Source").innerText = "Local";
			backingTrackNode.addElement("AssetId").innerText = backingTrackAssetId;
			const channelStrip = backingTrackNode.addElement("ChannelStrip");
			channelStrip.addElement("Parameters").innerText = "0.500000 0.500000 0.500000 0.500000 0.500000 0.500000 0.500000 0.500000 0.500000 0.000000 0.500000 0.500000 0.800000 0.500000 0.500000 0.500000";
			channelStrip.addElement("YouTubeVideoUrl").innerText = "";
			channelStrip.addElement("Filter").innerText = "6";
			channelStrip.addElement("FramesPerPixel").innerText = "400";
			const framePadding = this._backingTrackFramePadding !== void 0 ? this._backingTrackFramePadding : 0;
			backingTrackNode.addElement("FramePadding").innerText = `${framePadding}`;
			backingTrackNode.addElement("Semitones").innerText = "0";
			backingTrackNode.addElement("Cents").innerText = "0";
		}
		_writeNoteNode(parent, note) {
			const noteNode = parent.addElement("Note");
			noteNode.attributes.set("id", note.id.toString());
			this._writeNoteProperties(noteNode, note);
			if (note.isGhost) noteNode.addElement("AntiAccent").innerText = "normal";
			if (note.isLetRing) noteNode.addElement("LetRing");
			if (note.isTrill) noteNode.addElement("Trill").innerText = note.trillValue.toString();
			let accentFlags = 0;
			if (note.isStaccato) accentFlags |= 1;
			switch (note.accentuated) {
				case AccentuationType.Normal:
					accentFlags |= 8;
					break;
				case AccentuationType.Heavy:
					accentFlags |= 4;
					break;
				case AccentuationType.Tenuto:
					accentFlags |= 16;
					break;
			}
			if (accentFlags > 0) noteNode.addElement("Accent").innerText = accentFlags.toString();
			if (note.isTieOrigin || note.isTieDestination) {
				const tie = noteNode.addElement("Tie");
				tie.attributes.set("origin", note.isTieOrigin ? "true" : "false");
				tie.attributes.set("destination", note.isTieDestination ? "true" : "false");
			}
			switch (note.vibrato) {
				case VibratoType.Slight:
					noteNode.addElement("Vibrato").innerText = "Slight";
					break;
				case VibratoType.Wide:
					noteNode.addElement("Vibrato").innerText = "Wide";
					break;
			}
			if (note.isFingering) {
				switch (note.leftHandFinger) {
					case Fingers.Thumb:
						noteNode.addElement("LeftFingering").innerText = "P";
						break;
					case Fingers.IndexFinger:
						noteNode.addElement("LeftFingering").innerText = "I";
						break;
					case Fingers.MiddleFinger:
						noteNode.addElement("LeftFingering").innerText = "M";
						break;
					case Fingers.AnnularFinger:
						noteNode.addElement("LeftFingering").innerText = "A";
						break;
					case Fingers.LittleFinger:
						noteNode.addElement("LeftFingering").innerText = "C";
						break;
				}
				switch (note.rightHandFinger) {
					case Fingers.Thumb:
						noteNode.addElement("RightFingering").innerText = "P";
						break;
					case Fingers.IndexFinger:
						noteNode.addElement("RightFingering").innerText = "I";
						break;
					case Fingers.MiddleFinger:
						noteNode.addElement("RightFingering").innerText = "M";
						break;
					case Fingers.AnnularFinger:
						noteNode.addElement("RightFingering").innerText = "A";
						break;
					case Fingers.LittleFinger:
						noteNode.addElement("RightFingering").innerText = "C";
						break;
				}
			}
			if (note.percussionArticulation >= 0) noteNode.addElement("InstrumentArticulation").innerText = note.percussionArticulation.toString();
			else noteNode.addElement("InstrumentArticulation").innerText = "0";
			if (note.ornament !== NoteOrnament.None) noteNode.addElement("Ornament").innerText = NoteOrnament[note.ornament];
		}
		_writeNoteProperties(parent, note) {
			const properties = parent.addElement("Properties");
			this._writeConcertPitch(properties, note);
			this._writeTransposedPitch(properties, note);
			if (note.isStringed) {
				this._writeSimplePropertyNode(properties, "String", "String", (note.string - 1).toString());
				this._writeSimplePropertyNode(properties, "Fret", "Fret", note.fret.toString());
				this._writeSimplePropertyNode(properties, "Midi", "Number", note.realValue.toString());
				if (note.showStringNumber) this._writeSimplePropertyNode(properties, "ShowStringNumber", "Enable", null);
			}
			if (note.isPiano) {
				this._writeSimplePropertyNode(properties, "Octave", "Number", note.octave.toString());
				this._writeSimplePropertyNode(properties, "Tone", "Step", note.tone.toString());
				this._writeSimplePropertyNode(properties, "Midi", "Number", note.realValue.toString());
			}
			if (note.beat.tap) this._writeSimplePropertyNode(properties, "Tapped", "Enable", null);
			if (note.harmonicType !== HarmonicType.None) {
				switch (note.harmonicType) {
					case HarmonicType.Natural:
						this._writeSimplePropertyNode(properties, "HarmonicType", "HType", "Natural");
						break;
					case HarmonicType.Artificial:
						this._writeSimplePropertyNode(properties, "HarmonicType", "HType", "Artificial");
						break;
					case HarmonicType.Pinch:
						this._writeSimplePropertyNode(properties, "HarmonicType", "HType", "Pinch");
						break;
					case HarmonicType.Tap:
						this._writeSimplePropertyNode(properties, "HarmonicType", "HType", "Tap");
						break;
					case HarmonicType.Semi:
						this._writeSimplePropertyNode(properties, "HarmonicType", "HType", "Semi");
						break;
					case HarmonicType.Feedback:
						this._writeSimplePropertyNode(properties, "HarmonicType", "HType", "Feedback");
						break;
				}
				if (note.harmonicValue !== 0) this._writeSimplePropertyNode(properties, "HarmonicFret", "HFret", note.harmonicValue.toString());
			}
			if (note.isDead) this._writeSimplePropertyNode(properties, "Muted", "Enable", null);
			if (note.isPalmMute) this._writeSimplePropertyNode(properties, "PalmMuted", "Enable", null);
			if (note.hasBend) this._writeBend(properties, note);
			if (note.isHammerPullOrigin) this._writeSimplePropertyNode(properties, "HopoOrigin", "Enable", null);
			if (note.isHammerPullDestination) this._writeSimplePropertyNode(properties, "HopoDestination", "Enable", null);
			if (note.isLeftHandTapped) this._writeSimplePropertyNode(properties, "LeftHandTapped", "Enable", null);
			let slideFlags = 0;
			switch (note.slideInType) {
				case SlideInType.IntoFromAbove:
					slideFlags |= 32;
					break;
				case SlideInType.IntoFromBelow:
					slideFlags |= 16;
					break;
			}
			switch (note.slideOutType) {
				case SlideOutType.Shift:
					slideFlags |= 1;
					break;
				case SlideOutType.Legato:
					slideFlags |= 2;
					break;
				case SlideOutType.OutDown:
					slideFlags |= 4;
					break;
				case SlideOutType.OutUp:
					slideFlags |= 8;
					break;
				case SlideOutType.PickSlideDown:
					slideFlags |= 64;
					break;
				case SlideOutType.PickSlideUp:
					slideFlags |= 128;
					break;
			}
			if (slideFlags > 0) this._writeSimplePropertyNode(properties, "Slide", "Flags", slideFlags.toString());
		}
		_writeTransposedPitch(properties, note) {
			if (note.isPercussion) this._writePitch(properties, "ConcertPitch", "C", "-1", "");
			else this._writePitchForValue(properties, "TransposedPitch", note.displayValueWithoutBend, note.accidentalMode, note.beat.voice.bar.keySignature);
		}
		_writeConcertPitch(properties, note) {
			if (note.isPercussion) this._writePitch(properties, "ConcertPitch", "C", "-1", "");
			else this._writePitchForValue(properties, "ConcertPitch", note.realValueWithoutHarmonic, note.accidentalMode, note.beat.voice.bar.keySignature);
		}
		static _defaultSteps = [
			"C",
			"C",
			"D",
			"D",
			"E",
			"F",
			"F",
			"G",
			"G",
			"A",
			"A",
			"B"
		];
		_writePitchForValue(properties, propertyName, value, accidentalMode, keySignature) {
			let index = 0;
			let octave = 0;
			let step = "";
			let accidental = "";
			const updateParts = () => {
				index = value % 12;
				octave = value / 12 | 0;
				step = GpifWriter._defaultSteps[index];
				switch (ModelUtils.computeAccidental(keySignature, NoteAccidentalMode.Default, value, false)) {
					case AccidentalType.None:
					case AccidentalType.Natural:
						accidental = "";
						break;
					case AccidentalType.Sharp:
						accidental = "#";
						break;
					case AccidentalType.Flat:
						accidental = "b";
						break;
					case AccidentalType.DoubleSharp:
						accidental = "x";
						break;
					case AccidentalType.DoubleFlat:
						accidental = "bb";
						break;
				}
			};
			updateParts();
			switch (accidentalMode) {
				case NoteAccidentalMode.Default: break;
				case NoteAccidentalMode.ForceNone:
					accidental = "";
					break;
				case NoteAccidentalMode.ForceNatural:
					accidental = "";
					break;
				case NoteAccidentalMode.ForceSharp:
					accidental = "#";
					break;
				case NoteAccidentalMode.ForceDoubleSharp:
					if (accidental === "#") {
						value -= 2;
						updateParts();
					}
					accidental = "x";
					break;
				case NoteAccidentalMode.ForceFlat:
					if (accidental === "#") {
						value += 1;
						updateParts();
					}
					accidental = "b";
					break;
				case NoteAccidentalMode.ForceDoubleFlat:
					if (accidental === "#") {
						value += 2;
						updateParts();
					}
					accidental = "bb";
					break;
			}
			this._writePitch(properties, propertyName, step, octave.toString(), accidental);
		}
		_writePitch(properties, propertyName, step, octave, accidental) {
			const property = properties.addElement("Property");
			property.attributes.set("name", propertyName);
			const pitch = property.addElement("Pitch");
			pitch.addElement("Step").innerText = step;
			pitch.addElement("Accidental").innerText = accidental;
			pitch.addElement("Octave").innerText = octave;
		}
		_writeBend(properties, note) {
			if (note.hasBend && note.bendPoints.length <= 4) this._writeStandardBend(properties, note.bendPoints);
		}
		_writeStandardBend(properties, bendPoints) {
			this._writeSimplePropertyNode(properties, "Bended", "Enable", null);
			const bendOrigin = bendPoints[0];
			const bendDestination = bendPoints[bendPoints.length - 1];
			let bendMiddle1;
			let bendMiddle2;
			switch (bendPoints.length) {
				case 4:
					bendMiddle1 = bendPoints[1];
					bendMiddle2 = bendPoints[2];
					break;
				case 3:
					bendMiddle1 = bendPoints[1];
					bendMiddle2 = bendPoints[1];
					break;
				default:
					bendMiddle1 = new BendPoint((bendOrigin.offset + bendDestination.offset) / 2, (bendOrigin.value + bendDestination.value) / 2);
					bendMiddle2 = bendMiddle1;
					break;
			}
			this._writeSimplePropertyNode(properties, "BendDestinationOffset", "Float", this._toBendOffset(bendDestination.offset).toString());
			this._writeSimplePropertyNode(properties, "BendDestinationValue", "Float", this._toBendValue(bendDestination.value).toString());
			this._writeSimplePropertyNode(properties, "BendMiddleOffset1", "Float", this._toBendOffset(bendMiddle1.offset).toString());
			this._writeSimplePropertyNode(properties, "BendMiddleOffset2", "Float", this._toBendOffset(bendMiddle2.offset).toString());
			this._writeSimplePropertyNode(properties, "BendMiddleValue", "Float", this._toBendValue(bendMiddle1.value).toString());
			this._writeSimplePropertyNode(properties, "BendOriginOffset", "Float", this._toBendOffset(bendOrigin.offset).toString());
			this._writeSimplePropertyNode(properties, "BendOriginValue", "Float", this._toBendValue(bendOrigin.value).toString());
		}
		_toBendValue(value) {
			return value * 25;
		}
		_toBendOffset(value) {
			return value / BendPoint.MaxPosition * 100;
		}
		_writeBeatNode(parent, beat, rhythms) {
			const beatNode = parent.addElement("Beat");
			beatNode.attributes.set("id", beat.id.toString());
			beatNode.addElement("Dynamic").innerText = DynamicValue[beat.dynamics];
			if (beat.fade !== FadeType.None) beatNode.addElement("Fadding").innerText = FadeType[beat.fade];
			if (beat.isTremolo) switch (beat.tremoloPicking.marks) {
				case 1:
					beatNode.addElement("Tremolo").innerText = "1/2";
					break;
				case 2:
					beatNode.addElement("Tremolo").innerText = "1/4";
					break;
				case 3:
					beatNode.addElement("Tremolo").innerText = "1/8";
					break;
			}
			if (beat.hasChord) beatNode.addElement("Chord").setCData(beat.chordId);
			if (beat.crescendo !== CrescendoType.None) beatNode.addElement("Hairpin").innerText = CrescendoType[beat.crescendo];
			switch (beat.brushType) {
				case BrushType.ArpeggioUp:
					beatNode.addElement("Arpeggio").innerText = "Up";
					break;
				case BrushType.ArpeggioDown:
					beatNode.addElement("Arpeggio").innerText = "Down";
					break;
			}
			if (beat.text) beatNode.addElement("FreeText").setCData(beat.text);
			switch (beat.graceType) {
				case GraceType.OnBeat:
				case GraceType.BeforeBeat:
					beatNode.addElement("GraceNotes").innerText = GraceType[beat.graceType];
					break;
			}
			if (beat.ottava !== Ottavia.Regular) beatNode.addElement("Ottavia").innerText = Ottavia[beat.ottava].substr(1);
			if (beat.hasWhammyBar) this._writeWhammyNode(beatNode, beat);
			if (beat.isLegatoOrigin || beat.isLegatoDestination) {
				const legato = beatNode.addElement("Legato");
				legato.attributes.set("origin", beat.isLegatoOrigin ? "true" : "false");
				legato.attributes.set("destination", beat.isLegatoDestination ? "true" : "false");
			}
			this._writeRhythm(beatNode, beat, rhythms);
			if (beat.preferredBeamDirection !== null) switch (beat.preferredBeamDirection) {
				case BeamDirection.Up:
					beatNode.addElement("TransposedPitchStemOrientation").innerText = "Upward";
					beatNode.addElement("UserTransposedPitchStemOrientation").innerText = "Upward";
					break;
				case BeamDirection.Down:
					beatNode.addElement("TransposedPitchStemOrientation").innerText = "Downward";
					beatNode.addElement("UserTransposedPitchStemOrientation").innerText = "Downward";
					break;
			}
			beatNode.addElement("ConcertPitchStemOrientation").innerText = "Undefined";
			if (beat.slashed) beatNode.addElement("Slashed");
			if (beat.deadSlapped) beatNode.addElement("DeadSlapped");
			if (beat.notes.length > 0) beatNode.addElement("Notes").innerText = beat.notes.map((n) => n.id).join(" ");
			if (beat.golpe !== GolpeType.None) beatNode.addElement("Golpe").innerText = GolpeType[beat.golpe];
			if (beat.wahPedal !== WahPedal.None) beatNode.addElement("Wah").innerText = WahPedal[beat.wahPedal];
			if (beat.showTimer) beatNode.addElement("Timer").innerText = (beat.timer ?? 0).toString();
			this._writeBeatProperties(beatNode, beat);
			this._writeBeatXProperties(beatNode, beat);
			if (beat.lyrics && beat.lyrics.length > 0) this._writeBeatLyrics(beatNode, beat.lyrics);
		}
		_writeBeatLyrics(beatNode, lyrics) {
			const lyricsNode = beatNode.addElement("Lyrics");
			for (const l of lyrics) lyricsNode.addElement("Line").setCData(l);
		}
		_writeBeatXProperties(beatNode, beat) {
			const beatProperties = beatNode.addElement("XProperties");
			if (beat.brushDuration > 0) this._writeSimpleXPropertyNode(beatProperties, "687935489", "Int", beat.brushDuration.toString());
			switch (beat.beamingMode) {
				case BeatBeamingMode.ForceSplitToNext:
					this._writeSimpleXPropertyNode(beatProperties, "1124204546", "Int", "2");
					break;
				case BeatBeamingMode.ForceMergeWithNext:
					this._writeSimpleXPropertyNode(beatProperties, "1124204546", "Int", "1");
					break;
				case BeatBeamingMode.ForceSplitOnSecondaryToNext:
					this._writeSimpleXPropertyNode(beatProperties, "1124204552", "Int", "1");
					break;
			}
		}
		_writeBeatProperties(beatNode, beat) {
			const beatProperties = beatNode.addElement("Properties");
			switch (beat.brushType) {
				case BrushType.BrushUp:
					this._writeSimplePropertyNode(beatProperties, "Brush", "Direction", "Up");
					break;
				case BrushType.BrushDown:
					this._writeSimplePropertyNode(beatProperties, "Brush", "Direction", "Down");
					break;
			}
			switch (beat.pickStroke) {
				case PickStroke.Up:
					this._writeSimplePropertyNode(beatProperties, "PickStroke", "Direction", "Up");
					break;
				case PickStroke.Down:
					this._writeSimplePropertyNode(beatProperties, "PickStroke", "Direction", "Down");
					break;
			}
			if (beat.slap) this._writeSimplePropertyNode(beatProperties, "Slapped", "Enable", null);
			if (beat.pop) this._writeSimplePropertyNode(beatProperties, "Popped", "Enable", null);
			switch (beat.vibrato) {
				case VibratoType.Wide:
					this._writeSimplePropertyNode(beatProperties, "VibratoWTremBar", "Strength", "Wide");
					break;
				case VibratoType.Slight:
					this._writeSimplePropertyNode(beatProperties, "VibratoWTremBar", "Strength", "Slight");
					break;
			}
			if (beat.isBarre) {
				this._writeSimplePropertyNode(beatProperties, "BarreFret", "Fret", beat.barreFret.toString());
				switch (beat.barreShape) {
					case BarreShape.Full:
						this._writeSimplePropertyNode(beatProperties, "BarreString", "String", "0");
						break;
					case BarreShape.Half:
						this._writeSimplePropertyNode(beatProperties, "BarreString", "String", "1");
						break;
				}
			}
			if (beat.rasgueado !== Rasgueado.None) {
				let rasgueado = "";
				switch (beat.rasgueado) {
					case Rasgueado.Ii:
						rasgueado = "ii_1";
						break;
					case Rasgueado.Mi:
						rasgueado = "mi_1";
						break;
					case Rasgueado.MiiTriplet:
						rasgueado = "mii_1";
						break;
					case Rasgueado.MiiAnapaest:
						rasgueado = "mii_2";
						break;
					case Rasgueado.PmpTriplet:
						rasgueado = "pmp_1";
						break;
					case Rasgueado.PmpAnapaest:
						rasgueado = "pmp_2";
						break;
					case Rasgueado.PeiTriplet:
						rasgueado = "pei_1";
						break;
					case Rasgueado.PeiAnapaest:
						rasgueado = "pei_2";
						break;
					case Rasgueado.PaiTriplet:
						rasgueado = "pai_1";
						break;
					case Rasgueado.PaiAnapaest:
						rasgueado = "pai_2";
						break;
					case Rasgueado.AmiTriplet:
						rasgueado = "ami_1";
						break;
					case Rasgueado.AmiAnapaest:
						rasgueado = "ami_2";
						break;
					case Rasgueado.Ppp:
						rasgueado = "ppp_1";
						break;
					case Rasgueado.Amii:
						rasgueado = "amii_1";
						break;
					case Rasgueado.Amip:
						rasgueado = "amip_1";
						break;
					case Rasgueado.Eami:
						rasgueado = "eami_1";
						break;
					case Rasgueado.Eamii:
						rasgueado = "eamii_1";
						break;
					case Rasgueado.Peami:
						rasgueado = "peami_1";
						break;
				}
				this._writeSimplePropertyNode(beatProperties, "Rasgueado", "Rasgueado", rasgueado);
			}
		}
		_writeRhythm(parent, beat, rhythms) {
			const rhythmId = `${beat.duration}_${beat.dots}_${beat.tupletNumerator}_${beat.tupletDenominator}';`;
			let rhythm;
			if (!this._rhythmIdLookup.has(rhythmId)) {
				rhythm = this._rhythmIdLookup.size.toString();
				this._rhythmIdLookup.set(rhythmId, rhythm);
				const rhythmNode = rhythms.addElement("Rhythm");
				rhythmNode.attributes.set("id", rhythm);
				if (beat.hasTuplet) {
					const tupletNode = rhythmNode.addElement("PrimaryTuplet");
					tupletNode.attributes.set("num", beat.tupletNumerator.toString());
					tupletNode.attributes.set("den", beat.tupletDenominator.toString());
				}
				if (beat.dots > 0) rhythmNode.addElement("AugmentationDot").attributes.set("count", beat.dots.toString());
				let noteValue = "Quarter";
				switch (beat.duration) {
					case Duration.QuadrupleWhole:
						noteValue = "Long";
						break;
					case Duration.DoubleWhole:
						noteValue = "DoubleWhole";
						break;
					case Duration.Whole:
						noteValue = "Whole";
						break;
					case Duration.Half:
						noteValue = "Half";
						break;
					case Duration.Quarter:
						noteValue = "Quarter";
						break;
					case Duration.Eighth:
						noteValue = "Eighth";
						break;
					case Duration.Sixteenth:
						noteValue = "16th";
						break;
					case Duration.ThirtySecond:
						noteValue = "32nd";
						break;
					case Duration.SixtyFourth:
						noteValue = "64th";
						break;
					case Duration.OneHundredTwentyEighth:
						noteValue = "128th";
						break;
					case Duration.TwoHundredFiftySixth:
						noteValue = "256th";
						break;
				}
				rhythmNode.addElement("NoteValue").innerText = noteValue;
			} else rhythm = this._rhythmIdLookup.get(rhythmId);
			parent.addElement("Rhythm").attributes.set("ref", rhythm);
		}
		_writeWhammyNode(parent, beat) {
			if (beat.hasWhammyBar && beat.whammyBarPoints.length <= 4) this._writeStandardWhammy(parent, beat.whammyBarPoints);
		}
		_writeStandardWhammy(parent, whammyBarPoints) {
			const whammyNode = parent.addElement("Whammy");
			const whammyOrigin = whammyBarPoints[0];
			const whammyDestination = whammyBarPoints[whammyBarPoints.length - 1];
			let whammyMiddle1;
			let whammyMiddle2;
			switch (whammyBarPoints.length) {
				case 4:
					whammyMiddle1 = whammyBarPoints[1];
					whammyMiddle2 = whammyBarPoints[2];
					break;
				case 3:
					whammyMiddle1 = whammyBarPoints[1];
					whammyMiddle2 = whammyBarPoints[1];
					break;
				default:
					whammyMiddle1 = new BendPoint((whammyOrigin.offset + whammyDestination.offset) / 2, (whammyOrigin.value + whammyDestination.value) / 2);
					whammyMiddle2 = whammyMiddle1;
					break;
			}
			whammyNode.attributes.set("destinationOffset", this._toBendOffset(whammyDestination.offset).toString());
			whammyNode.attributes.set("destinationValue", this._toBendValue(whammyDestination.value).toString());
			whammyNode.attributes.set("middleOffset1", this._toBendOffset(whammyMiddle1.offset).toString());
			whammyNode.attributes.set("middleOffset2", this._toBendOffset(whammyMiddle2.offset).toString());
			whammyNode.attributes.set("middleValue", this._toBendValue(whammyMiddle1.value).toString());
			whammyNode.attributes.set("originOffset", this._toBendOffset(whammyOrigin.offset).toString());
			whammyNode.attributes.set("originValue", this._toBendValue(whammyOrigin.value).toString());
		}
		_writeScoreNode(parent, score) {
			const scoreNode = parent.addElement("Score");
			scoreNode.addElement("Title").setCData(score.title);
			scoreNode.addElement("SubTitle").setCData(score.subTitle);
			scoreNode.addElement("Artist").setCData(score.artist);
			scoreNode.addElement("Album").setCData(score.album);
			scoreNode.addElement("Words").setCData(score.words);
			scoreNode.addElement("Music").setCData(score.music);
			scoreNode.addElement("WordsAndMusic").setCData(score.words === score.music ? score.words : "");
			scoreNode.addElement("Copyright").setCData(score.copyright);
			scoreNode.addElement("Tabber").setCData(score.tab);
			scoreNode.addElement("Instructions").setCData(score.instructions);
			scoreNode.addElement("Notices").setCData(score.notices);
			scoreNode.addElement("FirstPageHeader").setCData("");
			scoreNode.addElement("FirstPageFooter").setCData("");
			scoreNode.addElement("PageHeader").setCData("");
			scoreNode.addElement("PageFooter").setCData("");
			scoreNode.addElement("ScoreSystemsDefaultLayout").setCData(score.defaultSystemsLayout.toString());
			scoreNode.addElement("ScoreSystemsLayout").setCData(score.systemsLayout.join(" "));
			scoreNode.addElement("ScoreZoomPolicy").innerText = "Value";
			scoreNode.addElement("ScoreZoom").innerText = "1";
			scoreNode.addElement("MultiVoice").innerText = "1>";
		}
		_writeMasterTrackNode(parent, score) {
			const masterTrackNode = parent.addElement("MasterTrack");
			masterTrackNode.addElement("Tracks").innerText = score.tracks.map((t) => t.index).join(" ");
			const automations = masterTrackNode.addElement("Automations");
			if (score.masterBars.length > 0 && score.masterBars[0].isAnacrusis) masterTrackNode.addElement("Anacrusis");
			if (score.masterBars[0].tempoAutomations.length === 0) {
				const initialTempoAutomation = automations.addElement("Automation");
				initialTempoAutomation.addElement("Type").innerText = "Tempo";
				initialTempoAutomation.addElement("Linear").innerText = "false";
				initialTempoAutomation.addElement("Bar").innerText = "0";
				initialTempoAutomation.addElement("Position").innerText = "0";
				initialTempoAutomation.addElement("Visible").innerText = "true";
				initialTempoAutomation.addElement("Value").innerText = `${score.tempo} 2`;
				if (score.tempoLabel) initialTempoAutomation.addElement("Text").innerText = score.tempoLabel;
			}
			const initialSyncPoint = score.masterBars[0].syncPoints ? score.masterBars[0].syncPoints.find((p) => p.ratioPosition === 0 && p.syncPointValue.barOccurence === 0) : void 0;
			const millisecondPadding = initialSyncPoint ? initialSyncPoint.syncPointValue.millisecondOffset : 0;
			this._backingTrackFramePadding = -1 * (millisecondPadding / 1e3 * GpifWriter._sampleRate) | 0;
			const modifiedTempoLookup = new Lazy(() => MidiFileGenerator.buildModifiedTempoLookup(score));
			for (const mb of score.masterBars) {
				for (const automation of mb.tempoAutomations) {
					const tempoAutomation = automations.addElement("Automation");
					tempoAutomation.addElement("Type").innerText = "Tempo";
					tempoAutomation.addElement("Linear").innerText = automation.isLinear ? "true" : "false";
					tempoAutomation.addElement("Bar").innerText = mb.index.toString();
					tempoAutomation.addElement("Position").innerText = automation.ratioPosition.toString();
					tempoAutomation.addElement("Visible").innerText = automation.isVisible ? "true" : "false";
					tempoAutomation.addElement("Value").innerText = `${automation.value} 2`;
					if (automation.text) tempoAutomation.addElement("Text").innerText = automation.text;
				}
				if (mb.syncPoints) for (const syncPoint of mb.syncPoints) {
					const syncPointAutomation = automations.addElement("Automation");
					syncPointAutomation.addElement("Type").innerText = "SyncPoint";
					syncPointAutomation.addElement("Linear").innerText = "false";
					syncPointAutomation.addElement("Bar").innerText = mb.index.toString();
					syncPointAutomation.addElement("Position").innerText = syncPoint.ratioPosition.toString();
					syncPointAutomation.addElement("Visible").innerText = syncPoint.isVisible ? "true" : "false";
					const value = syncPointAutomation.addElement("Value");
					value.addElement("BarIndex").innerText = mb.index.toString();
					value.addElement("BarOccurrence").innerText = syncPoint.syncPointValue.barOccurence.toString();
					value.addElement("ModifiedTempo").innerText = modifiedTempoLookup.value.get(syncPoint).syncBpm.toString();
					value.addElement("OriginalTempo").innerText = score.tempo.toString();
					let frameOffset = (syncPoint.syncPointValue.millisecondOffset - millisecondPadding) / 1e3 * GpifWriter._sampleRate;
					frameOffset = Math.floor(frameOffset + .5);
					value.addElement("FrameOffset").innerText = frameOffset.toString();
				}
			}
		}
		_writeAudioTracksNode(parent, _score) {
			parent.addElement("AudioTracks");
		}
		_writeTracksNode(parent, score) {
			const tracksNode = parent.addElement("Tracks");
			for (const track of score.tracks) this._writeTrackNode(tracksNode, track);
		}
		_writeTrackNode(parent, track) {
			const trackNode = parent.addElement("Track");
			trackNode.attributes.set("id", track.index.toString());
			trackNode.addElement("Name").setCData(track.name);
			trackNode.addElement("ShortName").setCData(track.shortName);
			trackNode.addElement("Color").innerText = `${track.color.r} ${track.color.g} ${track.color.b}`;
			trackNode.addElement("SystemsDefautLayout").innerText = track.defaultSystemsLayout.toString();
			trackNode.addElement("SystemsLayout").innerText = track.systemsLayout.join(" ");
			trackNode.addElement("AutoBrush");
			trackNode.addElement("PalmMute").innerText = "0";
			trackNode.addElement("PlayingStyle").innerText = GeneralMidi.isGuitar(track.playbackInfo.program) ? "StringedPick" : "Default";
			trackNode.addElement("UseOneChannelPerString");
			trackNode.addElement("IconId").innerText = GpifSoundMapper.getIconId(track.playbackInfo).toString();
			this._writeInstrumentSetNode(trackNode, track);
			this._writeTransposeNode(trackNode, track);
			this._writeRseNode(trackNode, track);
			trackNode.addElement("ForcedSound").innerText = "-1";
			this._writeMidiConnectionNode(trackNode, track);
			if (track.playbackInfo.isSolo) trackNode.addElement("PlaybackState").innerText = "Solo";
			else if (track.playbackInfo.isMute) trackNode.addElement("PlaybackState").innerText = "Mute";
			else trackNode.addElement("PlaybackState").innerText = "Default";
			trackNode.addElement("AudioEngineState").innerText = "MIDI";
			this._writeLyricsNode(trackNode, track);
			this._writeStavesNode(trackNode, track);
			this._writeSoundsAndAutomations(trackNode, track);
		}
		_writeSoundAndAutomation(soundsNode, automationsNode, name, path, role, barIndex, program, bank, ratioPosition = 0) {
			const soundNode = soundsNode.addElement("Sound");
			soundNode.addElement("Name").setCData(name);
			soundNode.addElement("Label").setCData(name);
			soundNode.addElement("Path").setCData(path);
			soundNode.addElement("Role").setCData(role);
			const midi = soundNode.addElement("MIDI");
			const lsbMsb = GeneralMidi.bankToLsbMsb(bank);
			midi.addElement("LSB").innerText = lsbMsb[0].toString();
			midi.addElement("MSB").innerText = lsbMsb[1].toString();
			midi.addElement("Program").innerText = program.toString();
			const automationNode = automationsNode.addElement("Automation");
			automationNode.addElement("Type").innerText = "Sound";
			automationNode.addElement("Linear").innerText = "false";
			automationNode.addElement("Bar").innerText = barIndex.toString();
			automationNode.addElement("Position").innerText = ratioPosition.toString();
			automationNode.addElement("Visible").innerText = "true";
			automationNode.addElement("Value").setCData(`${path};${name};${role}`);
		}
		_writeSoundsAndAutomations(trackNode, track) {
			const soundsNode = trackNode.addElement("Sounds");
			const automationsNode = trackNode.addElement("Automations");
			if (track.staves.length > 0 && track.staves[0].bars.length > 0) {
				const trackSoundName = `Track_${track.index}_Initial`;
				const trackSoundPath = `Midi/${track.playbackInfo.program}`;
				const trackSoundRole = "Factory";
				let trackSoundWritten = false;
				let bank = track.playbackInfo.bank;
				for (const staff of track.staves) for (const bar of staff.bars) for (const voice of bar.voices) for (const beat of voice.beats) {
					const soundAutomation = beat.getAutomation(AutomationType.Instrument);
					const isTrackSound = bar.index === 0 && beat.index === 0;
					const bankAutomation = beat.getAutomation(AutomationType.Bank);
					if (bankAutomation) bank = bankAutomation.value;
					if (soundAutomation) {
						const name = isTrackSound ? trackSoundName : `ProgramChange_${beat.id}`;
						const path = isTrackSound ? trackSoundPath : `Midi/${soundAutomation.value}`;
						const role = isTrackSound ? trackSoundRole : "User";
						if (!isTrackSound && !trackSoundWritten) {
							this._writeSoundAndAutomation(soundsNode, automationsNode, trackSoundName, trackSoundPath, trackSoundRole, track.staves[0].bars[0].index, track.playbackInfo.program, track.playbackInfo.bank);
							trackSoundWritten = true;
						}
						this._writeSoundAndAutomation(soundsNode, automationsNode, name, path, role, bar.index, soundAutomation.value, bank, soundAutomation.ratioPosition);
						if (isTrackSound) trackSoundWritten = true;
					}
				}
			}
			for (const s of track.staves) for (const b of s.bars) for (const sustainPedal of b.sustainPedals) if (sustainPedal.pedalType !== SustainPedalMarkerType.Hold) {
				const automation = automationsNode.addElement("Automation");
				automation.addElement("Type").innerText = "SustainPedal";
				automation.addElement("Linear").innerText = "false";
				automation.addElement("Bar").innerText = b.index.toString();
				automation.addElement("Position").innerText = sustainPedal.ratioPosition.toString();
				automation.addElement("Visible").innerText = "true";
				switch (sustainPedal.pedalType) {
					case SustainPedalMarkerType.Down:
						automation.addElement("Value").innerText = "0 1";
						break;
					case SustainPedalMarkerType.Up:
						automation.addElement("Value").innerText = "0 3";
						break;
				}
			}
		}
		_writeMidiConnectionNode(trackNode, track) {
			const midiConnection = trackNode.addElement("MidiConnection");
			midiConnection.addElement("Port").innerText = track.playbackInfo.port.toString();
			midiConnection.addElement("PrimaryChannel").innerText = track.playbackInfo.primaryChannel.toString();
			midiConnection.addElement("SecondaryChannel").innerText = track.playbackInfo.secondaryChannel.toString();
			midiConnection.addElement("ForeOneChannelPerString").innerText = "false";
		}
		_writeRseNode(trackNode, track) {
			const channelStrip = trackNode.addElement("RSE").addElement("ChannelStrip");
			channelStrip.attributes.set("version", "E56");
			const channelStripParameters = channelStrip.addElement("Parameters");
			channelStripParameters.innerText = `0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 1 0.5 ${track.playbackInfo.balance / 16} ${track.playbackInfo.volume / 16} 0.5 0.5 0.5`;
		}
		_writeStavesNode(trackNode, track) {
			const staves = trackNode.addElement("Staves");
			for (const staff of track.staves) this._writeStaffNode(staves, staff);
		}
		_writeStaffNode(parent, staff) {
			const properties = parent.addElement("Staff").addElement("Properties");
			this._writeSimplePropertyNode(properties, "CapoFret", "Fret", staff.capo.toString());
			this._writeSimplePropertyNode(properties, "FretCount", "Fret", "24");
			if (staff.tuning.length > 0) {
				const tuningProperty = properties.addElement("Property");
				tuningProperty.attributes.set("name", "Tuning");
				tuningProperty.addElement("Pitches").innerText = staff.tuning.slice().reverse().join(" ");
				tuningProperty.addElement("Label").setCData(staff.tuningName);
				tuningProperty.addElement("LabelVisible").innerText = staff.tuningName ? "true" : "false";
				tuningProperty.addElement("Flat");
				switch (staff.tuning.length) {
					case 3:
						tuningProperty.addElement("Instrument").innerText = "Shamisen";
						break;
					case 4:
						if (staff.track.playbackInfo.program === 105) tuningProperty.addElement("Instrument").innerText = "Banjo";
						else if (staff.track.playbackInfo.program === 42) tuningProperty.addElement("Instrument").innerText = "Cello";
						else if (staff.track.playbackInfo.program === 43) tuningProperty.addElement("Instrument").innerText = "Contrabass";
						else if (staff.track.playbackInfo.program === 40) tuningProperty.addElement("Instrument").innerText = "Violin";
						else if (staff.track.playbackInfo.program === 41) tuningProperty.addElement("Instrument").innerText = "Viola";
						else tuningProperty.addElement("Instrument").innerText = "Bass";
						break;
					case 5:
						if (staff.track.playbackInfo.program === 105) tuningProperty.addElement("Instrument").innerText = "Banjo";
						else tuningProperty.addElement("Instrument").innerText = "Bass";
						break;
					case 6:
						if (staff.track.playbackInfo.program === 105) tuningProperty.addElement("Instrument").innerText = "Banjo";
						else if (staff.track.playbackInfo.program <= 39) tuningProperty.addElement("Instrument").innerText = "Bass";
						else tuningProperty.addElement("Instrument").innerText = "Guitar";
						break;
					case 7:
						if (staff.track.playbackInfo.program <= 39) tuningProperty.addElement("Instrument").innerText = "Bass";
						else tuningProperty.addElement("Instrument").innerText = "Guitar";
						break;
					default:
						tuningProperty.addElement("Instrument").innerText = "Guitar";
						break;
				}
			}
			this._writeSimplePropertyNode(properties, "PartialCapoFret", "Fret", "0");
			this._writeSimplePropertyNode(properties, "PartialCapoStringFlags", "Bitset", staff.tuning.map((_) => "0").join(""));
			this._writeSimplePropertyNode(properties, "TuningFlat", "Enable", null);
			this._writeDiagramCollection(properties, staff, "DiagramCollection");
			this._writeDiagramCollection(properties, staff, "DiagramWorkingSet");
		}
		_writeDiagramCollection(properties, staff, name) {
			const diagramCollectionProperty = properties.addElement("Property");
			diagramCollectionProperty.attributes.set("name", name);
			const diagramCollectionItems = diagramCollectionProperty.addElement("Items");
			const sc = staff.chords;
			if (sc) for (const [id, chord] of sc) {
				const diagramCollectionItem = diagramCollectionItems.addElement("Item");
				diagramCollectionItem.attributes.set("id", id);
				diagramCollectionItem.attributes.set("name", chord.name);
				const diagram = diagramCollectionItem.addElement("Diagram");
				diagram.attributes.set("stringCount", chord.strings.length.toString());
				diagram.attributes.set("fretCount", "5");
				diagram.attributes.set("baseFret", (chord.firstFret - 1).toString());
				diagram.attributes.set("barStates", chord.strings.map((_) => "1").join(" "));
				const frets = [];
				const fretToStrings = /* @__PURE__ */ new Map();
				for (let i = 0; i < chord.strings.length; i++) {
					const chordFret = chord.strings[i];
					if (chordFret !== -1) {
						const fretNode = diagram.addElement("Fret");
						const chordString = chord.strings.length - 1 - i;
						fretNode.attributes.set("string", chordString.toString());
						fretNode.attributes.set("fret", (chordFret - chord.firstFret + 1).toString());
						if (!fretToStrings.has(chordFret)) {
							fretToStrings.set(chordFret, []);
							frets.push(chordFret);
						}
						fretToStrings.get(chordFret).push(chordString);
					}
				}
				frets.sort();
				const fingering = diagram.addElement("Fingering");
				if (chord.barreFrets.length > 0) {
					const fingers = [
						Fingers.LittleFinger,
						Fingers.AnnularFinger,
						Fingers.MiddleFinger,
						Fingers.IndexFinger
					];
					for (const fret of frets) {
						const fretStrings = fretToStrings.get(fret);
						if (fretStrings.length > 1 && chord.barreFrets.indexOf(fret) >= 0) {
							const finger = fingers.length > 0 ? fingers.pop() : Fingers.IndexFinger;
							for (const fretString of fretStrings) {
								const position = fingering.addElement("Position");
								switch (finger) {
									case Fingers.LittleFinger:
										position.attributes.set("finger", "Pinky");
										break;
									case Fingers.AnnularFinger:
										position.attributes.set("finger", "Ring");
										break;
									case Fingers.MiddleFinger:
										position.attributes.set("finger", "Middle");
										break;
									case Fingers.IndexFinger:
										position.attributes.set("finger", "Index");
										break;
								}
								position.attributes.set("fret", (fret - chord.firstFret + 1).toString());
								position.attributes.set("string", fretString.toString());
							}
						}
					}
				}
				const showName = diagram.addElement("Property");
				showName.attributes.set("name", "ShowName");
				showName.attributes.set("type", "bool");
				showName.attributes.set("value", chord.showName ? "true" : "false");
				const showDiagram = diagram.addElement("Property");
				showDiagram.attributes.set("name", "ShowDiagram");
				showDiagram.attributes.set("type", "bool");
				showDiagram.attributes.set("value", chord.showDiagram ? "true" : "false");
				const showFingering = diagram.addElement("Property");
				showFingering.attributes.set("name", "ShowFingering");
				showFingering.attributes.set("type", "bool");
				showFingering.attributes.set("value", chord.showFingering ? "true" : "false");
				const chordNode = diagram.addElement("Chord");
				const keyNoteNode = chordNode.addElement("KeyNote");
				keyNoteNode.attributes.set("step", "C");
				keyNoteNode.attributes.set("accidental", "Natural");
				const bassNoteNode = chordNode.addElement("BassNote");
				bassNoteNode.attributes.set("step", "C");
				bassNoteNode.attributes.set("accidental", "Natural");
				const degree1Node = chordNode.addElement("Degree");
				degree1Node.attributes.set("interval", "Third");
				degree1Node.attributes.set("alteration", "Major");
				degree1Node.attributes.set("omitted", "false");
				const degree2Node = chordNode.addElement("Degree");
				degree2Node.attributes.set("interval", "Fifth");
				degree2Node.attributes.set("alteration", "Perfect");
				degree2Node.attributes.set("omitted", "false");
			}
		}
		_writeSimplePropertyNode(parent, propertyName, propertyValueTagName, propertyValue) {
			const prop = parent.addElement("Property");
			prop.attributes.set("name", propertyName);
			const propertyValueTag = prop.addElement(propertyValueTagName);
			if (propertyValue !== null) propertyValueTag.innerText = propertyValue;
			return prop;
		}
		_writeSimpleXPropertyNode(parent, propertyId, propertyValueTagName, propertyValue) {
			const prop = parent.addElement("XProperty");
			prop.attributes.set("id", propertyId);
			const propertyValueTag = prop.addElement(propertyValueTagName);
			if (propertyValue !== null) propertyValueTag.innerText = propertyValue;
			return prop;
		}
		_writeLyricsNode(trackNode, track) {
			const lyrics = trackNode.addElement("Lyrics");
			lyrics.attributes.set("dispatched", "true");
			const lines = [];
			for (const bar of track.staves[0].bars) for (const voice of bar.voices) if (!voice.isEmpty) {
				for (const beat of voice.beats) if (beat.lyrics) for (let l = 0; l < beat.lyrics.length; l++) {
					while (l >= lines.length) {
						const newLyrics = new Lyrics();
						newLyrics.startBar = bar.index;
						newLyrics.text = "[Empty]";
						lines.push(newLyrics);
					}
					const line = lines[l];
					line.text = line.text === "[Empty]" ? beat.lyrics[l] : `${line.text} ${beat.lyrics[l].split(" ").join("+")}`;
				}
			}
			for (let i = 0; i < lines.length; i++) {
				const line = lyrics.addElement("Line");
				line.addElement("Text").setCData(lines[i].text);
				line.addElement("Offset").innerText = lines[i].startBar.toString();
			}
		}
		_writeTransposeNode(trackNode, track) {
			const transpose = trackNode.addElement("Transpose");
			const octaveTranspose = Math.floor(track.staves[0].displayTranspositionPitch / 12);
			const chromaticTranspose = track.staves[0].displayTranspositionPitch - octaveTranspose * 12;
			transpose.addElement("Chromatic").innerText = chromaticTranspose.toString();
			transpose.addElement("Octave").innerText = octaveTranspose.toString();
		}
		_writeInstrumentSetNode(trackNode, track) {
			const instrumentSet = GpifSoundMapper.buildInstrumentSet(track);
			const instrumentSetNode = trackNode.addElement("InstrumentSet");
			instrumentSetNode.addElement("Name").innerText = instrumentSet.name;
			instrumentSetNode.addElement("Type").innerText = instrumentSet.type;
			instrumentSetNode.addElement("LineCount").innerText = instrumentSet.lineCount.toString();
			const elementsNode = instrumentSetNode.addElement("Elements");
			for (const element of instrumentSet.elements) {
				const elementNode = elementsNode.addElement("Element");
				elementNode.addElement("Name").innerText = element.name;
				elementNode.addElement("Type").innerText = element.type;
				elementNode.addElement("SoundbankName").innerText = element.soundbankName;
				const articulationsNode = elementNode.addElement("Articulations");
				for (const articulation of element.articulations) {
					const articulationNode = articulationsNode.addElement("Articulation");
					articulationNode.addElement("Name").innerText = articulation.name;
					articulationNode.addElement("StaffLine").innerText = articulation.staffLine.toString();
					articulationNode.addElement("Noteheads").innerText = [
						this._mapMusicSymbol(articulation.noteHeads[0]),
						this._mapMusicSymbol(articulation.noteHeads[1]),
						this._mapMusicSymbol(articulation.noteHeads[2])
					].join(" ");
					switch (articulation.techniqueSymbolPlacement) {
						case TechniqueSymbolPlacement.Below:
							articulationNode.addElement("TechniquePlacement").innerText = "below";
							break;
						case TechniqueSymbolPlacement.Outside:
							articulationNode.addElement("TechniquePlacement").innerText = "outside";
							break;
						case TechniqueSymbolPlacement.Inside:
							articulationNode.addElement("TechniquePlacement").innerText = "inside";
							break;
						case TechniqueSymbolPlacement.Above:
							articulationNode.addElement("TechniquePlacement").innerText = "above";
							break;
					}
					articulationNode.addElement("TechniqueSymbol").innerText = this._mapMusicSymbol(articulation.techniqueSymbol);
					articulationNode.addElement("InputMidiNumbers").innerText = articulation.inputMidiNumbers.map((n) => n.toString()).join(" ");
					articulationNode.addElement("OutputRSESound").innerText = articulation.outputRSESound;
					articulationNode.addElement("OutputMidiNumber").innerText = articulation.outputMidiNumber.toString();
				}
			}
		}
		_mapMusicSymbol(symbol) {
			if (symbol === MusicFontSymbol.None) return "";
			const s = MusicFontSymbol[symbol];
			return s.substring(0, 1).toLowerCase() + s.substring(1);
		}
		_writeMasterBarsNode(parent, score) {
			const masterBars = parent.addElement("MasterBars");
			for (const masterBar of score.masterBars) this._writeMasterBarNode(masterBars, masterBar);
		}
		_writeMasterBarNode(parent, masterBar) {
			const masterBarNode = parent.addElement("MasterBar");
			const key = masterBarNode.addElement("Key");
			let keySignature = masterBar.score.tracks[0].staves[0].bars[masterBar.index].keySignature;
			const keySignatureType = masterBar.score.tracks[0].staves[0].bars[masterBar.index].keySignatureType;
			const transposeIndex = ModelUtils.flooredDivision(masterBar.score.tracks[0].staves[0].displayTranspositionPitch, 12);
			keySignature = ModelUtils.transposeKey(keySignature, -transposeIndex);
			key.addElement("AccidentalCount").innerText = keySignature.toString();
			key.addElement("Mode").innerText = KeySignatureType[keySignatureType];
			key.addElement("Sharps").innerText = "Sharps";
			masterBarNode.addElement("Time").innerText = `${masterBar.timeSignatureNumerator}/${masterBar.timeSignatureDenominator}`;
			if (masterBar.actualBeamingRules) this._writeBarXProperties(masterBarNode, masterBar);
			if (masterBar.isFreeTime) masterBarNode.addElement("FreeTime");
			const bars = [];
			for (const tracks of masterBar.score.tracks) for (const staves of tracks.staves) bars.push(staves.bars[masterBar.index].id.toString());
			masterBarNode.addElement("Bars").innerText = bars.join(" ");
			if (masterBar.isDoubleBar) masterBarNode.addElement("DoubleBar");
			if (masterBar.isSectionStart) {
				const section = masterBarNode.addElement("Section");
				section.addElement("Letter").setCData(masterBar.section.marker);
				section.addElement("Text").setCData(masterBar.section.text);
			}
			if (masterBar.isRepeatStart || masterBar.isRepeatEnd) {
				const repeat = masterBarNode.addElement("Repeat");
				repeat.attributes.set("start", masterBar.isRepeatStart ? "true" : "false");
				repeat.attributes.set("end", masterBar.isRepeatEnd ? "true" : "false");
				if (masterBar.isRepeatEnd) repeat.attributes.set("count", masterBar.repeatCount.toString());
			}
			if (masterBar.alternateEndings > 0) {
				let remainingBits = masterBar.alternateEndings;
				const alternateEndings = [];
				let bit = 0;
				while (remainingBits > 0) {
					if ((remainingBits >> bit & 1) === 1) {
						alternateEndings.push(bit + 1);
						remainingBits &= ~(1 << bit);
					}
					bit++;
				}
				masterBarNode.addElement("AlternateEndings").innerText = alternateEndings.join(" ");
			}
			if (masterBar.tripletFeel !== TripletFeel.NoTripletFeel) masterBarNode.addElement("TripletFeel").innerText = TripletFeel[masterBar.tripletFeel];
			if (masterBar.directions && masterBar.directions.size > 0) {
				const directions = masterBarNode.addElement("Directions");
				for (const d of masterBar.directions) switch (d) {
					case Direction.TargetFine:
						directions.addElement("Target").innerText = "Fine";
						break;
					case Direction.TargetSegno:
						directions.addElement("Target").innerText = "Segno";
						break;
					case Direction.TargetSegnoSegno:
						directions.addElement("Target").innerText = "SegnoSegno";
						break;
					case Direction.TargetCoda:
						directions.addElement("Target").innerText = "Coda";
						break;
					case Direction.TargetDoubleCoda:
						directions.addElement("Target").innerText = "DoubleCoda";
						break;
					case Direction.JumpDaCapo:
						directions.addElement("Jump").innerText = "DaCapo";
						break;
					case Direction.JumpDaCapoAlCoda:
						directions.addElement("Jump").innerText = "DaCapoAlCoda";
						break;
					case Direction.JumpDaCapoAlDoubleCoda:
						directions.addElement("Jump").innerText = "DaCapoAlDoubleCoda";
						break;
					case Direction.JumpDaCapoAlFine:
						directions.addElement("Jump").innerText = "DaCapoAlFine";
						break;
					case Direction.JumpDalSegno:
						directions.addElement("Jump").innerText = "DaSegno";
						break;
					case Direction.JumpDalSegnoAlCoda:
						directions.addElement("Jump").innerText = "DaSegnoAlCoda";
						break;
					case Direction.JumpDalSegnoAlDoubleCoda:
						directions.addElement("Jump").innerText = "DaSegnoAlDoubleCoda";
						break;
					case Direction.JumpDalSegnoAlFine:
						directions.addElement("Jump").innerText = "DaSegnoAlFine";
						break;
					case Direction.JumpDalSegnoSegno:
						directions.addElement("Jump").innerText = "DaSegnoSegno";
						break;
					case Direction.JumpDalSegnoSegnoAlCoda:
						directions.addElement("Jump").innerText = "DaSegnoSegnoAlCoda";
						break;
					case Direction.JumpDalSegnoSegnoAlDoubleCoda:
						directions.addElement("Jump").innerText = "DaSegnoSegnoAlDoubleCoda";
						break;
					case Direction.JumpDalSegnoSegnoAlFine:
						directions.addElement("Jump").innerText = "DaSegnoSegnoAlFine";
						break;
					case Direction.JumpDaCoda:
						directions.addElement("Jump").innerText = "DaCoda";
						break;
					case Direction.JumpDaDoubleCoda:
						directions.addElement("Jump").innerText = "DaDoubleCoda";
						break;
				}
			}
			this._writeFermatas(masterBarNode, masterBar);
		}
		_writeBarXProperties(masterBarNode, masterBar) {
			const properties = masterBarNode.addElement("XProperties");
			const beamingRules = masterBar.actualBeamingRules;
			if (beamingRules) {
				const rule = beamingRules.findRule(Duration.Eighth);
				let durationProp = rule[0];
				let groupSizeFactor = 1;
				if (rule[0] === Duration.Quarter) {
					durationProp = 8;
					groupSizeFactor = 2;
				}
				this._writeSimpleXPropertyNode(properties, "1124139010", "Int", durationProp.toString());
				const startGroupid = 1124139264;
				let i = 0;
				while (i < rule[1].length) {
					this._writeSimpleXPropertyNode(properties, (startGroupid + i).toString(), "Int", (rule[1][i] * groupSizeFactor).toString());
					i++;
				}
			}
		}
		_writeFermatas(parent, masterBar) {
			const fermataCount = masterBar.fermata?.size ?? 0;
			if (fermataCount === 0) return;
			if (fermataCount > 0) {
				const fermatas = parent.addElement("Fermatas");
				for (const [offset, fermata] of masterBar.fermata) this._writeFermata(fermatas, offset, fermata);
			}
		}
		_writeFermata(parent, offset, fermata) {
			let numerator = -1;
			let denominator = 1;
			if (offset > 0) while (denominator < 10) {
				numerator = offset / MidiUtils.QuarterTime * denominator;
				if (numerator === Math.floor(numerator)) break;
				numerator = -1;
				denominator++;
			}
			else {
				numerator = 0;
				denominator = 1;
			}
			if (numerator === -1) return;
			const fermataNode = parent.addElement("Fermata");
			fermataNode.addElement("Type").innerText = FermataType[fermata.type];
			fermataNode.addElement("Length").innerText = fermata.length.toString();
			fermataNode.addElement("Offset").innerText = `${numerator}/${denominator}`;
		}
		_writeBarNode(parent, bar) {
			const barNode = parent.addElement("Bar");
			barNode.attributes.set("id", bar.id.toString());
			barNode.addElement("Voices").innerText = bar.voices.map((v) => v.isEmpty ? "-1" : v.id.toString()).join(" ");
			barNode.addElement("Clef").innerText = Clef[bar.clef];
			if (bar.clefOttava !== Ottavia.Regular) barNode.addElement("Ottavia").innerText = Ottavia[bar.clefOttava].substr(1);
			if (bar.simileMark !== SimileMark.None) barNode.addElement("SimileMark").innerText = SimileMark[bar.simileMark];
		}
		_writeVoiceNode(parent, voice) {
			if (voice.isEmpty) return;
			const voiceNode = parent.addElement("Voice");
			voiceNode.attributes.set("id", voice.id.toString());
			voiceNode.addElement("Beats").innerText = voice.beats.map((v) => v.id).join(" ");
		}
	};
	//#endregion
	//#region src/zip/Crc32.ts
	/**
	* CRC-32 with reversed data and unreversed output
	* @internal
	*/
	var Crc32 = class Crc32 {
		static _crc32Lookup = Crc32._buildCrc32Lookup();
		static _buildCrc32Lookup() {
			const poly = 3988292384;
			const lookup = new Uint32Array(256);
			for (let i = 0; i < lookup.length; i++) {
				let crc = i;
				for (let bit = 0; bit < 8; bit++) crc = (crc & 1) === 1 ? crc >>> 1 ^ poly : crc >>> 1;
				lookup[i] = crc;
			}
			return lookup;
		}
		static _crcInit = 4294967295;
		/**
		* The CRC data checksum so far.
		*/
		_checkValue = Crc32._crcInit;
		/**
		* Returns the CRC data checksum computed so far.
		*/
		get value() {
			return ~this._checkValue;
		}
		/**
		* Initialise a default instance of Crc32.
		*/
		constructor() {
			this.reset();
		}
		/**
		* Update CRC data checksum based on a portion of a block of data
		* @param data The array containing the data to add
		* @param offset Range start for data (inclusive)
		* @param count The number of bytes to checksum starting from offset
		*/
		update(data, offset, count) {
			for (let i = 0; i < count; i++) this._checkValue = Crc32._crc32Lookup[(this._checkValue ^ data[offset + i]) & 255] ^ this._checkValue >>> 8;
		}
		/**
		* Resets the CRC data checksum as if no update was ever called.
		*/
		reset() {
			this._checkValue = Crc32._crcInit;
		}
	};
	//#endregion
	//#region src/zip/DeflaterConstants.ts
	/**
	* This class contains constants used for deflation.
	* 
	* @internal
	*/
	var DeflaterConstants = class DeflaterConstants {
		static maxWbits = 15;
		static wsize = 1 << DeflaterConstants.maxWbits;
		static wmask = DeflaterConstants.wsize - 1;
		static minMatch = 3;
		static maxMatch = 258;
		static defaultMemLevel = 8;
		static pendingBufSize = 1 << DeflaterConstants.defaultMemLevel + 8;
		static hashBits = DeflaterConstants.defaultMemLevel + 7;
		static hashSize = 1 << DeflaterConstants.hashBits;
		static hashShift = (DeflaterConstants.hashBits + DeflaterConstants.minMatch - 1) / DeflaterConstants.minMatch;
		static hashMask = DeflaterConstants.hashSize - 1;
		static minLookahead = DeflaterConstants.maxMatch + DeflaterConstants.minMatch + 1;
		static maxDist = DeflaterConstants.wsize - DeflaterConstants.minLookahead;
	};
	//#endregion
	//#region src/zip/DeflaterHuffman.ts
	/**
	* @internal
	*/
	var Tree = class Tree {
		static _repeat3To6 = 16;
		static _repeat3To10 = 17;
		static _repeat11To138 = 18;
		freqs;
		length = null;
		minNumCodes;
		numCodes = 0;
		_codes = null;
		_bitLengthCounts;
		_maxLength;
		_huffman;
		constructor(dh, elems, minCodes, maxLength) {
			this._huffman = dh;
			this.minNumCodes = minCodes;
			this._maxLength = maxLength;
			this.freqs = new Int16Array(elems);
			this._bitLengthCounts = new Int32Array(maxLength);
		}
		/**
		* Resets the internal state of the tree
		*/
		reset() {
			for (let i = 0; i < this.freqs.length; i++) this.freqs[i] = 0;
			this._codes = null;
			this.length = null;
		}
		buildTree() {
			const numSymbols = this.freqs.length;
			const heap = new Int32Array(numSymbols);
			let heapLen = 0;
			let maxCode = 0;
			for (let n = 0; n < numSymbols; n++) {
				const freq = this.freqs[n];
				if (freq !== 0) {
					let pos = heapLen++;
					while (true) if (pos > 0) {
						const ppos = Math.floor((pos - 1) / 2);
						if (this.freqs[heap[ppos]] > freq) {
							heap[pos] = heap[ppos];
							pos = ppos;
						} else break;
					} else break;
					heap[pos] = n;
					maxCode = n;
				}
			}
			while (heapLen < 2) {
				const node = maxCode < 2 ? ++maxCode : 0;
				heap[heapLen++] = node;
			}
			this.numCodes = Math.max(maxCode + 1, this.minNumCodes);
			const numLeafs = heapLen;
			const childs = new Int32Array(4 * heapLen - 2);
			const values = new Int32Array(2 * heapLen - 1);
			let numNodes = numLeafs;
			for (let i = 0; i < heapLen; i++) {
				const node = heap[i];
				childs[2 * i] = node;
				childs[2 * i + 1] = -1;
				values[i] = this.freqs[node] << 8;
				heap[i] = i;
			}
			do {
				const first = heap[0];
				let last = heap[--heapLen];
				let ppos = 0;
				let path = 1;
				while (path < heapLen) {
					if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) path++;
					heap[ppos] = heap[path];
					ppos = path;
					path = path * 2 + 1;
				}
				let lastVal = values[last];
				while (true) {
					path = ppos;
					if (ppos > 0) {
						ppos = Math.floor((path - 1) / 2);
						if (values[heap[ppos]] > lastVal) heap[path] = heap[ppos];
						else break;
					} else break;
				}
				heap[path] = last;
				const second = heap[0];
				last = numNodes++;
				childs[2 * last] = first;
				childs[2 * last + 1] = second;
				const mindepth = Math.min(values[first] & 255, values[second] & 255);
				lastVal = values[first] + values[second] - mindepth + 1;
				values[last] = lastVal;
				ppos = 0;
				path = 1;
				while (path < heapLen) {
					if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]]) path++;
					heap[ppos] = heap[path];
					ppos = path;
					path = ppos * 2 + 1;
				}
				while (true) {
					path = ppos;
					if (path > 0) {
						ppos = Math.floor((path - 1) / 2);
						if (values[heap[ppos]] > lastVal) heap[path] = heap[ppos];
						else break;
					} else break;
				}
				heap[path] = last;
			} while (heapLen > 1);
			this._buildLength(childs);
		}
		_buildLength(childs) {
			this.length = new Uint8Array(this.freqs.length);
			const numNodes = Math.floor(childs.length / 2);
			const numLeafs = Math.floor((numNodes + 1) / 2);
			let overflow = 0;
			for (let i = 0; i < this._maxLength; i++) this._bitLengthCounts[i] = 0;
			const lengths = new Int32Array(numNodes);
			lengths[numNodes - 1] = 0;
			for (let i = numNodes - 1; i >= 0; i--) if (childs[2 * i + 1] !== -1) {
				let bitLength = lengths[i] + 1;
				if (bitLength > this._maxLength) {
					bitLength = this._maxLength;
					overflow++;
				}
				lengths[childs[2 * i]] = bitLength;
				lengths[childs[2 * i + 1]] = bitLength;
			} else {
				const bitLength = lengths[i];
				this._bitLengthCounts[bitLength - 1]++;
				this.length[childs[2 * i]] = lengths[i];
			}
			if (overflow === 0) return;
			let incrBitLen = this._maxLength - 1;
			do {
				while (this._bitLengthCounts[--incrBitLen] === 0);
				do {
					this._bitLengthCounts[incrBitLen]--;
					this._bitLengthCounts[++incrBitLen]++;
					overflow -= 1 << this._maxLength - 1 - incrBitLen;
				} while (overflow > 0 && incrBitLen < this._maxLength - 1);
			} while (overflow > 0);
			this._bitLengthCounts[this._maxLength - 1] += overflow;
			this._bitLengthCounts[this._maxLength - 2] -= overflow;
			let nodePtr = 2 * numLeafs;
			for (let bits = this._maxLength; bits !== 0; bits--) {
				let n = this._bitLengthCounts[bits - 1];
				while (n > 0) {
					const childPtr = 2 * childs[nodePtr++];
					if (childs[childPtr + 1] === -1) {
						this.length[childs[childPtr]] = bits;
						n--;
					}
				}
			}
		}
		/**
		* Get encoded length
		* @returns Encoded length, the sum of frequencies * lengths
		*/
		getEncodedLength() {
			let len = 0;
			for (let i = 0; i < this.freqs.length; i++) len += this.freqs[i] * this.length[i];
			return len;
		}
		/**
		* Scan a literal or distance tree to determine the frequencies of the codes
		* in the bit length tree.
		* @param blTree
		*/
		calcBLFreq(blTree) {
			let maxCount;
			let minCount;
			let count;
			let curlen = -1;
			let i = 0;
			while (i < this.numCodes) {
				count = 1;
				const nextlen = this.length[i];
				if (nextlen === 0) {
					maxCount = 138;
					minCount = 3;
				} else {
					maxCount = 6;
					minCount = 3;
					if (curlen !== nextlen) {
						blTree.freqs[nextlen]++;
						count = 0;
					}
				}
				curlen = nextlen;
				i++;
				while (i < this.numCodes && curlen === this.length[i]) {
					i++;
					if (++count >= maxCount) break;
				}
				if (count < minCount) blTree.freqs[curlen] += count;
				else if (curlen !== 0) blTree.freqs[Tree._repeat3To6]++;
				else if (count <= 10) blTree.freqs[Tree._repeat3To10]++;
				else blTree.freqs[Tree._repeat11To138]++;
			}
		}
		/**
		* Set static codes and length
		* @param staticCodes new codes
		* @param staticLengths length for new codes
		*/
		setStaticCodes(staticCodes, staticLengths) {
			this._codes = staticCodes;
			this.length = staticLengths;
		}
		/**
		* Build dynamic codes and lengths
		*/
		buildCodes() {
			const nextCode = new Int32Array(this._maxLength);
			let code = 0;
			this._codes = new Int16Array(this.freqs.length);
			for (let bits = 0; bits < this._maxLength; bits++) {
				nextCode[bits] = code;
				code += this._bitLengthCounts[bits] << 15 - bits;
			}
			for (let i = 0; i < this.numCodes; i++) {
				const bits = this.length[i];
				if (bits > 0) {
					this._codes[i] = DeflaterHuffman.bitReverse(nextCode[bits - 1]);
					nextCode[bits - 1] += 1 << 16 - bits;
				}
			}
		}
		/**
		* Write tree values
		* @param blTree Tree to write
		*/
		writeTree(blTree) {
			let maxCount;
			let minCount;
			let count;
			let curlen = -1;
			let i = 0;
			while (i < this.numCodes) {
				count = 1;
				const nextlen = this.length[i];
				if (nextlen === 0) {
					maxCount = 138;
					minCount = 3;
				} else {
					maxCount = 6;
					minCount = 3;
					if (curlen !== nextlen) {
						blTree.writeSymbol(nextlen);
						count = 0;
					}
				}
				curlen = nextlen;
				i++;
				while (i < this.numCodes && curlen === this.length[i]) {
					i++;
					if (++count >= maxCount) break;
				}
				if (count < minCount) while (count-- > 0) blTree.writeSymbol(curlen);
				else if (curlen !== 0) {
					blTree.writeSymbol(Tree._repeat3To6);
					this._huffman.pending.writeBits(count - 3, 2);
				} else if (count <= 10) {
					blTree.writeSymbol(Tree._repeat3To10);
					this._huffman.pending.writeBits(count - 3, 3);
				} else {
					blTree.writeSymbol(Tree._repeat11To138);
					this._huffman.pending.writeBits(count - 11, 7);
				}
			}
		}
		writeSymbol(code) {
			this._huffman.pending.writeBits(this._codes[code] & 65535, this.length[code]);
		}
	};
	/**
	* @internal
	*/
	var DeflaterHuffman = class DeflaterHuffman {
		static _bufSize = 1 << DeflaterConstants.defaultMemLevel + 6;
		static _literalNum = 286;
		/**
		* Written to Zip file to identify a stored block
		*/
		static storedBlock = 0;
		/**
		* Identifies static tree in Zip file
		*/
		static staticTrees = 1;
		/**
		* Identifies dynamic tree in Zip file
		*/
		static dynTrees = 2;
		static _distNum = 30;
		static _staticLCodes = new Int16Array(DeflaterHuffman._literalNum);
		static _staticLLength = new Uint8Array(DeflaterHuffman._literalNum);
		static _staticDCodes = new Int16Array(DeflaterHuffman._distNum);
		static _staticDLength = new Uint8Array(DeflaterHuffman._distNum);
		static staticInit() {
			let i = 0;
			while (i < 144) {
				DeflaterHuffman._staticLCodes[i] = DeflaterHuffman.bitReverse(48 + i << 8);
				DeflaterHuffman._staticLLength[i++] = 8;
			}
			while (i < 256) {
				DeflaterHuffman._staticLCodes[i] = DeflaterHuffman.bitReverse(256 + i << 7);
				DeflaterHuffman._staticLLength[i++] = 9;
			}
			while (i < 280) {
				DeflaterHuffman._staticLCodes[i] = DeflaterHuffman.bitReverse(-256 + i << 9);
				DeflaterHuffman._staticLLength[i++] = 7;
			}
			while (i < DeflaterHuffman._literalNum) {
				DeflaterHuffman._staticLCodes[i] = DeflaterHuffman.bitReverse(-88 + i << 8);
				DeflaterHuffman._staticLLength[i++] = 8;
			}
			for (i = 0; i < DeflaterHuffman._distNum; i++) {
				DeflaterHuffman._staticDCodes[i] = DeflaterHuffman.bitReverse(i << 11);
				DeflaterHuffman._staticDLength[i] = 5;
			}
		}
		static _blOrder = [
			16,
			17,
			18,
			0,
			8,
			7,
			9,
			6,
			10,
			5,
			11,
			4,
			12,
			3,
			13,
			2,
			14,
			1,
			15
		];
		static _bit4Reverse = new Uint8Array([
			0,
			8,
			4,
			12,
			2,
			10,
			6,
			14,
			1,
			9,
			5,
			13,
			3,
			11,
			7,
			15
		]);
		/**
		* Reverse the bits of a 16 bit value.
		* @param toReverse Value to reverse bits
		* @returns Value with bits reversed
		*/
		static bitReverse(toReverse) {
			return DeflaterHuffman._bit4Reverse[toReverse & 15] << 12 | DeflaterHuffman._bit4Reverse[toReverse >> 4 & 15] << 8 | DeflaterHuffman._bit4Reverse[toReverse >> 8 & 15] << 4 | DeflaterHuffman._bit4Reverse[toReverse >> 12];
		}
		static _bitLenNum = 19;
		static _eofSymbol = 256;
		/**
		* Pending buffer to use
		*/
		pending;
		_literalTree;
		_distTree;
		_blTree;
		_dBuf;
		_lBuf;
		_lastLit = 0;
		_extraBits = 0;
		constructor(pending) {
			this.pending = pending;
			this._literalTree = new Tree(this, DeflaterHuffman._literalNum, 257, 15);
			this._distTree = new Tree(this, DeflaterHuffman._distNum, 1, 15);
			this._blTree = new Tree(this, DeflaterHuffman._bitLenNum, 4, 7);
			this._dBuf = new Int16Array(DeflaterHuffman._bufSize);
			this._lBuf = new Uint8Array(DeflaterHuffman._bufSize);
		}
		isFull() {
			return this._lastLit >= DeflaterHuffman._bufSize;
		}
		reset() {
			this._lastLit = 0;
			this._extraBits = 0;
			this._literalTree.reset();
			this._distTree.reset();
			this._blTree.reset();
		}
		flushStoredBlock(stored, storedOffset, storedLength, lastBlock) {
			this.pending.writeBits((DeflaterHuffman.storedBlock << 1) + (lastBlock ? 1 : 0), 3);
			this.pending.alignToByte();
			this.pending.writeShort(storedLength);
			this.pending.writeShort(~storedLength);
			this.pending.writeBlock(stored, storedOffset, storedLength);
			this.reset();
		}
		flushBlock(stored, storedOffset, storedLength, lastBlock) {
			this._literalTree.freqs[DeflaterHuffman._eofSymbol]++;
			this._literalTree.buildTree();
			this._distTree.buildTree();
			this._literalTree.calcBLFreq(this._blTree);
			this._distTree.calcBLFreq(this._blTree);
			this._blTree.buildTree();
			let blTreeCodes = 4;
			for (let i = 18; i > blTreeCodes; i--) if (this._blTree.length[DeflaterHuffman._blOrder[i]] > 0) blTreeCodes = i + 1;
			let optLen = 14 + blTreeCodes * 3 + this._blTree.getEncodedLength() + this._literalTree.getEncodedLength() + this._distTree.getEncodedLength() + this._extraBits;
			let staticLen = this._extraBits;
			for (let i = 0; i < DeflaterHuffman._literalNum; i++) staticLen += this._literalTree.freqs[i] * DeflaterHuffman._staticLLength[i];
			for (let i = 0; i < DeflaterHuffman._distNum; i++) staticLen += this._distTree.freqs[i] * DeflaterHuffman._staticDLength[i];
			if (optLen >= staticLen) optLen = staticLen;
			if (storedOffset >= 0 && storedLength + 4 < optLen >> 3) this.flushStoredBlock(stored, storedOffset, storedLength, lastBlock);
			else if (optLen === staticLen) {
				this.pending.writeBits((DeflaterHuffman.staticTrees << 1) + (lastBlock ? 1 : 0), 3);
				this._literalTree.setStaticCodes(DeflaterHuffman._staticLCodes, DeflaterHuffman._staticLLength);
				this._distTree.setStaticCodes(DeflaterHuffman._staticDCodes, DeflaterHuffman._staticDLength);
				this.compressBlock();
				this.reset();
			} else {
				this.pending.writeBits((DeflaterHuffman.dynTrees << 1) + (lastBlock ? 1 : 0), 3);
				this.sendAllTrees(blTreeCodes);
				this.compressBlock();
				this.reset();
			}
		}
		/**
		* Write all trees to pending buffer
		* @param blTreeCodes The number/rank of treecodes to send.
		*/
		sendAllTrees(blTreeCodes) {
			this._blTree.buildCodes();
			this._literalTree.buildCodes();
			this._distTree.buildCodes();
			this.pending.writeBits(this._literalTree.numCodes - 257, 5);
			this.pending.writeBits(this._distTree.numCodes - 1, 5);
			this.pending.writeBits(blTreeCodes - 4, 4);
			for (let rank = 0; rank < blTreeCodes; rank++) this.pending.writeBits(this._blTree.length[DeflaterHuffman._blOrder[rank]], 3);
			this._literalTree.writeTree(this._blTree);
			this._distTree.writeTree(this._blTree);
		}
		/**
		* Compress current buffer writing data to pending buffer
		*/
		compressBlock() {
			for (let i = 0; i < this._lastLit; i++) {
				const litlen = this._lBuf[i] & 255;
				let dist = this._dBuf[i];
				if (dist-- !== 0) {
					const lc = DeflaterHuffman._lCode(litlen);
					this._literalTree.writeSymbol(lc);
					let bits = Math.floor((lc - 261) / 4);
					if (bits > 0 && bits <= 5) this.pending.writeBits(litlen & (1 << bits) - 1, bits);
					const dc = DeflaterHuffman._dCode(dist);
					this._distTree.writeSymbol(dc);
					bits = Math.floor(dc / 2) - 1;
					if (bits > 0) this.pending.writeBits(dist & (1 << bits) - 1, bits);
				} else this._literalTree.writeSymbol(litlen);
			}
			this._literalTree.writeSymbol(DeflaterHuffman._eofSymbol);
		}
		/**
		* Add distance code and length to literal and distance trees
		* @param distance Distance code
		* @param length Length
		* @returns Value indicating if internal buffer is full
		*/
		tallyDist(distance, length) {
			this._dBuf[this._lastLit] = distance;
			this._lBuf[this._lastLit++] = length - 3;
			const lc = DeflaterHuffman._lCode(length - 3);
			this._literalTree.freqs[lc]++;
			if (lc >= 265 && lc < 285) this._extraBits += Math.floor((lc - 261) / 4);
			const dc = DeflaterHuffman._dCode(distance - 1);
			this._distTree.freqs[dc]++;
			if (dc >= 4) this._extraBits += Math.floor(dc / 2) - 1;
			return this.isFull();
		}
		/**
		* Add literal to buffer
		* @param literal Literal value to add to buffer
		* @returns Value indicating internal buffer is full
		*/
		tallyLit(literal) {
			this._dBuf[this._lastLit] = 0;
			this._lBuf[this._lastLit++] = literal;
			this._literalTree.freqs[literal]++;
			return this.isFull();
		}
		static _lCode(length) {
			if (length === 255) return 285;
			let code = 257;
			while (length >= 8) {
				code += 4;
				length = length >> 1;
			}
			return code + length;
		}
		static _dCode(distance) {
			let code = 0;
			while (distance >= 4) {
				code += 2;
				distance = distance >> 1;
			}
			return code + distance;
		}
	};
	DeflaterHuffman.staticInit();
	//#endregion
	//#region src/zip/DeflaterEngine.ts
	/**
	* Low level compression engine for deflate algorithm which uses a 32K sliding window
	* with secondary compression from Huffman/Shannon-Fano codes.
	* 
	* @internal
	*/
	var DeflaterEngine = class DeflaterEngine {
		static _tooFar = 4096;
		_blockStart;
		_maxChain = 128;
		_niceLength = 128;
		_goodLength = 8;
		/**
		* Hash index of string to be inserted
		*/
		_insertHashIndex = 0;
		/**
		* Points to the current character in the window.
		*/
		_strstart;
		/**
		* This array contains the part of the uncompressed stream that
		* is of relevance.  The current character is indexed by strstart.
		*/
		_window;
		/**
		* Hashtable, hashing three characters to an index for window, so
		* that window[index]..window[index+2] have this hash code.
		* Note that the array should really be unsigned short, so you need
		* to and the values with 0xffff.
		*/
		_head;
		/**
		* <code>prev[index &amp; WMASK]</code> points to the previous index that has the
		* same hash code as the string starting at index.  This way
		* entries with the same hash code are in a linked list.
		* Note that the array should really be unsigned short, so you need
		* to and the values with 0xffff.
		*/
		_prev;
		/**
		* lookahead is the number of characters starting at strstart in
		* window that are valid.
		* So window[strstart] until window[strstart+lookahead-1] are valid
		* characters.
		*/
		_lookahead = 0;
		/**
		* The input data for compression.
		*/
		_inputBuf = null;
		/**
		* The offset into inputBuf, where input data starts.
		*/
		_inputOff = 0;
		/**
		* The end offset of the input data.
		*/
		_inputEnd = 0;
		/**
		* Set if previous match exists
		*/
		_prevAvailable = false;
		_matchStart = 0;
		/**
		* Length of best match
		*/
		_matchLen = 0;
		_pending;
		_huffman;
		inputCrc;
		/**
		* Construct instance with pending buffer
		* @param pending Pending buffer to use
		* @param noAdlerCalculation Pending buffer to use
		*/
		constructor(pending) {
			this._pending = pending;
			this._huffman = new DeflaterHuffman(pending);
			this.inputCrc = new Crc32();
			this._window = new Uint8Array(2 * DeflaterConstants.wsize);
			this._head = new Int16Array(DeflaterConstants.hashSize);
			this._prev = new Int16Array(DeflaterConstants.wsize);
			this._blockStart = 1;
			this._strstart = 1;
		}
		/**
		* Reset internal state
		*/
		reset() {
			this._huffman.reset();
			this.inputCrc.reset();
			this._blockStart = 1;
			this._strstart = 1;
			this._lookahead = 0;
			this._prevAvailable = false;
			this._matchLen = DeflaterConstants.minMatch - 1;
			for (let i = 0; i < DeflaterConstants.hashSize; i++) this._head[i] = 0;
			for (let i = 0; i < DeflaterConstants.wsize; i++) this._prev[i] = 0;
		}
		_updateHash() {
			this._insertHashIndex = this._window[this._strstart] << DeflaterConstants.hashShift ^ this._window[this._strstart + 1];
		}
		/**
		* Determines if more input is needed.
		* @returns Return true if input is needed via setInput
		*/
		needsInput() {
			return this._inputEnd === this._inputOff;
		}
		/**
		* Sets input data to be deflated.  Should only be called when <code>NeedsInput()</code>
		* returns true
		* @param buffer The buffer containing input data.
		* @param offset The offset of the first byte of data.
		* @param count The number of bytes of data to use as input.
		*/
		setInput(buffer, offset, count) {
			const end = offset + count;
			this._inputBuf = buffer;
			this._inputOff = offset;
			this._inputEnd = end;
		}
		/**
		* Deflate drives actual compression of data
		* @param flush True to flush input buffers
		* @param finish Finish deflation with the current input.
		* @returns Returns true if progress has been made.
		*/
		deflate(flush, finish) {
			let progress;
			do {
				this.fillWindow();
				const canFlush = flush && this._inputOff === this._inputEnd;
				progress = this._deflateSlow(canFlush, finish);
			} while (this._pending.isFlushed && progress);
			return progress;
		}
		_deflateSlow(flush, finish) {
			if (this._lookahead < DeflaterConstants.minLookahead && !flush) return false;
			while (this._lookahead >= DeflaterConstants.minLookahead || flush) {
				if (this._lookahead === 0) {
					if (this._prevAvailable) this._huffman.tallyLit(this._window[this._strstart - 1] & 255);
					this._prevAvailable = false;
					this._huffman.flushBlock(this._window, this._blockStart, this._strstart - this._blockStart, finish);
					this._blockStart = this._strstart;
					return false;
				}
				if (this._strstart >= 2 * DeflaterConstants.wsize - DeflaterConstants.minLookahead) this._slideWindow();
				const prevMatch = this._matchStart;
				let prevLen = this._matchLen;
				if (this._lookahead >= DeflaterConstants.minMatch) {
					const hashHead = this._insertString();
					if (hashHead !== 0 && this._strstart - hashHead <= DeflaterConstants.maxDist && this._findLongestMatch(hashHead)) {
						if (this._matchLen === DeflaterConstants.minMatch && this._strstart - this._matchStart > DeflaterEngine._tooFar) this._matchLen = DeflaterConstants.minMatch - 1;
					}
				}
				if (prevLen >= DeflaterConstants.minMatch && this._matchLen <= prevLen) {
					this._huffman.tallyDist(this._strstart - 1 - prevMatch, prevLen);
					prevLen -= 2;
					do {
						this._strstart++;
						this._lookahead--;
						if (this._lookahead >= DeflaterConstants.minMatch) this._insertString();
					} while (--prevLen > 0);
					this._strstart++;
					this._lookahead--;
					this._prevAvailable = false;
					this._matchLen = DeflaterConstants.minMatch - 1;
				} else {
					if (this._prevAvailable) this._huffman.tallyLit(this._window[this._strstart - 1] & 255);
					this._prevAvailable = true;
					this._strstart++;
					this._lookahead--;
				}
				if (this._huffman.isFull()) {
					let len = this._strstart - this._blockStart;
					if (this._prevAvailable) len--;
					const lastBlock = finish && this._lookahead === 0 && !this._prevAvailable;
					this._huffman.flushBlock(this._window, this._blockStart, len, lastBlock);
					this._blockStart += len;
					return !lastBlock;
				}
			}
			return true;
		}
		/**
		* Find the best (longest) string in the window matching the
		* string starting at strstart.
		* @param curMatch
		* @returns True if a match greater than the minimum length is found
		*/
		_findLongestMatch(curMatch) {
			let match;
			let scan = this._strstart;
			const scanMax = scan + Math.min(DeflaterConstants.maxMatch, this._lookahead) - 1;
			const limit = Math.max(scan - DeflaterConstants.maxDist, 0);
			const window = this._window;
			const prev = this._prev;
			let chainLength = this._maxChain;
			const niceLength = Math.min(this._niceLength, this._lookahead);
			this._matchLen = Math.max(this._matchLen, DeflaterConstants.minMatch - 1);
			if (scan + this._matchLen > scanMax) return false;
			let scanEnd1 = window[scan + this._matchLen - 1];
			let scanEnd = window[scan + this._matchLen];
			if (this._matchLen >= this._goodLength) chainLength >>= 2;
			do {
				match = curMatch;
				scan = this._strstart;
				if (window[match + this._matchLen] !== scanEnd || window[match + this._matchLen - 1] !== scanEnd1 || window[match] !== window[scan] || window[++match] !== window[++scan]) continue;
				switch ((scanMax - scan) % 8) {
					case 1:
						if (window[++scan] === window[++match]) break;
						break;
					case 2:
						if (window[++scan] === window[++match] && window[++scan] === window[++match]) break;
						break;
					case 3:
						if (window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match]) break;
						break;
					case 4:
						if (window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match]) break;
						break;
					case 5:
						if (window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match]) break;
						break;
					case 6:
						if (window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match]) break;
						break;
					case 7:
						if (window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match]) break;
						break;
				}
				if (window[scan] === window[match]) do
					if (scan === scanMax) {
						++scan;
						++match;
						break;
					}
				while (window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match] && window[++scan] === window[++match]);
				if (scan - this._strstart > this._matchLen) {
					this._matchStart = curMatch;
					this._matchLen = scan - this._strstart;
					if (this._matchLen >= niceLength) break;
					scanEnd1 = window[scan - 1];
					scanEnd = window[scan];
				}
				curMatch = prev[curMatch & DeflaterConstants.wmask] & 65535;
			} while (curMatch > limit && 0 !== --chainLength);
			return this._matchLen >= DeflaterConstants.minMatch;
		}
		/**
		* Inserts the current string in the head hash and returns the previous
		* value for this hash.
		* @returns The previous hash value
		*/
		_insertString() {
			const hash = (this._insertHashIndex << DeflaterConstants.hashShift ^ this._window[this._strstart + (DeflaterConstants.minMatch - 1)]) & DeflaterConstants.hashMask;
			const match = this._head[hash];
			this._prev[this._strstart & DeflaterConstants.wmask] = match;
			this._head[hash] = this._strstart;
			this._insertHashIndex = hash;
			return match & 65535;
		}
		/**
		* Fill the window
		*/
		fillWindow() {
			if (this._strstart >= DeflaterConstants.wsize + DeflaterConstants.maxDist) this._slideWindow();
			if (this._lookahead < DeflaterConstants.minLookahead && this._inputOff < this._inputEnd) {
				let more = 2 * DeflaterConstants.wsize - this._lookahead - this._strstart;
				if (more > this._inputEnd - this._inputOff) more = this._inputEnd - this._inputOff;
				this._window.set(this._inputBuf.subarray(this._inputOff, this._inputOff + more), this._strstart + this._lookahead);
				this.inputCrc.update(this._inputBuf, this._inputOff, more);
				this._inputOff += more;
				this._lookahead += more;
			}
			if (this._lookahead >= DeflaterConstants.minMatch) this._updateHash();
		}
		_slideWindow() {
			this._window.set(this._window.subarray(DeflaterConstants.wsize, DeflaterConstants.wsize + DeflaterConstants.wsize), 0);
			this._matchStart -= DeflaterConstants.wsize;
			this._strstart -= DeflaterConstants.wsize;
			this._blockStart -= DeflaterConstants.wsize;
			for (let i = 0; i < DeflaterConstants.hashSize; ++i) {
				const m = this._head[i] & 65535;
				this._head[i] = m >= DeflaterConstants.wsize ? m - DeflaterConstants.wsize : 0;
			}
			for (let i = 0; i < DeflaterConstants.wsize; i++) {
				const m = this._prev[i] & 65535;
				this._prev[i] = m >= DeflaterConstants.wsize ? m - DeflaterConstants.wsize : 0;
			}
		}
	};
	//#endregion
	//#region src/zip/PendingBuffer.ts
	/**
	* This class is general purpose class for writing data to a buffer.
	* It allows you to write bits as well as bytes
	* Based on DeflaterPending.java
	* @internal
	*/
	var PendingBuffer = class {
		_buffer;
		_start = 0;
		_end = 0;
		_bits = 0;
		/**
		* The number of bits written to the buffer
		*/
		bitCount = 0;
		/**
		* Indicates if buffer has been flushed
		*/
		get isFlushed() {
			return this._end === 0;
		}
		/**
		* construct instance using specified buffer size
		* @param bufferSize size to use for internal buffer
		*/
		constructor(bufferSize) {
			this._buffer = new Uint8Array(bufferSize);
		}
		/**
		* Clear internal state/buffers
		*/
		reset() {
			this._start = 0;
			this._end = 0;
			this.bitCount = 0;
		}
		/**
		* Write a short value to internal buffer most significant byte first
		* @param s value to write
		*/
		writeShortMSB(s) {
			this._buffer[this._end++] = s >> 8 & 255;
			this._buffer[this._end++] = s & 255;
		}
		/**
		* Write a short value to buffer LSB first
		* @param value The value to write.
		*/
		writeShort(value) {
			this._buffer[this._end++] = value;
			this._buffer[this._end++] = value >> 8;
		}
		/**
		* Write a block of data to buffer
		* @param block data to write
		* @param offset offset of first byte to write
		* @param length number of bytes to write
		*/
		writeBlock(block, offset, length) {
			this._buffer.set(block.subarray(offset, offset + length), this._end);
			this._end += length;
		}
		/**
		* Flushes the pending buffer into the given output array.  If the
		* output array is to small, only a partial flush is done.
		* @param output The output array.
		* @param offset The offset into output array.
		* @param length The maximum number of bytes to store.
		* @returns The number of bytes flushed.
		*/
		flush(output, offset, length) {
			if (this.bitCount >= 8) {
				this._buffer[this._end++] = this._bits & 255;
				this._bits >>= 8;
				this.bitCount -= 8;
			}
			if (length > this._end - this._start) {
				length = this._end - this._start;
				output.set(this._buffer.subarray(this._start, this._start + length), offset);
				this._start = 0;
				this._end = 0;
			} else {
				output.set(this._buffer.subarray(this._start, this._start + length), offset);
				this._start += length;
			}
			return length;
		}
		/**
		* Write bits to internal buffer
		* @param b source of bits
		* @param count number of bits to write
		*/
		writeBits(b, count) {
			this._bits |= b << this.bitCount;
			this.bitCount += count;
			if (this.bitCount >= 16) {
				this._buffer[this._end++] = this._bits & 255;
				this._buffer[this._end++] = this._bits >> 8 & 255;
				this._bits >>= 16;
				this.bitCount -= 16;
			}
		}
		/**
		* Align internal buffer on a byte boundary
		*/
		alignToByte() {
			if (this.bitCount > 0) {
				this._buffer[this._end++] = this._bits & 255;
				if (this.bitCount > 8) this._buffer[this._end++] = this._bits >> 8 & 255;
			}
			this._bits = 0;
			this.bitCount = 0;
		}
	};
	//#endregion
	//#region src/zip/Deflater.ts
	/**
	* This is the Deflater class.  The deflater class compresses input
	* with the deflate algorithm described in RFC 1951.  It has several
	* compression levels and three different strategies described below.
	*
	* This class is <i>not</i> thread safe.  This is inherent in the API, due
	* to the split of deflate and setInput.
	*
	* author of the original java version : Jochen Hoenicke
	* 
	* @internal
	*/
	var Deflater = class Deflater {
		static _isFlushing = 4;
		static isFinishing = 8;
		static _busyState = 16;
		static _flushingState = 20;
		static _finishingState = 28;
		static _finishedState = 30;
		_state = 0;
		_pending;
		_engine;
		get inputCrc() {
			return this._engine.inputCrc.value;
		}
		/**
		* Creates a new deflater with given compression level
		* @param level the compression level, a value between NO_COMPRESSION and BEST_COMPRESSION.
		* beginning and the adler checksum at the end of the output.  This is
		* useful for the GZIP/PKZIP formats.
		*/
		constructor() {
			this._pending = new PendingBuffer(DeflaterConstants.pendingBufSize);
			this._engine = new DeflaterEngine(this._pending);
			this.reset();
		}
		/**
		* Returns true, if the input buffer is empty.
		* You should then call setInput().
		* NOTE: This method can also return true when the stream
		* was finished.
		*/
		get isNeedingInput() {
			return this._engine.needsInput();
		}
		/**
		* Returns true if the stream was finished and no more output bytes
		* are available.
		*/
		get isFinished() {
			return this._state === Deflater._finishedState && this._pending.isFlushed;
		}
		/**
		* Resets the deflater. The deflater acts afterwards as if it was
		* just created with the same compression level and strategy as it
		* had before.
		*/
		reset() {
			this._state = Deflater._busyState;
			this._pending.reset();
			this._engine.reset();
		}
		/**
		* Sets the data which should be compressed next.  This should be
		* only called when needsInput indicates that more input is needed.
		* The given byte array should not be changed, before needsInput() returns
		* true again.
		* @param input the buffer containing the input data.
		* @param offset the start of the data.
		* @param count the number of data bytes of input.
		*/
		setInput(input, offset, count) {
			this._engine.setInput(input, offset, count);
		}
		/**
		* Deflates the current input block to the given array.
		* @param output Buffer to store the compressed data.
		* @param offset Offset into the output array.
		* @param length The maximum number of bytes that may be stored.
		* @returns The number of compressed bytes added to the output, or 0 if either
		* needsInput() or finished() returns true or length is zero.
		*/
		deflate(output, offset, length) {
			const origLength = length;
			while (true) {
				const count = this._pending.flush(output, offset, length);
				offset += count;
				length -= count;
				if (length === 0 || this._state === Deflater._finishedState) break;
				if (!this._engine.deflate((this._state & Deflater._isFlushing) !== 0, (this._state & Deflater.isFinishing) !== 0)) switch (this._state) {
					case Deflater._busyState: return origLength - length;
					case Deflater._flushingState:
						let neededbits = 8 + (-this._pending.bitCount & 7);
						while (neededbits > 0) {
							this._pending.writeBits(2, 10);
							neededbits -= 10;
						}
						this._state = Deflater._busyState;
						break;
					case Deflater._finishingState:
						this._pending.alignToByte();
						this._state = Deflater._finishedState;
						break;
				}
			}
			return origLength - length;
		}
		/**
		* Finishes the deflater with the current input block.  It is an error
		* to give more input after this method was called.  This method must
		* be called to force all bytes to be flushed.
		*/
		finish() {
			this._state |= Deflater._isFlushing | Deflater.isFinishing;
		}
	};
	//#endregion
	//#region src/zip/ZipWriter.ts
	/**
	* @internal
	*/
	var ZipCentralDirectoryHeader = class {
		entry;
		localHeaderOffset;
		compressedSize;
		crc32;
		compressionMode;
		constructor(entry, crc32, localHeaderOffset, compressionMode, compressedSize) {
			this.entry = entry;
			this.crc32 = crc32;
			this.localHeaderOffset = localHeaderOffset;
			this.compressionMode = compressionMode;
			this.compressedSize = compressedSize;
		}
	};
	/**
	* @internal
	*/
	var ZipWriter = class {
		_data;
		_centralDirectoryHeaders = [];
		_deflater = new Deflater();
		constructor(data) {
			this._data = data;
		}
		writeEntry(entry) {
			const compressionMode = ZipEntry.CompressionMethodDeflate;
			const compressedData = ByteBuffer.empty();
			const crc32 = this._compress(compressedData, entry.data, compressionMode);
			const compressedDataArray = compressedData.toArray();
			const directoryHeader = new ZipCentralDirectoryHeader(entry, crc32, this._data.bytesWritten, compressionMode, compressedData.length);
			this._centralDirectoryHeaders.push(directoryHeader);
			IOHelper.writeInt32LE(this._data, ZipEntry.LocalFileHeaderSignature);
			IOHelper.writeUInt16LE(this._data, 10);
			IOHelper.writeUInt16LE(this._data, 2048);
			IOHelper.writeUInt16LE(this._data, compressionMode);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt32LE(this._data, crc32);
			IOHelper.writeInt32LE(this._data, compressedDataArray.length);
			IOHelper.writeInt32LE(this._data, entry.data.length);
			IOHelper.writeInt16LE(this._data, entry.fullName.length);
			IOHelper.writeInt16LE(this._data, 0);
			const fileNameBuffer = IOHelper.stringToBytes(entry.fullName);
			this._data.write(fileNameBuffer, 0, fileNameBuffer.length);
			this._data.write(compressedDataArray, 0, compressedDataArray.length);
		}
		_compress(output, data, compressionMode) {
			if (compressionMode !== ZipEntry.CompressionMethodDeflate) {
				const crc = new Crc32();
				crc.update(data, 0, data.length);
				output.write(data, 0, data.length);
				return crc.value;
			}
			const buffer = new Uint8Array(512);
			this._deflater.reset();
			this._deflater.setInput(data, 0, data.length);
			while (!this._deflater.isNeedingInput) {
				const len = this._deflater.deflate(buffer, 0, buffer.length);
				if (len <= 0) break;
				output.write(buffer, 0, len);
			}
			this._deflater.finish();
			while (!this._deflater.isFinished) {
				const len = this._deflater.deflate(buffer, 0, buffer.length);
				if (len <= 0) break;
				output.write(buffer, 0, len);
			}
			return this._deflater.inputCrc;
		}
		end() {
			const startOfCentralDirectory = this._data.bytesWritten;
			for (const header of this._centralDirectoryHeaders) this._writeCentralDirectoryHeader(header);
			const endOfCentralDirectory = this._data.bytesWritten;
			this._writeEndOfCentralDirectoryRecord(startOfCentralDirectory, endOfCentralDirectory);
		}
		_writeEndOfCentralDirectoryRecord(startOfCentralDirectory, endOfCentralDirectory) {
			IOHelper.writeInt32LE(this._data, ZipEntry.EndOfCentralDirSignature);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt16LE(this._data, this._centralDirectoryHeaders.length);
			IOHelper.writeInt16LE(this._data, this._centralDirectoryHeaders.length);
			IOHelper.writeInt32LE(this._data, endOfCentralDirectory - startOfCentralDirectory);
			IOHelper.writeInt32LE(this._data, startOfCentralDirectory);
			IOHelper.writeInt16LE(this._data, 0);
		}
		_writeCentralDirectoryHeader(header) {
			IOHelper.writeInt32LE(this._data, ZipEntry.CentralFileHeaderSignature);
			IOHelper.writeUInt16LE(this._data, 10);
			IOHelper.writeUInt16LE(this._data, 10);
			IOHelper.writeUInt16LE(this._data, 2048);
			IOHelper.writeUInt16LE(this._data, header.compressionMode);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt32LE(this._data, header.crc32);
			IOHelper.writeInt32LE(this._data, header.compressedSize);
			IOHelper.writeInt32LE(this._data, header.entry.data.length);
			IOHelper.writeInt16LE(this._data, header.entry.fullName.length);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt16LE(this._data, 0);
			IOHelper.writeInt32LE(this._data, 0);
			IOHelper.writeInt32LE(this._data, header.localHeaderOffset);
			const fileNameBuffer = IOHelper.stringToBytes(header.entry.fullName);
			this._data.write(fileNameBuffer, 0, fileNameBuffer.length);
		}
	};
	//#endregion
	//#region src/exporter/Gp7Exporter.ts
	/**
	* This ScoreExporter can write Guitar Pro 7+ (gp) files.
	* @public
	*/
	var Gp7Exporter = class extends ScoreExporter {
		get name() {
			return "Guitar Pro 7-8";
		}
		writeScore(score) {
			Logger.debug(this.name, "Writing data entries");
			const gpifWriter = new GpifWriter();
			const gpifXml = gpifWriter.writeXml(score);
			const binaryStylesheet = BinaryStylesheet.writeForScore(score);
			const partConfiguration = PartConfiguration.writeForScore(score);
			const layoutConfiguration = LayoutConfiguration.writeForScore(score);
			Logger.debug(this.name, "Writing ZIP entries");
			const fileSystem = new ZipWriter(this.data);
			fileSystem.writeEntry(new ZipEntry("VERSION", IOHelper.stringToBytes("7.0")));
			fileSystem.writeEntry(new ZipEntry("Content/", new Uint8Array(0)));
			fileSystem.writeEntry(new ZipEntry("Content/BinaryStylesheet", binaryStylesheet));
			fileSystem.writeEntry(new ZipEntry("Content/PartConfiguration", partConfiguration));
			fileSystem.writeEntry(new ZipEntry("Content/LayoutConfiguration", layoutConfiguration));
			fileSystem.writeEntry(new ZipEntry("Content/score.gpif", IOHelper.stringToBytes(gpifXml)));
			if (gpifWriter.backingTrackAssetFileName) fileSystem.writeEntry(new ZipEntry(gpifWriter.backingTrackAssetFileName, score.backingTrack.rawAudioFile));
			fileSystem.end();
		}
	};
	//#endregion
	//#region src/exporter/_barrel.ts
	var _barrel_exports = /* @__PURE__ */ __exportAll({
		AlphaTexExporter: () => AlphaTexExporter,
		Gp7Exporter: () => Gp7Exporter,
		ScoreExporter: () => ScoreExporter
	});
	//#endregion
	//#region src/midi/DeprecatedEvents.ts
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var DeprecatedMidiEvent = class extends MidiEvent {
		constructor() {
			super(0, 0, MidiEventType.EndOfTrack);
		}
		writeTo(_s) {
			throw new AlphaTabError(AlphaTabErrorType.General, "Deprecated event, serialization not supported");
		}
	};
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var MetaEventType = /* @__PURE__ */ function(MetaEventType) {
		MetaEventType[MetaEventType["SequenceNumber"] = 0] = "SequenceNumber";
		MetaEventType[MetaEventType["TextEvent"] = 1] = "TextEvent";
		MetaEventType[MetaEventType["CopyrightNotice"] = 2] = "CopyrightNotice";
		MetaEventType[MetaEventType["SequenceOrTrackName"] = 3] = "SequenceOrTrackName";
		MetaEventType[MetaEventType["InstrumentName"] = 4] = "InstrumentName";
		MetaEventType[MetaEventType["LyricText"] = 5] = "LyricText";
		MetaEventType[MetaEventType["MarkerText"] = 6] = "MarkerText";
		MetaEventType[MetaEventType["CuePoint"] = 7] = "CuePoint";
		MetaEventType[MetaEventType["PatchName"] = 8] = "PatchName";
		MetaEventType[MetaEventType["PortName"] = 9] = "PortName";
		MetaEventType[MetaEventType["MidiChannel"] = 32] = "MidiChannel";
		MetaEventType[MetaEventType["MidiPort"] = 33] = "MidiPort";
		MetaEventType[MetaEventType["EndOfTrack"] = 47] = "EndOfTrack";
		MetaEventType[MetaEventType["Tempo"] = 81] = "Tempo";
		MetaEventType[MetaEventType["SmpteOffset"] = 84] = "SmpteOffset";
		MetaEventType[MetaEventType["TimeSignature"] = 88] = "TimeSignature";
		MetaEventType[MetaEventType["KeySignature"] = 89] = "KeySignature";
		MetaEventType[MetaEventType["SequencerSpecific"] = 127] = "SequencerSpecific";
		return MetaEventType;
	}({});
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var MetaEvent = class extends DeprecatedMidiEvent {
		get metaStatus() {
			return 47;
		}
	};
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var MetaDataEvent = class extends MetaEvent {
		data = new Uint8Array();
	};
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var MetaNumberEvent = class extends MetaEvent {
		value = 0;
	};
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var Midi20PerNotePitchBendEvent = class extends DeprecatedMidiEvent {
		noteKey = 0;
		pitch = 0;
	};
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var SystemCommonType = /* @__PURE__ */ function(SystemCommonType) {
		SystemCommonType[SystemCommonType["SystemExclusive"] = 240] = "SystemExclusive";
		SystemCommonType[SystemCommonType["MtcQuarterFrame"] = 241] = "MtcQuarterFrame";
		SystemCommonType[SystemCommonType["SongPosition"] = 242] = "SongPosition";
		SystemCommonType[SystemCommonType["SongSelect"] = 243] = "SongSelect";
		SystemCommonType[SystemCommonType["TuneRequest"] = 246] = "TuneRequest";
		SystemCommonType[SystemCommonType["SystemExclusive2"] = 247] = "SystemExclusive2";
		return SystemCommonType;
	}({});
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var SystemCommonEvent = class extends DeprecatedMidiEvent {};
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var AlphaTabSystemExclusiveEvents = /* @__PURE__ */ function(AlphaTabSystemExclusiveEvents) {
		AlphaTabSystemExclusiveEvents[AlphaTabSystemExclusiveEvents["MetronomeTick"] = 0] = "MetronomeTick";
		AlphaTabSystemExclusiveEvents[AlphaTabSystemExclusiveEvents["Rest"] = 1] = "Rest";
		return AlphaTabSystemExclusiveEvents;
	}({});
	/**
	* @deprecated Move to the new concrete Midi Event Types.
	* @public
	*/
	var SystemExclusiveEvent = class extends SystemCommonEvent {
		static AlphaTabManufacturerId = 125;
		data = new Uint8Array();
		get isMetronome() {
			return false;
		}
		get metronomeNumerator() {
			return -1;
		}
		get metronomeDurationInTicks() {
			return -1;
		}
		get metronomeDurationInMilliseconds() {
			return -1;
		}
		get isRest() {
			return false;
		}
		get manufacturerId() {
			return 0;
		}
	};
	//#endregion
	//#region src/midi/_barrel.ts
	var _barrel_exports$3 = /* @__PURE__ */ __exportAll({
		AlphaSynthMidiFileHandler: () => AlphaSynthMidiFileHandler,
		AlphaTabMetronomeEvent: () => AlphaTabMetronomeEvent,
		AlphaTabRestEvent: () => AlphaTabRestEvent,
		AlphaTabSysExEvent: () => AlphaTabSysExEvent,
		AlphaTabSystemExclusiveEvents: () => AlphaTabSystemExclusiveEvents,
		BeatTickLookup: () => BeatTickLookup,
		BeatTickLookupItem: () => BeatTickLookupItem,
		ControlChangeEvent: () => ControlChangeEvent,
		ControllerType: () => ControllerType,
		DeprecatedMidiEvent: () => DeprecatedMidiEvent,
		EndOfTrackEvent: () => EndOfTrackEvent,
		MasterBarTickLookup: () => MasterBarTickLookup,
		MasterBarTickLookupTempoChange: () => MasterBarTickLookupTempoChange,
		MetaDataEvent: () => MetaDataEvent,
		MetaEvent: () => MetaEvent,
		MetaEventType: () => MetaEventType,
		MetaNumberEvent: () => MetaNumberEvent,
		Midi20PerNotePitchBendEvent: () => Midi20PerNotePitchBendEvent,
		MidiEvent: () => MidiEvent,
		MidiEventType: () => MidiEventType,
		MidiFile: () => MidiFile,
		MidiFileFormat: () => MidiFileFormat,
		MidiFileGenerator: () => MidiFileGenerator,
		MidiTickLookup: () => MidiTickLookup,
		MidiTickLookupFindBeatResult: () => MidiTickLookupFindBeatResult,
		MidiTickLookupFindBeatResultCursorMode: () => MidiTickLookupFindBeatResultCursorMode,
		MidiTrack: () => MidiTrack,
		NoteBendEvent: () => NoteBendEvent,
		NoteEvent: () => NoteEvent,
		NoteOffEvent: () => NoteOffEvent,
		NoteOnEvent: () => NoteOnEvent,
		PitchBendEvent: () => PitchBendEvent,
		ProgramChangeEvent: () => ProgramChangeEvent,
		SystemCommonEvent: () => SystemCommonEvent,
		SystemCommonType: () => SystemCommonType,
		SystemExclusiveEvent: () => SystemExclusiveEvent,
		TempoChangeEvent: () => TempoChangeEvent,
		TimeSignatureEvent: () => TimeSignatureEvent
	});
	//#endregion
	//#region src/model/_barrel.ts
	var _barrel_exports$4 = /* @__PURE__ */ __exportAll({
		AccentuationType: () => AccentuationType,
		AccidentalType: () => AccidentalType,
		Automation: () => Automation,
		AutomationType: () => AutomationType,
		BackingTrack: () => BackingTrack,
		Bar: () => Bar,
		BarLineStyle: () => BarLineStyle,
		BarNumberDisplay: () => BarNumberDisplay,
		BarStyle: () => BarStyle,
		BarSubElement: () => BarSubElement,
		BarreShape: () => BarreShape,
		BeamingRules: () => BeamingRules,
		Beat: () => Beat,
		BeatBeamingMode: () => BeatBeamingMode,
		BeatStyle: () => BeatStyle,
		BeatSubElement: () => BeatSubElement,
		BendPoint: () => BendPoint,
		BendStyle: () => BendStyle,
		BendType: () => BendType,
		BracketExtendMode: () => BracketExtendMode,
		BrushType: () => BrushType,
		Chord: () => Chord,
		Clef: () => Clef,
		Color: () => Color,
		CrescendoType: () => CrescendoType,
		Direction: () => Direction,
		Duration: () => Duration,
		DynamicValue: () => DynamicValue,
		ElementStyle: () => ElementStyle,
		FadeType: () => FadeType,
		Fermata: () => Fermata,
		FermataType: () => FermataType,
		Fingers: () => Fingers,
		Font: () => Font,
		FontStyle: () => FontStyle,
		FontWeight: () => FontWeight,
		GolpeType: () => GolpeType,
		GraceGroup: () => GraceGroup,
		GraceType: () => GraceType,
		HarmonicType: () => HarmonicType,
		HeaderFooterStyle: () => HeaderFooterStyle,
		InstrumentArticulation: () => InstrumentArticulation,
		JsonConverter: () => JsonConverter,
		KeySignature: () => KeySignature,
		KeySignatureType: () => KeySignatureType,
		Lyrics: () => Lyrics,
		MasterBar: () => MasterBar,
		MusicFontSymbol: () => MusicFontSymbol,
		Note: () => Note,
		NoteAccidentalMode: () => NoteAccidentalMode,
		NoteOrnament: () => NoteOrnament,
		NoteStyle: () => NoteStyle,
		NoteSubElement: () => NoteSubElement,
		Ottavia: () => Ottavia,
		PickStroke: () => PickStroke,
		PlaybackInformation: () => PlaybackInformation,
		Rasgueado: () => Rasgueado,
		RenderStylesheet: () => RenderStylesheet,
		RepeatGroup: () => RepeatGroup,
		Score: () => Score,
		ScoreStyle: () => ScoreStyle,
		ScoreSubElement: () => ScoreSubElement,
		Section: () => Section,
		SimileMark: () => SimileMark,
		SlideInType: () => SlideInType,
		SlideOutType: () => SlideOutType,
		Staff: () => Staff,
		SustainPedalMarker: () => SustainPedalMarker,
		SustainPedalMarkerType: () => SustainPedalMarkerType,
		SyncPointData: () => SyncPointData,
		TechniqueSymbolPlacement: () => TechniqueSymbolPlacement,
		Track: () => Track,
		TrackNameMode: () => TrackNameMode,
		TrackNameOrientation: () => TrackNameOrientation,
		TrackNamePolicy: () => TrackNamePolicy,
		TrackStyle: () => TrackStyle,
		TrackSubElement: () => TrackSubElement,
		TremoloPickingEffect: () => TremoloPickingEffect,
		TremoloPickingStyle: () => TremoloPickingStyle,
		TripletFeel: () => TripletFeel,
		Tuning: () => Tuning,
		TupletGroup: () => TupletGroup,
		VibratoType: () => VibratoType,
		Voice: () => Voice$1,
		VoiceStyle: () => VoiceStyle,
		VoiceSubElement: () => VoiceSubElement,
		WahPedal: () => WahPedal,
		WhammyType: () => WhammyType
	});
	//#endregion
	//#region src/rendering/_barrel.ts
	var _barrel_exports$6 = /* @__PURE__ */ __exportAll({
		BarBounds: () => BarBounds,
		BeamDirection: () => BeamDirection,
		BeatBounds: () => BeatBounds,
		Bounds: () => Bounds,
		BoundsLookup: () => BoundsLookup,
		MasterBarBounds: () => MasterBarBounds,
		NoteBounds: () => NoteBounds,
		RenderFinishedEventArgs: () => RenderFinishedEventArgs,
		ScoreRenderer: () => ScoreRenderer,
		StaffSystemBounds: () => StaffSystemBounds
	});
	//#endregion
	//#region src/platform/_barrel.ts
	var _barrel_exports$5 = /* @__PURE__ */ __exportAll({
		CssFontSvgCanvas: () => CssFontSvgCanvas,
		Cursors: () => Cursors,
		FontSizeDefinition: () => FontSizeDefinition,
		FontSizes: () => FontSizes,
		MeasuredText: () => MeasuredText,
		SvgCanvas: () => SvgCanvas,
		TextAlign: () => TextAlign,
		TextBaseline: () => TextBaseline
	});
	//#endregion
	//#region src/synth/_barrel.ts
	var _barrel_exports$7 = /* @__PURE__ */ __exportAll({
		ActiveBeatsChangedEventArgs: () => ActiveBeatsChangedEventArgs,
		AlphaSynth: () => AlphaSynth,
		AlphaSynthAudioWorkletOutput: () => AlphaSynthAudioWorkletOutput,
		AlphaSynthBase: () => AlphaSynthBase,
		AlphaSynthScriptProcessorOutput: () => AlphaSynthScriptProcessorOutput,
		AlphaSynthWebAudioOutputBase: () => AlphaSynthWebAudioOutputBase,
		AlphaSynthWebWorkerApi: () => AlphaSynthWebWorkerApi,
		AudioExportChunk: () => AudioExportChunk,
		AudioExportOptions: () => AudioExportOptions,
		BackingTrackSyncPoint: () => BackingTrackSyncPoint,
		CircularSampleBuffer: () => CircularSampleBuffer,
		MidiEventsPlayedEventArgs: () => MidiEventsPlayedEventArgs,
		PlaybackRange: () => PlaybackRange,
		PlaybackRangeChangedEventArgs: () => PlaybackRangeChangedEventArgs,
		PlayerState: () => PlayerState,
		PlayerStateChangedEventArgs: () => PlayerStateChangedEventArgs,
		PositionChangedEventArgs: () => PositionChangedEventArgs
	});
	//#endregion
	//#region src/generated/_jsonbarrel.ts
	var _jsonbarrel_exports = /* @__PURE__ */ __exportAll({});
	//#endregion
	//#region src/alphaTab.main.ts
	if (Environment.isRunningInWorker) Environment.initializeWorker();
	else if (Environment.isRunningInAudioWorklet) Environment.initializeAudioWorklet();
	else Environment.initializeMain((settings) => {
		if (Environment.webPlatform === WebPlatform.NodeJs) throw new AlphaTabError(AlphaTabErrorType.General, "Workers not yet supported in Node.js");
		if (Environment.webPlatform === WebPlatform.BrowserModule || Environment.isWebPackBundled || Environment.isViteBundled) {
			Logger.debug("AlphaTab", "Creating webworker");
			try {
				return new Environment.alphaTabWorker(new Environment.alphaTabUrl("./alphaTab.worker.ts", {}.url), { type: "module" });
			} catch (e) {
				Logger.debug("AlphaTab", "ESM webworker construction with direct URL failed", e);
			}
			let workerUrl = "";
			try {
				workerUrl = new Environment.alphaTabUrl("./alphaTab.worker.ts", {}.url);
				const script = `import ${JSON.stringify(workerUrl)}`;
				const blob = new Blob([script], { type: "application/javascript" });
				return new Worker(URL.createObjectURL(blob), { type: "module" });
			} catch (e) {
				Logger.debug("AlphaTab", "ESM webworker construction with blob import failed", workerUrl, e);
			}
			try {
				if (!settings.core.scriptFile) throw new Error("Could not detect alphaTab script file");
				workerUrl = settings.core.scriptFile;
				const script = `import ${JSON.stringify(settings.core.scriptFile)}`;
				const blob = new Blob([script], { type: "application/javascript" });
				return new Worker(URL.createObjectURL(blob), { type: "module" });
			} catch (e) {
				Logger.debug("AlphaTab", "ESM webworker construction with blob import failed", settings.core.scriptFile, e);
			}
		}
		if (!settings.core.scriptFile) throw new AlphaTabError(AlphaTabErrorType.General, "Could not detect alphaTab script file, cannot initialize renderer");
		try {
			Logger.debug("AlphaTab", "Creating Blob worker");
			const script = `importScripts('${settings.core.scriptFile}')`;
			const blob = new Blob([script], { type: "application/javascript" });
			return new Worker(URL.createObjectURL(blob));
		} catch {
			Logger.warning("Rendering", "Could not create inline worker, fallback to normal worker");
			return new Worker(settings.core.scriptFile);
		}
	}, (context, settings) => {
		if (Environment.webPlatform === WebPlatform.NodeJs) throw new AlphaTabError(AlphaTabErrorType.General, "Audio Worklets not yet supported in Node.js");
		if (Environment.webPlatform === WebPlatform.BrowserModule || Environment.isWebPackBundled || Environment.isViteBundled) {
			Logger.debug("AlphaTab", "Creating Module worklet");
			const { audioWorklet: alphaTabWorklet } = context;
			return alphaTabWorklet.addModule(new Environment.alphaTabUrl("./alphaTab.worklet.ts", {}.url));
		}
		Logger.debug("AlphaTab", "Creating Script worklet");
		return context.audioWorklet.addModule(settings.core.scriptFile);
	});
	//#endregion
	exports.AlphaTabApi = AlphaTabApi;
	exports.AlphaTabApiBase = AlphaTabApiBase;
	exports.AlphaTabError = AlphaTabError;
	exports.AlphaTabErrorType = AlphaTabErrorType;
	exports.ConsoleLogger = ConsoleLogger;
	exports.CoreSettings = CoreSettings;
	exports.DisplaySettings = DisplaySettings;
	exports.EngravingSettings = EngravingSettings;
	exports.EngravingStemInfo = EngravingStemInfo;
	exports.Environment = Environment;
	exports.ExporterSettings = ExporterSettings;
	exports.FileLoadError = FileLoadError;
	exports.FingeringMode = FingeringMode;
	exports.FontFileFormat = FontFileFormat;
	exports.FormatError = FormatError;
	exports.ImporterSettings = ImporterSettings;
	exports.LayoutMode = LayoutMode;
	exports.LogLevel = LogLevel;
	exports.Logger = Logger;
	exports.NotationElement = NotationElement;
	exports.NotationMode = NotationMode;
	exports.NotationSettings = NotationSettings;
	exports.PlayerMode = PlayerMode;
	exports.PlayerOutputMode = PlayerOutputMode;
	exports.PlayerSettings = PlayerSettings;
	exports.ProgressEventArgs = ProgressEventArgs;
	exports.RenderEngineFactory = RenderEngineFactory;
	exports.RenderingResources = RenderingResources;
	exports.ResizeEventArgs = ResizeEventArgs;
	exports.ScrollMode = ScrollMode;
	exports.Settings = Settings;
	exports.SlidePlaybackSettings = SlidePlaybackSettings;
	exports.StaveProfile = StaveProfile;
	exports.SystemsLayoutMode = SystemsLayoutMode;
	exports.TabRhythmMode = TabRhythmMode;
	exports.VibratoPlaybackSettings = VibratoPlaybackSettings;
	exports.WebPlatform = WebPlatform;
	Object.defineProperty(exports, "exporter", {
		enumerable: true,
		get: function() {
			return _barrel_exports;
		}
	});
	Object.defineProperty(exports, "importer", {
		enumerable: true,
		get: function() {
			return _barrel_exports$1;
		}
	});
	Object.defineProperty(exports, "io", {
		enumerable: true,
		get: function() {
			return _barrel_exports$2;
		}
	});
	Object.defineProperty(exports, "json", {
		enumerable: true,
		get: function() {
			return _jsonbarrel_exports;
		}
	});
	exports.meta = VersionInfo;
	Object.defineProperty(exports, "midi", {
		enumerable: true,
		get: function() {
			return _barrel_exports$3;
		}
	});
	Object.defineProperty(exports, "model", {
		enumerable: true,
		get: function() {
			return _barrel_exports$4;
		}
	});
	Object.defineProperty(exports, "platform", {
		enumerable: true,
		get: function() {
			return _barrel_exports$5;
		}
	});
	Object.defineProperty(exports, "rendering", {
		enumerable: true,
		get: function() {
			return _barrel_exports$6;
		}
	});
	Object.defineProperty(exports, "synth", {
		enumerable: true,
		get: function() {
			return _barrel_exports$7;
		}
	});
});
