v1.9
1.9.0โ
This release gives the alphaTab attribution a smaller, quieter place in the score, renders faster with about half the memory, reworks note spacing and the placement of annotations, adds per-staff control over clefs, key and time signatures and bar numbers, plays repeats and jumps in the right order, imports MusicXML files more faithfully, and loads alphaTab's core once for the page, its workers and its Audio Worklet with webpack, Rspack, Vite and Turbopack. The website is rebuilt and now lives in the alphaTab repository. The upgrade notes at the end list the visual changes, changed defaults and deprecations.
Attributionโ
render: a smaller, quieter attributionโ
The "rendered by alphaTab" line below the score is replaced by a small "โช alphaTab.net" above the top staff at the end of the first system. It is drawn in the staff line color and adds no extra line. Songs with up to 10 bars and at most 2 tracks show no attribution at all.
Many projects hid the attribution without our consent and without crediting alphaTab elsewhere. The attribution is now part of how the score is drawn and much harder to remove; there is no setting to turn it off. If you have permission for a different credit and the new placement does not fit, get in touch.
The new Attribution page explains why we ask for credit, which alternative credits work, and offers logos and badges to download.
license: planned move to CPAL-1.0 or similarโ
A future release will move from MPL-2.0 to an open-source license with an attribution clause. The choice is not settled yet; CPAL-1.0 is the best fit we see so far. alphaTab stays open source and free, also for commercial use, and releases under MPL-2.0, including this one, stay under MPL-2.0. See what changes.
Performanceโ
render: faster rendering and resizingโ
https://github.com/CoderLine/alphaTab/pull/2997 https://github.com/CoderLine/alphaTab/pull/2751
Compared with 1.8.4, rendering a song takes about a third less time, resizing up to 40 % less, and both allocate about half the memory. A resize now gives the same layout as a fresh render at that width. In the browser, the worker exchanges less data with the page, parts of the score far out of view release their memory, and the MIDI is generated once per load.
Full demo and all options: Responsive resize.
Music Notationโ
render: power-law note spacing and last-system justificationโ
https://github.com/CoderLine/alphaTab/pull/2749
alphaTab spaces notes with a power-law model, the approach Dorico, MuseScore and Finale use: doubling a duration multiplies its width by display.spacingRatio. The default is Math.SQRT2 (about 1.414, as in Dorico); values are clamped to 1.2โ2.0. Whole notes and rest bars follow the same ratio, so how much of a system they take depends on spacingRatio. display.stretchForce still sets the overall density.
The same four bars with spacingRatio 1.2 (first) and the default (second):
display.lastSystemFillThreshold decides when the last system stretches to the full width: once its natural width reaches the given fraction of the available width. 1 (default) never stretches it, 0 always does, and values between 0.4 and 0.7 behave like Dorico and MuseScore. It replaces display.justifyLastSystem.
Full demo and all options: Density and spacing.
Thanks to @AvaTheArchitect for the discussion that led to this.
render: effect placement against the notationโ
https://github.com/CoderLine/alphaTab/pull/2750
Texts, chord names, dynamics, palm-mute and let-ring brackets and the other annotations are placed against the outline of the notation (the skyline) instead of in rows spanning the whole system. An annotation moves away from the staff only where a note, stem, beam or another annotation is in the way. Charts with many annotations need less vertical space.
\track "Guitar"
\staff {score tabs}
:8 (0.5 2.4){ch "Am" dy mf} 2.3{lr} 1.2{lr} 0.1{lr} 1.2 2.3{txt "rit."} :4 2.4 |
:8 0.6{pm} 0.6{pm} 3.6{pm} 0.6{pm} :16 12.1{txt "solo" h} 15.1{h} 12.1 14.2 :8 17.1{v} 12.1
Am and rit. sit right above the low notes of the first bar, while the high sixteenth notes in the second bar push the labels and solo up. The placement is always active. display.effectBandPaddingBottom sets the gap between an annotation row and the staff or the row below it.
Full demo and all options: Effect placement.
notation: per-staff display of clefs, key and time signatures, bar numbers and tab restsโ
https://github.com/CoderLine/alphaTab/pull/2752 https://github.com/CoderLine/alphaTab/pull/2946
Each staff type (standard notation, tablature, slash and numbered notation) has its own configuration for the elements it can draw: clef, key signature, time signature, bar numbers and, on tablature, rests. Each element can be hidden, drawn only on the topmost staff type of a staff, or drawn only in the first system. You set this score-wide on the stylesheet (RenderStylesheet.scoreConfig and its siblings), per staff (Staff.scoreConfig) or per bar (Bar.scoreDisplay). The values are ElementDisplay records.
\staff {score tabs}
\staffDisplay tabs { clefVisibility false tsPlacement allStaves restsPlacement allStaves }
:4 3.3 r 0.2 1.2 | 3.2 1.2 r 0.2
The tab staff drops its TAB clef and repeats the time signature and the rests, which alphaTab otherwise draws only on the standard notation staff above it. The defaults render as before, apart from bar numbers (see the next item).
Full demo and all options: Staff element display.
notation: bar numbering with pick-up bars, custom numbers and textsโ
https://github.com/CoderLine/alphaTab/pull/2907
Bar numbers belong to the master bar. Pick-up bars get no number and do not count. MasterBar.customBarNumber restarts the count, and MasterBar.customBarNumberText shows a text such as 1a instead of the number. In alphaTex, \barNumber sets either one.
\defaultBarNumberDisplay allBars
\ac :4 G4 |
:2 C5 E5 |
\barNumber "1a" :2 D5 F5 |
\barNumber 5 :1 C5
The pick-up bar has no number, the third bar shows 1a, and the last bar restarts the count at 5. By default, alphaTab now numbers only the first bar of each system. The number is centered above the start barline and no longer adds space at the start of the bar. Clef, key signature and time signature line up across the staves of a system. Multi-bar rests show their number too. The MusicXML importer reads the number attribute of each measure.
Full demo and all options: Bar numbers.
notation: tuning on the staff linesโ
https://github.com/CoderLine/alphaTab/pull/2742
alphaTab can write the note name of each open string at the left end of its tab line on the first system, instead of the tuning block above the score. This matches the "tuning before staff" option in Guitar Pro. Select it with RenderStylesheet.tuningDisplayMode set to TuningDisplayMode.Staff, or with \tuningDisplayMode staff in alphaTex. display.inlineTuningPaddingRight sets the gap between the labels and the staff.
\tuningDisplayMode staff
\track "Guitar"
\staff { tabs }
\tuning (E4 B3 G3 D3 A2 D2)
:8 0.6 2.4 0.3 2.2 0.1 2.2 0.3 2.4
Guitar Pro 7 and 8 files store the mode in their stylesheet; alphaTab reads it and the Guitar Pro 7 exporter writes it.
Full demo and all options: Tuning display.
Thanks to @kulek1 for contributing this feature, and to @AvaTheArchitect for the discussion that led to it.
notation: drum tablatureโ
https://github.com/CoderLine/alphaTab/pull/2591 https://github.com/CoderLine/alphaTab/pull/2990
Percussion staves can render as a drum tablature, as in Guitar Pro and TuxGuitar. Each drum piece sits on a line, and the number on the line is its articulation number. Turn it on with Staff.showTablature, or with \staff { score tabs } in alphaTex. In alphaTex, @ assigns the line of a percussion note: SnareHit@3 places the snare on line 3.
\track "Drums" { instrument percussion }
\staff { score tabs }
\clef neutral
\articulation defaults
:4 (KickHit@5 HiHatClosed@1) (SnareHit@3 HiHatClosed@1) (KickHit@5 HiHatClosed@1) (SnareHit@3 HiHatClosed@1)
Guitar Pro files show the drum tablature where the file turns it on, and Guitar Pro 7 and 8 files keep the line of every drum note on import and export.
Full demo and all options: Drum and percussion notation.
Thanks to @leocaseiro for contributing this feature, and to @sugizo for the discussion that led to it.
notation: hammer-on, pull-off and slide labels above the staffโ
https://github.com/CoderLine/alphaTab/pull/2945 https://github.com/CoderLine/alphaTab/pull/2943
The H, P and sl. labels introduced in 1.8.3 are drawn above the staff instead of on the slur arcs, on standard notation, tablature and numbered notation. Each beat gets one label, centered on its slur segment; different labels on one beat stack. A segment across a system break is labeled on the first system only. Regular slurs carry no label.
Slurs between chords follow Behind Bars and Guitar Pro: on standard notation one slur joins the outer noteheads of the chord, on tablature each beat gets at most one arc above and one below. On narrow screens these slurs no longer disappear.
\staff {score tabs}
:4 r r 5.3{h} 7.3{h} | 5.3 r r (5.1{h} 5.2{sl}) | (7.1 9.2) r r r
Hide the labels with NotationElement.EffectHammerOnPullOffText and NotationElement.EffectSlideText in notation.elements.
Full demo and all options: Effects and articulations.
Thanks to @shimabox for reporting the problem with slurs between chords.
notation: centered full-bar notes and restsโ
https://github.com/CoderLine/alphaTab/pull/2781
When a bar holds a single beat that lasts the whole bar, alphaTab centers it in the bar together with its annotations, following Behind Bars. This applies when every staff and voice rendered in the bar has one such beat; other bars keep the regular positioning.
\hideDynamics
:1 C5 | r.1 | \ts (3 4) :2 C5{d} | r.2{d}
Full demo and all options: Rests and full-bar notes.
Thanks to @comus111 for the discussion that led to this.
notation: rest position per beatโ
https://github.com/CoderLine/alphaTab/pull/2721
A rest can take the staff position of a given pitch instead of the automatic one. In alphaTex, write the beat property restDisplayPitch; in the model, set Beat.restDisplayTone and Beat.restDisplayOctave. The position follows the clef and works per voice.
\hideDynamics
:4 r C5 r C5 | r{restDisplayPitch A5} C5 r{restDisplayPitch E4} C5
The first bar shows the automatic positions, the second bar moves the rests to A5 and E4. alphaTab does not read rest positions from Guitar Pro or MusicXML files, and the alphaTex exporter does not write restDisplayPitch.
Full demo and all options: Rests and full-bar notes.
Thanks to @roscopeeco for contributing this feature.
Other changesโ
- render: ties and slurs that continue on a new system start after the clef, key signature and time signature instead of at the left edge of the staff (#2800, thanks @GiovanniSlabs for contributing this fix)
- render: tab staves with slashed beats render stems, beams and dots in place when
notation.rhythmModeshows tab rhythm, instead of failing or drawing them at the top of the staff (#2916, thanks @zyk-mjzs) - render: the minimum bar width is computed correctly, and the new engraving settings
beatContentPaddingandbarlineContentPaddingkeep accidentals, grace notes and flags clear of the next beat and the barline; a bar that must be squeezed below its minimum logs a warning (#2943, see Engraving clearances) - render: numbered notation writes rests longer than a quarter as repeated
0, voice colors reach stems, beams, flags and effects, and bend labels on one beat are stacked (#2997, see Per-element colors) - render: triplet feel is shown once per bar and the capo once per staff (#2992, thanks @parvanitis15)
- render: bend and whammy annotations, grace-only bars, dense dynamics, ledger lines, string-number circles and texts of other tracks get the room they need, and adjacent trills stay separate (#2990)
- render: dead-slapped beats, displaced unisons and rest-only beams in numbered notation no longer fail to render (#2993, #2990, thanks @yezhenbiao)
Playerโ
player: repeats, alternate endings and jumps play in the right orderโ
https://github.com/CoderLine/alphaTab/pull/2915 https://github.com/CoderLine/alphaTab/pull/2895 https://github.com/CoderLine/alphaTab/pull/2917 https://github.com/CoderLine/alphaTab/pull/2929
The player, the cursor and MIDI export follow one set of rules for repeats and jumps:
- Each D.C. and D.S. is taken once. Before, a coda placed before the bar that jumps back could make playback loop forever.
- After a jump, repeats play as their final pass: the passage plays once, with only its last alternate ending, as in MuseScore.
- Repeat passes are counted per repeat group, so with Guitar Pro style repeat counts a repeat sign in several alternate endings plays every ending once, as in Guitar Pro 8. MusicXML files whose endings each close with a backward repeat but give no
timescan play fewer endings. - A jump inside a repeat, or on its closing bar, is taken after all repeat passes.
- A jump on an alternate ending that playback skips is not taken.
- MusicXML files that write jumps and markers as
<sound>attributes inside a<direction>, as MuseScore exports them, play these jumps.
\track "Guitar"
\staff {score}
\ro :4 C4 D4 E4 F4 |
\ae 1 \rc 2 G4 F4 E4 D4 |
\ae 2 \jump fine G4 E4 :2 C4 |
\jump daCapoAlFine :4 A4 G4 F4 E4
This plays bars 1 2 1 3 4 1 3: after the D.C. the repeat plays as its final pass, so bar 1 continues into the second ending, where Fine ends the piece.
Full demo and all options: Repeats and structural elements.
Thanks to @AnshulJ999 and @gabbe for reporting these problems, and to @noy-solvin for contributing the fix for repeats in alternate endings.
player: pick-up bars for metronome, count-in and beamingโ
https://github.com/CoderLine/alphaTab/pull/2939
alphaTab treats a pick-up bar as the end of a full bar. Beaming, triplet feel and metronome clicks follow the beats of the time signature. The count-in counts one full bar and continues up to the beat where playback starts, also when you start in the middle of a bar.
\ts (2 4)
\ac C4.8 D4.8 E4.8 |
F4.4 G4.4 |
A4.8 B4.8 C5.8 D5.8
The pick-up holds the last three eighths of a 2/4 bar: C keeps its own flag, and D and E are beamed as beat 2. The same change corrects beat timers with several tracks and tempo changes within a bar, and reading MidiFile.events with MidiFileFormat.MultiTrack no longer overflows the stack.
Full demo and all options: Count-in and metronome.
Thanks to @AlbinoBJJ for reporting this problem.
integration: separate settings for seek, range selection and click resetโ
https://github.com/CoderLine/alphaTab/pull/2779
Three settings replace player.enableUserInteraction:
player.enableSeekToClickmoves the playhead to the clicked beat.player.enablePlaybackRangeSelectionselects a playback range by dragging.player.resetPlaybackRangeOnClickclears the range on a plain click. Withfalse, a click keeps the range and seeks within it.
All three default to true. A drag creates a range only once it reaches another beat; a press and release on the same beat counts as a click, even if the mouse moved a little.
import * as alphaTab from '@coderline/alphatab';
const api = new alphaTab.AlphaTabApi(document.getElementById('alphaTab'), {
core: { file: '/scores/song.gp' },
player: {
playerMode: alphaTab.PlayerMode.EnabledAutomatic,
enableSeekToClick: true,
enablePlaybackRangeSelection: true,
resetPlaybackRangeOnClick: false,
},
});
Full demo and all options: Enabling and disabling interaction.
Thanks to @AvaTheArchitect for the discussion that led to this.
Other changesโ
- player: pausing, or switching quickly between play and pause, before the Audio Worklet has loaded no longer fails with
Failed to execute 'stop' on 'AudioScheduledSourceNode'or stalls playback (#2911, thanks @kulek1) - player: a
midiLoadedhandler registered after the MIDI was loaded is called right away instead of overflowing the stack (#2928, thanks @gabbe) - player: a
customScrollHandleris called also whenplayer.scrollModeisOff(2889cac) - player: changing
player.enableAnimatedBeatCursorat runtime switches the cursor (9a23e14) - integration: a mouse press that ends outside the score, or is lost through a window switch or an Android touch cancel, ends with one mouse-up event; before, the press stayed active, extended the selection on hover and turned off auto-scrolling (#2951, thanks @kulek1)
- player: backing tracks and external media no longer drift behind the audio at tempos like 148 BPM (#2960, thanks @bj0rge)
- player: after a fade out or volume swell the track plays again instead of staying silent; fades use the expression controller (CC 11) (#2995, thanks @yoyecros)
- player: a local
initialAttenuationin a SoundFont zone replaces the global value, so affected presets are no longer too quiet (#2994, thanks @fanjink) - player:
player.scrollModechanges throughupdateSettings()take effect, a backing track the browser refuses to play pauses the player, audio export loads the presets it needs, and custom cursor handlers set later are attached (#2990)
alphaTex Extensionsโ
alphaTex: staff display tagsโ
https://github.com/CoderLine/alphaTab/pull/2946
Three tags express the staff element display settings: \defaultStaffDisplay for the whole score, \staffDisplay for the current staff and \barDisplay for the current bar. Each takes optional staff types (score, tabs, slash, numbered, several in parentheses) and a property list such as clefVisibility, tsPlacement or barNumber. The alphaTex exporter writes these settings, so they survive a round trip.
\staff {score tabs}
:4 3.3 r 0.2 1.2 |
\barDisplay tabs { tsPlacement allStaves } \ts (3 4) 3.3 0.2 r | 1.2 r 0.2
Only the change to 3/4 is restated on the tab staff.
Full demo and all options: Staff element display.
Other changesโ
- alphaTex:
\barNumbersets a custom bar number or text (#2907) - alphaTex:
\tuningDisplayModeplaces the tuning above the score or on the staff lines (#2742, thanks @kulek1) - alphaTex: the beat property
restDisplayPitchpositions a rest (#2721, thanks @roscopeeco) - alphaTex: percussion notes take their tablature line after
@, as inSnareHit@3, and the exporter writes it (#2591, thanks @leocaseiro; see Drum tablature) - alphaTex: the note property
stringshows a string number on pitched notes, as ina4{string 1}(#2913, thanks @magmasystems) - alphaTex: harmonic values can be fractional, as in
3.3{ah 2.4}, so exported files with such values load again (#2941, thanks @stewacide) - alphaTex: the exporter writes
acconly where the accidental changes the spelling (#2931, thanks @gabbe) - alphaTex:
\syncaccepts decimal millisecond offsets, and an export and re-import keeps empty Guitar Pro voices and drum note strings (#2960, #2997) - alphaTex:
basicEditorLspIntegrationof@coderline/alphatab-monacoanswers only for its editor's model, so several editors can each use a language server, and returns a disposable;diagnosticsDelayandcompletionRangetune diagnostics and completions (see Monaco) - alphaTex:
@coderline/alphatab-language-serverand@coderline/alphatab-monacobundle and run again; the language server has separate entry points for browsers and Node.js (#2830; see Language server, Monaco and the package changes)
MusicXML Extensionsโ
musicxml: note spelling from step and alterโ
https://github.com/CoderLine/alphaTab/pull/2931
Notes without a printed <accidental>, for example a repeated note in a bar or a note tied over the barline, were spelled from the key signature. An Fโฏ in F major became a Gโญ, a B in Gโญ major became a Cโญ, and ties joined noteheads on different staff positions. alphaTab now spells every note from <step> and <alter>, as MuseScore and Verovio do.
In bar 1 the second Fโฏ stays on the F line, bars 2 and 3 tie the same notehead, and in bar 4 the B in Gโญ major stays a Bโฎ. The same change fixes the spellings the Guitar Pro exporter writes.
Thanks to @gabbe for reporting this problem.
musicxml: more faithful importโ
Full list of supported elements: MusicXML feature table.
- musicxml: let ring, palm mute, wedges, octave shifts, slash notation and endings are paired per part, staff and number, so they end where the file says, and let ring and palm mute are audible (#2938, thanks @ppisljar)
- musicxml:
<string>on a staff without tuning, as in classical guitar parts, becomes a string number on the pitched note instead of silencing the whole score (#2913, thanks @magmasystems) - musicxml:
xnoteheads and<play><mute>become dead notes on fretted parts, and ties on transposed staves are kept (#2914, thanks @ppisljar) - musicxml:
<fingering>uses left-hand numbering on instruments other than piano, so a 1 is the index finger instead of the thumb (#2927, thanks @magmasystems) - musicxml: D.C., D.S., To Coda, Coda, Segno and Fine written as
<sound>attributes inside a<direction>are played as jumps (#2929, thanks @gabbe) - musicxml:
<metronome>with a beat unit other than a quarter, or with dots, gives the right tempo, and a<sound tempo>in the same direction takes precedence. The tempo mark shows the converted quarter-note value, for exampleโฉ = 189for a dotted quarter at 126 (#2910, thanks @magmasystems) - musicxml: harmonics written as base, touching and sounding notes, as Guitar Pro 8 exports them, become one harmonic note; in alphaTex, artificial and other harmonics on pitched notes such as
C4{ah 12}sound and render (#2947, thanks @parvanitis15) - musicxml: notes with an
<instrument>reference are treated as percussion only when that instrument is unpitched or the staff is a percussion staff (#2777, thanks @ldupoueyUB) - musicxml: high voice numbers are packed into consecutive voices per staff (#2831)
- musicxml: dynamics are shown only where the file writes them, on their own staff, and apply to all staves of the part for playback (#2996, thanks @weblings)
- musicxml: the
numberattribute of each measure sets custom bar numbers and texts, and implicit measures become pick-up bars (#2907; see Bar numbers) - musicxml: a
<string>without<fret>gets its fret from the pitch, andmeasure-numberingholds until the file changes it (#2990)
Guitar Pro Extensionsโ
exporter: files Guitar Pro opens correctlyโ
https://github.com/CoderLine/alphaTab/pull/2774 https://github.com/CoderLine/alphaTab/pull/2832 https://github.com/CoderLine/alphaTab/pull/2831 https://github.com/CoderLine/alphaTab/pull/2931
Files written by the Guitar Pro 7 exporter open correctly in Guitar Pro 7 and 8:
- The system layout is written in the form Guitar Pro expects. Before, the multi-track view of Guitar Pro 8 broke and its memory use grew without bound.
- Every note gets a string and fret, also on staves without a tuning such as piano parts or MusicXML imports.
- Voices beyond the four Guitar Pro supports move into free slots or are dropped with a warning, instead of crashing Guitar Pro.
- Notes keep their spelling in every key, for example a Bโญ in F major.
- The exporter works on a copy of the score and leaves
api.scoreunchanged.
Full demo and all options: Export to Guitar Pro 7.
Thanks to @chenkigba for contributing the system layout fix.
importer: windows-1252 decoding for Guitar Pro 3โ5โ
https://github.com/CoderLine/alphaTab/pull/2774
Guitar Pro 3โ5 files store texts in the code page of the author's system. alphaTab decodes them with the new setting importer.gp3To5encoding, windows-1252 by default, so umlauts and other accented characters in titles and lyrics load correctly. A value other than utf-8 in importer.encoding still takes precedence.
Full demo and all options: Tuning importer behavior.
Thanks to @chenkigba for contributing this change.
Other changesโ
- importer/exporter: the tuning display mode of Guitar Pro 7 and 8 files is read and written (#2742, thanks @kulek1; see Tuning display)
- importer/exporter: the drum tablature lines of Guitar Pro 7 and 8 files are kept on import and export (#2591, thanks @leocaseiro; see Drum tablature)
- importer: a malformed GPX file fails with an error instead of looping until it runs out of memory (#2991, thanks @CaliLuke)
- importer: Guitar Pro 3โ5 files read drum grace notes, note durations, fingerings, frets and MIDI channels correctly, and Guitar Pro 6 files keep ties and the track pan and volume (#2997, #2990)
Bundlers and Frameworksโ
bundlers: one alphaTab core for the page, the workers and the workletโ
https://github.com/CoderLine/alphaTab/pull/2998
With webpack, Rspack and Vite, the page, the Web Workers and the Audio Worklet load alphaTab's core from one shared chunk instead of a copy each, so the browser downloads and compiles about 1.2 MiB (minified) once instead of up to three times. alphaTab starts its worker with the standard new Worker(new URL('./alphaTab.worker.mjs', import.meta.url), { type: 'module' }) and its worklet from alphaTab.worklet.mjs, both importing alphaTab.core.mjs.
The new page Installing in web projects lists the setup for every bundler and framework with the number of core copies each one loads, and links to a verified sample project for each. New pages cover other bundlers, React and Next.js, Vue and Nuxt, Angular, Svelte and SvelteKit and Solid.
webpack: Rspack and Rsbuild supportโ
https://github.com/CoderLine/alphaTab/pull/2998
@coderline/alphatab-webpack works with webpack 5 (5.90 or later), Rspack 1.7 and 2, and Rsbuild through tools.rspack. It bundles alphaTab's worker and worklet as entries and moves the core into an alphaTabCore split chunk. For that it sets optimization.usedExports to 'global' in production builds when you did not set it. See Installation (webpack, Rspack, Rsbuild).
vite: worker and worklet as chunks of the main buildโ
https://github.com/CoderLine/alphaTab/pull/2998
@coderline/alphatab-vite emits alphaTab's worker and worklet as chunks of the main build, sharing the core chunk with the page, and supports Vite 6, 7 and 8. The URLs are written relative to the chunk that references them, so a relative base, renderBuiltUrl, SvelteKit and Nuxt 4 work. In the dev server, alphaTab is excluded from dependency pre-bundling. See Installation (Vite).
integration: entries for bundlers without a pluginโ
https://github.com/CoderLine/alphaTab/pull/2998
The new exports @coderline/alphatab/core, @coderline/alphatab/worker and @coderline/alphatab/worklet let your app own alphaTab's worker and worklet entries. @coderline/alphatab/core exports the full API and starts nothing on its own; you register the worker and worklet with Environment.initializeMain. Installation (other bundlers) shows the setup for esbuild, Rollup and Parcel.
bundlers: Turbopack detectionโ
https://github.com/CoderLine/alphaTab/pull/2998
alphaTab detects Turbopack (Environment.isTurbopackBundled, also printed by Environment.printEnvironmentInfo()) and starts its workers in the form Turbopack bundles, sharing the core chunk with the page. Turbopack does not bundle Audio Worklets, so there alphaTab loads its worklet from core.scriptFile. See Next.js with Turbopack.
Other changesโ
- bundlers: the minified files reference each other:
alphaTab.min.mjsimportsalphaTab.core.min.mjsand startsalphaTab.worker.min.mjsandalphaTab.worklet.min.mjs, which import the minified core too, so a CDN or copied setup loads only minified files. - player: without a detectable script file, loading the Audio Worklet fails with the error "Could not detect alphaTab script file, cannot initialize audio worklet".
- webpack and vite:
webWorkers: falseturns off the worker bundling, the webpack plugin reports copy errors instead of hanging, and the Vite worker and worklet chunks are minified and no longer manifest entries (#2998, #2997, #2990) - bundlers:
Ottavia._8vaand the other enum members starting with an underscore are defined in the minified files again (#2997)
Websiteโ
https://github.com/CoderLine/alphaTab/pull/2998
The website is rebuilt and moved into the alphaTab repository, so documentation and release notes now ship in the same pull request as the code. Report website problems in the alphaTab repository.
- A new landing page with a full player and a live alphaTex editor, and a standalone Playground with track mixer, settings, export and a media sync editor.
- A feature catalog with a demo per feature, new installation pages per bundler and framework, an Attribution page and a Showcase.
- Site-wide choice of synthesizer or backing track and of the SoundFont, and public-domain demo songs.
- The site builds and starts its dev server several times faster; nightlies deploy to next.alphatab.net.
Improvements & Bugfixesโ
- render: the horizontal layout with
display.scaleabove 1 gets its full size, so the end of the score is visible and scrolls with the playhead (#2894, thanks @leocaseiro for contributing this fix and @fiskpinne for reporting it) - importer: Capella (
.capx) files load instead of failing with "No compatible importer found for file" (Capella (CapXML)) - platform: alphaTab reads and writes zip archives and decodes SF3 SoundFonts with its own Deflate and Vorbis implementations, so the package no longer carries four third-party license notices (#2950)
- integration: the
ICursorHandlertype is exported (3d1f1bf), together with the two built-in handlersToNextBeatAnimatingCursorHandler(used whenplayer.enableAnimatedBeatCursoris on) andNonAnimatingCursorHandler, so a custom handler can delegate to them - integration:
BoundsLookup.findBeatsreturns each beat once in the horizontal layout, errors while the worker reads a score reach theerrorevent, and the JSON converter acceptsnullcolors and fonts (#2997) - platform: fixes for the IntersectionObserver fallback, zero-width rectangles on .NET and Android, and number parsing and collections on .NET and Kotlin (#2997)
Upgrade Notesโ
Visual changesโ
- The "rendered by alphaTab" line below the score is gone, so scores lose a line at the bottom. See Attribution.
- Horizontal spacing changes in every score with the power-law model (#2749). Adjust it with
display.spacingRatioanddisplay.stretchForce; see Density and spacing. - Annotations sit closer to the notes (#2750). The default of
display.effectBandPaddingBottomchanges from2to5; raise or lower it to change the gap. See Effect placement. - The default of
display.staffPaddingLeftchanges from2to6(#2907). Set it to2for the previous padding. - Notes and rests that fill a whole bar are centered (#2781), and hammer-on, pull-off and slide labels sit above the staff (#2945). Hide the labels through
notation.elements; see Effects and articulations. - Numbered notation rests, voice colors, triplet feel and MusicXML dynamics render differently (#2997, #2992, #2996); see the items above.
Changed defaultsโ
- Bar numbers appear on the first bar of each system instead of on every bar (#2907). Restore numbers on every bar with
\defaultBarNumberDisplay allBarsin alphaTex, or setbarNumbertoBarNumberDisplay.AllBarson the four staff configurations of the stylesheet. See Bar numbers. - The engraving setting
preBeatGlyphSpacingchanges from 0.5 to 0.6 staff spaces (4.5 to 5.4 at the default size), and the newstaffContentPadding(1 staff space) keeps the content of neighbouring staves apart (#2907). - Guitar Pro 3โ5 files are decoded with
importer.gp3To5encoding,windows-1252by default, instead of UTF-8 (#2774). Set it toutf-8for the previous decoding. A value other thanutf-8inimporter.encodingstill takes precedence. See Tuning importer behavior. - A drag creates a playback range only once it reaches another beat, and a click that seeks while a range stays active is clamped to the range (#2779). See Enabling and disabling interaction.
Deprecationsโ
The deprecated members still work.
player.enableUserInteraction: useplayer.enableSeekToClick,player.enablePlaybackRangeSelectionandplayer.resetPlaybackRangeOnClick. Setting it writes all three (#2779). See Migrating fromenableUserInteraction.display.justifyLastSystem: usedisplay.lastSystemFillThreshold.truemaps to0,falseto1(#2749).RenderStylesheet.barNumberDisplayandBar.barNumberDisplay: use thebarNumberfield of the staff configurations and bar overrides. Setting the old fields writes all four staff types (#2752). See Deprecated bar number fields.
For integrationsโ
- With
@coderline/alphatab-webpack, alphaTab's core is a chunk of its own that the page loads next to your entry script. HTML generated byHtmlWebpackPlugin,HtmlRspackPlugin, Rsbuild or Next.js includes it. A hand-written<script>list must include every file of the entrypoint, and hosts that only inject chunks they know by name, such as Angular's webpack builder, setoptimization.splitChunks.cacheGroups.alphaTabCore = false. See Optimization settings. @coderline/alphatab-webpacksetsoptimization.usedExportsto'global'in production builds when you did not set it, and warns when it istrue, which bundles the core twice.- With Vite and Rsbuild, the scripts are emitted into a subfolder (
assets/,static/js/), so setcore.fontDirectoryto the font the plugin copies; see Point alphaTab to the font and the SoundFont. - Unset values of
Note.fret,Note.string,Note.octave,Note.toneandNote.percussionArticulationareNaNinstead of-1(#2591). Score JSON written by 1.8 with-1loads as unset (#2990). Replace=== -1checks withnote.isStringed,note.isPercussion,note.isPianoorNumber.isNaN(...). A percussion note in a drum tablature is both percussion and stringed. - Custom
IMidiFileHandlerimplementations need the new memberaddMetronome(tick, counter, durationInTicks); handlers that write standard MIDI files can ignore the call. In pick-up bars,Automation.ratioPositionis relative to the full bar of the time signature, as Guitar Pro writes it (#2939). AutomationType.Bankchanges from4to5; in 1.8 it had the same value asAutomationType.SyncPoint. Score JSON written by 1.8 stores bank changes as4, which 1.9 loads as sync points (#2907).- Guitar Pro 3โ5 files: each track gets the MIDI port and channel stored in the file and its own
PlaybackInformation.portis zero-based (1.8 kept the one-based value of the file), andprimaryChannelcan differ from 1.8, for example2instead of4. Programs, volume, balance and the notes do not change, and two tracks that 1.8 played on one channel get a channel each. Code that addresses MIDI channels or ports per track sees the new numbers (#2774). - Settings JSON (
RenderingResourcesJson) accepts the deprecated fontscopyrightFont,titleFont,subTitleFont,wordsFont,timerFont,directionsFont,fretboardNumberFont,markerFontandbarNumberFontand applies them as the properties of the same name do; 1.8 ignored them in JSON.effectFont,fingeringFontandinlineFingeringFontare still accepted and still have no effect (#2749). - The SVG output is no longer identical between two renders of the same score: the staff lines of the bar with the attribution and the attribution itself are written as one path in a random order. Whitespace and some attributes of the SVG text changed too (#2997). The drawn result is the same. Compare rendered images instead of SVG strings.
- The page and its alphaTab worker must load the same alphaTab version, and during a window drag only the last resize raises render events (#2997).
- With the Audio Worklet,
playerPositionChangedfires at most every 10 ms by default;player.positionUpdateIntervalInMillisecondsset to0restores the previous rate. Internal flow messages moved fromDebugto the newLogLevel.Trace(#2997). - Generated MIDI fades use CC 11 instead of CC 7, and millisecond values such as sync point times keep their decimals (#2995, #2960).
- C# and Kotlin: deprecated members are marked
[Obsolete]and@Deprecated(#2990). - alphaTex AST consumers: the values of
AlphaTexNodeTypeare renumbered, so compare against the enum members instead of numbers, andAlphaTexNoteNode.noteStringDotis nownoteStringSeparatorof typeIAlphaTexStringSeparatorNode(#2591).
Package changesโ
- The npm packages carry provenance attestations from npm trusted publishing (#2959).
@coderline/alphatab/viteand/webpackforward to the plugin packages, and@coderline/alphatab-language-serverloads withrequire(#2990).@coderline/alphatab-vite/workerPluginis removed. RegisteralphaTab()from@coderline/alphatab-vite; it covers the worker and the worklet.@coderline/alphatab-viteaccepts Vite^6 || ^7 || ^8as peer dependency.@coderline/alphatab-webpackdeclareswebpack(^5.0.0) and@rspack/core(^1.7.0 || ^2.0.0) as optional peer dependencies; install the one your project builds with.@coderline/alphatabexports./core,./workerand./worklet. Bundlers that resolve packageexportsfind them without configuration; Parcel needspackageExportsenabled.@coderline/alphatab-webpackdeclares webpack as a peer dependency (^5.0.0) instead of a dependency. Install webpack in your project if it is not there yet (#2806).@coderline/alphatab-language-serverhas separate entry points for browsers and Node.js (#2830):- Import
startWebWorkerLanguageServerfrom@coderline/alphatab-language-server/server/browserandstartNodeLanguageServerfrom@coderline/alphatab-language-server/server/node. The package root resolves to the browser entry only for bundlers that apply thebrowsercondition; TypeScript withmoduleResolution: "bundler"does not, and reports that the root has nostartWebWorkerLanguageServer. main,typesandbinpoint todist/index.node.*instead ofdist/server.*. Paths intodistare not exported; use the entry points above.startWebWorkerLanguageServertakes aLanguageServerMessagePort: anyMessagePort,Workeror workerselffits, and its declaration type checks with either the DOM or the WebWorker library.
- Import
@coderline/alphatab-monacoexports its modules as subpaths:@coderline/alphatab-monaco/lsp,/lspMonacoMappings,/alphatex,/textmate,/typesand/worker. Imports of@coderline/alphatab-monaco/dist/<module>keep working (see Monaco).- Major dependency updates:
vscode-languageserver9 to 11 in@coderline/alphatab-language-server(@coderline/alphatab-monaconow declares it too),monaco-editor0.55 to 0.57 in@coderline/alphatab-monaco, andmagic-string0.30 to 1 in@coderline/alphatab-vite.