Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e69058c
feat(importer): map TablEdit effects, graces, fingerings and strokes
Danielku15 Nov 1, 2026
be4695f
feat(importer): apply TablEdit markers
Danielku15 Nov 1, 2026
91cbedc
feat(importer): read TablEdit key signatures, minor keys and pick-up …
Danielku15 Nov 1, 2026
b249777
feat(importer): apply TablEdit lyrics to the beats of their track
Danielku15 Nov 1, 2026
cad7de8
feat(importer): read more of the TablEdit format and follow TablEdit'…
Danielku15 Nov 2, 2026
c8d8620
feat(importer): read TablEdit 2 files (formats 3 to 9)
Danielku15 Nov 2, 2026
baf51c7
feat(importer): read the abbreviated name of TablEdit instruments
Danielku15 Nov 2, 2026
1881f65
style(importer): format the importers touched while adding the TablEd…
Danielku15 Nov 1, 2026
665fcbd
feat(importer): express the TablEdit reading list through repeats and…
Danielku15 Nov 2, 2026
766723d
feat(importer): read TablEdit clefs, display modes, mixer settings, t…
Danielku15 Nov 1, 2026
cfbb673
test(importer): prove the TablEdit importer with files entered in Tab…
Danielku15 Nov 2, 2026
2d9aa8b
test(importer): compare TablEdit 2 files with TablEdit's conversion
Danielku15 Nov 2, 2026
071a57a
test(rendering): render TablEdit files and round-trip them through JS…
Danielku15 Nov 1, 2026
9c09468
docs: document the TablEdit importer and its compatibility
Danielku15 Nov 2, 2026
67d73c3
fix(kotlin): spread only the items of a DoubleList, not its spare cap…
Danielku15 Nov 2, 2026
17626fc
fix(csharp): decode Windows-1252 text without a code pages provider
Danielku15 Nov 2, 2026
98c3914
fix(platform): add the array members of the TablEdit importer and its…
Danielku15 Nov 2, 2026
907c967
test(platform): compare numbers, enums and map entries in toEqual lik…
Danielku15 Nov 2, 2026
b526eb5
feat(importer): read TablEdit 3 files into bars, voices and beats
Danielku15 Nov 1, 2026
6e473c1
test(importer): give the TablEdit tremolo bar test real amounts
Danielku15 Nov 6, 2026
a1912f2
test(rendering): add the reviewed TablEdit visual references
Danielku15 Nov 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Music notation, rendered as a first-class SDK.**

alphaTab renders interactive sheet music and guitar tablature from Guitar Pro, MusicXML, Capella and alphaTex files, and plays it back with a built-in synthesizer or in sync with your own audio and video. One TypeScript core ships for the web, .NET and Android, with no runtime dependencies and TypeScript types included. Open source since 2010.
alphaTab renders interactive sheet music and guitar tablature from Guitar Pro, MusicXML, Capella, TablEdit and alphaTex files, and plays it back with a built-in synthesizer or in sync with your own audio and video. One TypeScript core ships for the web, .NET and Android, with no runtime dependencies and TypeScript types included. Open source since 2010.

[![npm](https://img.shields.io/npm/v/@coderline/alphatab?label=npm)](https://www.npmjs.com/package/@coderline/alphatab)
[![npm downloads](https://img.shields.io/npm/dm/@coderline/alphatab?label=downloads)](https://www.npmjs.com/package/@coderline/alphatab)
Expand All @@ -29,7 +29,7 @@ alphaTab renders interactive sheet music and guitar tablature from Guitar Pro, M

| | Formats |
|---|---|
| **Reads** | Guitar Pro 3–8 (`.gp3` `.gp4` `.gp5` `.gpx` `.gp`), MusicXML (`.xml` `.musicxml` `.mxl`), Capella (`.capx`), [alphaTex](https://alphatab.net/docs/alphatex/introduction) |
| **Reads** | Guitar Pro 3–8 (`.gp3` `.gp4` `.gp5` `.gpx` `.gp`), MusicXML (`.xml` `.musicxml` `.mxl`), Capella (`.capx`), TablEdit (`.tef`), [alphaTex](https://alphatab.net/docs/alphatex/introduction) |
| **Writes** | Guitar Pro 7+ (`.gp`), alphaTex, MIDI, audio (PCM samples) |

## Quick start
Expand Down
2 changes: 1 addition & 1 deletion packages/alphatab/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@coderline/alphatab",
"version": "1.10.0",
"description": "Render and play interactive sheet music and guitar tablature from Guitar Pro, MusicXML, Capella and alphaTex, in the browser, Node.js, .NET and Android.",
"description": "Render and play interactive sheet music and guitar tablature from Guitar Pro, MusicXML, Capella, TablEdit and alphaTex, in the browser, Node.js, .NET and Android.",
"keywords": [
"music-notation",
"sheet-music",
Expand Down
11 changes: 7 additions & 4 deletions packages/alphatab/src/Environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Gp7To8Importer } from '@coderline/alphatab/importer/Gp7To8Importer';
import { GpxImporter } from '@coderline/alphatab/importer/GpxImporter';
import { MusicXmlImporter } from '@coderline/alphatab/importer/MusicXmlImporter';
import type { ScoreImporter } from '@coderline/alphatab/importer/ScoreImporter';
import { TablEditImporter } from '@coderline/alphatab/importer/TablEditImporter';
import { LayoutMode } from '@coderline/alphatab/LayoutMode';
import { Logger } from '@coderline/alphatab/Logger';
import type { Font } from '@coderline/alphatab/model/Font';
Expand All @@ -22,9 +23,7 @@ import { SkiaCanvas } from '@coderline/alphatab/platform/skia/SkiaCanvas';
import { CssFontSvgCanvas } from '@coderline/alphatab/platform/svg/CssFontSvgCanvas';
import { AlphaSynthWebWorker } from '@coderline/alphatab/platform/worker/AlphaSynthWebWorker';
import { AlphaTabWebWorker } from '@coderline/alphatab/platform/worker/AlphaTabWebWorker';
import type {
IAlphaTabWorkerGlobalScope
} from '@coderline/alphatab/platform/worker/AlphaTabWorkerProtocol';
import type { IAlphaTabWorkerGlobalScope } from '@coderline/alphatab/platform/worker/AlphaTabWorkerProtocol';
import { type BarRendererFactory, EffectBandMode } from '@coderline/alphatab/rendering/BarRendererFactory';
import { alternateEndingsEffectInfo } from '@coderline/alphatab/rendering/effects/AlternateEndingsEffectInfo';
import { barNumberEffectInfo } from '@coderline/alphatab/rendering/effects/BarNumberEffectInfo';
Expand All @@ -35,6 +34,10 @@ import { chordsEffectInfo } from '@coderline/alphatab/rendering/effects/ChordsEf
import { crescendoEffectInfo } from '@coderline/alphatab/rendering/effects/CrescendoEffectInfo';
import { directionsEffectInfo } from '@coderline/alphatab/rendering/effects/DirectionsEffectInfo';
import { dynamicsEffectInfo } from '@coderline/alphatab/rendering/effects/DynamicsEffectInfo';
import {
hammerPullLabelEffectInfo,
slideLabelEffectInfo
} from '@coderline/alphatab/rendering/effects/EffectSlurLabelEffectInfo';
import { fadeEffectInfo } from '@coderline/alphatab/rendering/effects/FadeEffectInfo';
import { fermataEffectInfo } from '@coderline/alphatab/rendering/effects/FermataEffectInfo';
import { fingeringEffectInfo } from '@coderline/alphatab/rendering/effects/FingeringEffectInfo';
Expand All @@ -58,7 +61,6 @@ import { createSlightNoteVibratoEffectInfo } from '@coderline/alphatab/rendering
import { sustainPedalEffectInfo } from '@coderline/alphatab/rendering/effects/SustainPedalEffectInfo';
import { tabWhammyEffectInfo } from '@coderline/alphatab/rendering/effects/TabWhammyEffectInfo';
import { tapEffectInfo } from '@coderline/alphatab/rendering/effects/TapEffectInfo';
import { hammerPullLabelEffectInfo, slideLabelEffectInfo } from '@coderline/alphatab/rendering/effects/EffectSlurLabelEffectInfo';
import { tempoEffectInfo } from '@coderline/alphatab/rendering/effects/TempoEffectInfo';
import { textEffectInfo } from '@coderline/alphatab/rendering/effects/TextEffectInfo';
import { trillEffectInfo } from '@coderline/alphatab/rendering/effects/TrillEffectInfo';
Expand Down Expand Up @@ -404,6 +406,7 @@ export class Environment {
new Gp7To8Importer(),
new MusicXmlImporter(),
new CapellaImporter(),
new TablEditImporter(),
new AlphaTexImporter()
];
}
Expand Down
10 changes: 8 additions & 2 deletions packages/alphatab/src/importer/AlphaTexImporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,10 @@ export class AlphaTexImporter extends ScoreImporter implements IAlphaTexImporter
}
for (const [sustainPedal, beat] of this._state.sustainPedalToBeat) {
if (sustainPedal.ratioPosition < 1) {
sustainPedal.ratioPosition = ModelUtils.tickToRatioPosition(beat.voice.bar.masterBar, beat.playbackStart);
sustainPedal.ratioPosition = ModelUtils.tickToRatioPosition(
beat.voice.bar.masterBar,
beat.playbackStart
);
}
}
return this._state.score;
Expand Down Expand Up @@ -718,7 +721,10 @@ export class AlphaTexImporter extends ScoreImporter implements IAlphaTexImporter

if (node.noteString) {
const percussionNoteString: number = node.noteString!.value;
if (percussionNoteString < 1 || percussionNoteString > this._state.currentStaff!.tuning.length) {
if (
percussionNoteString < 1 ||
percussionNoteString > 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}`,
Expand Down
14 changes: 7 additions & 7 deletions packages/alphatab/src/importer/BinaryStylesheet.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { type HeaderFooterStyle, type Score, ScoreSubElement } from '@coderline/alphatab/model/Score';
import { AlphaTabError, AlphaTabErrorType } from '@coderline/alphatab/AlphaTabError';
import { GpBinaryHelpers } from '@coderline/alphatab/importer/Gp3To5Importer';
import { ByteBuffer } from '@coderline/alphatab/io/ByteBuffer';
import { IOHelper } from '@coderline/alphatab/io/IOHelper';
import { GpBinaryHelpers } from '@coderline/alphatab/importer/Gp3To5Importer';
import type { IWriteable } from '@coderline/alphatab/io/IWriteable';
import { BendPoint } from '@coderline/alphatab/model/BendPoint';
import { Bounds } from '@coderline/alphatab/rendering/utils/Bounds';
import { Color } from '@coderline/alphatab/model/Color';
import { ModelUtils } from '@coderline/alphatab/model/ModelUtils';
import {
BarNumberDisplay,
type BracketExtendMode,
Expand All @@ -13,10 +14,9 @@ import {
TrackNamePolicy,
TuningDisplayMode
} from '@coderline/alphatab/model/RenderStylesheet';
import type { IWriteable } from '@coderline/alphatab/io/IWriteable';
import { AlphaTabError, AlphaTabErrorType } from '@coderline/alphatab/AlphaTabError';
import { ModelUtils } from '@coderline/alphatab/model/ModelUtils';
import { type HeaderFooterStyle, type Score, ScoreSubElement } from '@coderline/alphatab/model/Score';
import { TextAlign } from '@coderline/alphatab/platform/ICanvas';
import { Bounds } from '@coderline/alphatab/rendering/utils/Bounds';

/**
* @internal
Expand Down Expand Up @@ -625,7 +625,7 @@ export class BinaryStylesheet {
binaryStylesheet.addValue('Global/TuningDisplayMode', 0, DataType.Integer);
break;
}

const writer = ByteBuffer.withCapacity(128);
binaryStylesheet.writeTo(writer);
return writer.toArray();
Expand Down
11 changes: 4 additions & 7 deletions packages/alphatab/src/importer/CapellaImporter.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { CapellaParser } from '@coderline/alphatab/importer/CapellaParser';
import { ScoreImporter } from '@coderline/alphatab/importer/ScoreImporter';
import { UnsupportedFormatError } from '@coderline/alphatab/importer/UnsupportedFormatError';

import type { Score } from '@coderline/alphatab/model/Score';

import { IOHelper } from '@coderline/alphatab/io/IOHelper';
import { Logger } from '@coderline/alphatab/Logger';

import { ZipReader } from '@coderline/alphatab/zip/ZipReader';
import type { Score } from '@coderline/alphatab/model/Score';
import type { ZipEntry } from '@coderline/alphatab/zip/ZipEntry';
import { IOHelper } from '@coderline/alphatab/io/IOHelper';
import { CapellaParser } from '@coderline/alphatab/importer/CapellaParser';
import { ZipReader } from '@coderline/alphatab/zip/ZipReader';

/**
* This ScoreImporter can read Capella (cap/capx) files.
Expand Down
25 changes: 15 additions & 10 deletions packages/alphatab/src/importer/CapellaParser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { UnsupportedFormatError } from '@coderline/alphatab/importer/UnsupportedFormatError';
import { Logger } from '@coderline/alphatab/Logger';
import { AccentuationType } from '@coderline/alphatab/model/AccentuationType';
import { Automation, AutomationType } from '@coderline/alphatab/model/Automation';
import { Bar, BarLineStyle } from '@coderline/alphatab/model/Bar';
Expand All @@ -7,25 +8,23 @@ import { Chord } from '@coderline/alphatab/model/Chord';
import { Clef } from '@coderline/alphatab/model/Clef';
import { CrescendoType } from '@coderline/alphatab/model/CrescendoType';
import { Duration } from '@coderline/alphatab/model/Duration';
import { DynamicValue } from '@coderline/alphatab/model/DynamicValue';
import { Fermata, FermataType } from '@coderline/alphatab/model/Fermata';
import type { KeySignature } from '@coderline/alphatab/model/KeySignature';
import { MasterBar } from '@coderline/alphatab/model/MasterBar';
import { ModelUtils } from '@coderline/alphatab/model/ModelUtils';
import { Note } from '@coderline/alphatab/model/Note';
import { Ottavia } from '@coderline/alphatab/model/Ottavia';
import { Score } from '@coderline/alphatab/model/Score';
import type { Staff } from '@coderline/alphatab/model/Staff';
import { Track } from '@coderline/alphatab/model/Track';
import { VibratoType } from '@coderline/alphatab/model/VibratoType';
import { Voice } from '@coderline/alphatab/model/Voice';
import { TextAlign } from '@coderline/alphatab/platform/ICanvas';
import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection';
import type { Settings } from '@coderline/alphatab/Settings';
import { XmlDocument } from '@coderline/alphatab/xml/XmlDocument';

import type { XmlNode } from '@coderline/alphatab/xml/XmlNode';
import { BeamDirection } from '@coderline/alphatab/rendering/utils/BeamDirection';
import { TextAlign } from '@coderline/alphatab/platform/ICanvas';
import { ModelUtils } from '@coderline/alphatab/model/ModelUtils';
import { Logger } from '@coderline/alphatab/Logger';
import { Fermata, FermataType } from '@coderline/alphatab/model/Fermata';
import { DynamicValue } from '@coderline/alphatab/model/DynamicValue';
import { Ottavia } from '@coderline/alphatab/model/Ottavia';
import type { KeySignature } from '@coderline/alphatab/model/KeySignature';

/**
* @internal
Expand Down Expand Up @@ -500,7 +499,13 @@ export class CapellaParser {
break;
}
}
private _parseVoices(staffId: string, staff: Staff, systemElement: XmlNode, firstBarIndex: number, element: XmlNode) {
private _parseVoices(
staffId: string,
staff: Staff,
systemElement: XmlNode,
firstBarIndex: number,
element: XmlNode
) {
let voiceIndex = 0;
for (const c of element.childElements()) {
switch (c.localName) {
Expand Down
22 changes: 11 additions & 11 deletions packages/alphatab/src/importer/Gp7To8Importer.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { BinaryStylesheet } from '@coderline/alphatab/importer/BinaryStylesheet';
import { GpifParser } from '@coderline/alphatab/importer/GpifParser';
import { LayoutConfiguration } from '@coderline/alphatab/importer/LayoutConfiguration';
import { PartConfiguration } from '@coderline/alphatab/importer/PartConfiguration';
import { ScoreImporter } from '@coderline/alphatab/importer/ScoreImporter';
import { UnsupportedFormatError } from '@coderline/alphatab/importer/UnsupportedFormatError';

import type { Score } from '@coderline/alphatab/model/Score';

import { IOHelper } from '@coderline/alphatab/io/IOHelper';
import { Logger } from '@coderline/alphatab/Logger';

import { ZipReader } from '@coderline/alphatab/zip/ZipReader';
import type { Score } from '@coderline/alphatab/model/Score';
import type { ZipEntry } from '@coderline/alphatab/zip/ZipEntry';
import { IOHelper } from '@coderline/alphatab/io/IOHelper';
import { LayoutConfiguration } from '@coderline/alphatab/importer/LayoutConfiguration';
import { ZipReader } from '@coderline/alphatab/zip/ZipReader';

/**
* This ScoreImporter can read Guitar Pro 7 and 8 (gp) files.
Expand Down Expand Up @@ -66,10 +63,10 @@ export class Gp7To8Importer extends ScoreImporter {
// the score information as XML we need to parse.
Logger.trace(this.name, 'Start Parsing score.gpif');
const gpifParser: GpifParser = new GpifParser();
gpifParser.loadAsset = (fileName) => {
if(entryLookup.has(fileName)) {
gpifParser.loadAsset = fileName => {
if (entryLookup.has(fileName)) {
return entryLookup.get(fileName)!.data;
};
}
return undefined;
};
gpifParser.parseXml(xml, this.settings);
Expand All @@ -78,7 +75,10 @@ export class Gp7To8Importer extends ScoreImporter {

if (binaryStylesheetData) {
Logger.trace(this.name, 'Start Parsing BinaryStylesheet');
const stylesheet: BinaryStylesheet = new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize);
const stylesheet: BinaryStylesheet = new BinaryStylesheet(
binaryStylesheetData,
this.settings.importer.maxDecodingBufferSize
);
stylesheet.apply(score);
Logger.trace(this.name, 'BinaryStylesheet parsed');
}
Expand Down
3 changes: 1 addition & 2 deletions packages/alphatab/src/importer/GpifParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2817,8 +2817,7 @@ export class GpifParser {
if (isPercussion) {
staff.stringTuning.tunings = [0, 0, 0, 0, 0, 0];
} else {
const fallback =
staff.index === 0 ? Tuning.getDefaultTuningFor(6) : Tuning.getDefaultTuningFor(5);
const fallback = staff.index === 0 ? Tuning.getDefaultTuningFor(6) : Tuning.getDefaultTuningFor(5);
if (fallback !== null) {
staff.stringTuning.tunings = fallback.tunings.slice();
staff.stringTuning.name = fallback.name;
Expand Down
11 changes: 7 additions & 4 deletions packages/alphatab/src/importer/GpxImporter.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { BinaryStylesheet } from '@coderline/alphatab/importer/BinaryStylesheet';
import { GpifParser } from '@coderline/alphatab/importer/GpifParser';
import { GpxFileSystem } from '@coderline/alphatab/importer/GpxFileSystem';
import { LayoutConfiguration } from '@coderline/alphatab/importer/LayoutConfiguration';
import { PartConfiguration } from '@coderline/alphatab/importer/PartConfiguration';
import { ScoreImporter } from '@coderline/alphatab/importer/ScoreImporter';
import type { Score } from '@coderline/alphatab/model/Score';
import { Logger } from '@coderline/alphatab/Logger';
import { UnsupportedFormatError } from '@coderline/alphatab/importer/UnsupportedFormatError';
import { IOHelper } from '@coderline/alphatab/io/IOHelper';
import { LayoutConfiguration } from '@coderline/alphatab/importer/LayoutConfiguration';
import { Logger } from '@coderline/alphatab/Logger';
import type { Score } from '@coderline/alphatab/model/Score';

/**
* This ScoreImporter can read Guitar Pro 6 (gpx) files.
Expand Down Expand Up @@ -70,7 +70,10 @@ export class GpxImporter extends ScoreImporter {

if (binaryStylesheetData) {
Logger.trace(this.name, 'Start Parsing BinaryStylesheet');
const binaryStylesheet: BinaryStylesheet = new BinaryStylesheet(binaryStylesheetData, this.settings.importer.maxDecodingBufferSize);
const binaryStylesheet: BinaryStylesheet = new BinaryStylesheet(
binaryStylesheetData,
this.settings.importer.maxDecodingBufferSize
);
binaryStylesheet.apply(score);
Logger.trace(this.name, 'BinaryStylesheet parsed');
}
Expand Down
2 changes: 1 addition & 1 deletion packages/alphatab/src/importer/LayoutConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { PartConfiguration } from '@coderline/alphatab/importer/PartConfiguration';
import { ByteBuffer } from '@coderline/alphatab/io/ByteBuffer';
import { IOHelper } from '@coderline/alphatab/io/IOHelper';
import type { Score } from '@coderline/alphatab/model/Score';
import type { PartConfiguration } from '@coderline/alphatab/importer/PartConfiguration';

// PartConfiguration File Format Notes.
// Based off Guitar Pro 8
Expand Down
8 changes: 2 additions & 6 deletions packages/alphatab/src/importer/MusicXmlImporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Clef } from '@coderline/alphatab/model/Clef';
import { Direction } from '@coderline/alphatab/model/Direction';
import { Duration } from '@coderline/alphatab/model/Duration';
import { DynamicValue } from '@coderline/alphatab/model/DynamicValue';
import { FermataType, Fermata } from '@coderline/alphatab/model/Fermata';
import { Fermata, FermataType } from '@coderline/alphatab/model/Fermata';
import { Fingers } from '@coderline/alphatab/model/Fingers';
import { GolpeType } from '@coderline/alphatab/model/GolpeType';
import { GraceType } from '@coderline/alphatab/model/GraceType';
Expand Down Expand Up @@ -3084,11 +3084,7 @@ export class MusicXmlImporter extends ScoreImporter {

// on a staff with tuning, string and pitch define the tab position of a note written without fret
// (e.g. dead notes written by Guitar Pro 5)
if (
!note.isStringed &&
(note.isDead || !note.isPercussion) &&
note.beat.voice.bar.staff.tuning.length > 0
) {
if (!note.isStringed && (note.isDead || !note.isPercussion) && note.beat.voice.bar.staff.tuning.length > 0) {
const fret = this._calculatePitchedNoteValue(note) - note.stringTuning;
if (fret >= 0) {
note.fret = fret;
Expand Down
2 changes: 1 addition & 1 deletion packages/alphatab/src/importer/ScoreImporter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ThrowingReadable, type IReadable } from '@coderline/alphatab/io/IReadable';
import { type IReadable, ThrowingReadable } from '@coderline/alphatab/io/IReadable';
import { Score } from '@coderline/alphatab/model/Score';
import type { Settings } from '@coderline/alphatab/Settings';

Expand Down
Loading
Loading