Skip to main content

Looping a section

"Loop the pre-chorus while I drill the chord voicing" is the classic practice-tool ask. Combine playbackRange (the tick bounds) and isLooping (the wrap flag) and you have a section that repeats until the muscle memory sticks.

00:00 / 00:00

The two propertiesโ€‹

  • playbackRange โ€” a { startTick, endTick } object marking the tick bounds of the loop. Set it to null to release the constraint and play the whole score.
  • isLooping โ€” a boolean. When true, playback wraps back to startTick on reaching endTick. When false, playback stops at endTick.

Set playbackRange without isLooping to constrain playback to a section that plays once, then stops. Set isLooping without playbackRange to loop the entire score.

Converting bars to ticksโ€‹

playbackRange is tick-based, but users think in bars. The tickCache on the API exposes the tick position of any beat, so grabbing the first beat of the start bar and the last beat of the end bar gives you the range.

Show it in codeโ€‹

import * as alphaTab from '@coderline/alphatab';

const container = getAlphaTabContainer();
const api = new alphaTab.AlphaTabApi(container, {
core: { file: '/scores/song.gp' },
player: { playerMode: alphaTab.PlayerMode.EnabledSynthesizer },
});

api.playerReady.on(() => {
const track = api.score.tracks[0];
const startBar = track.staves[0].bars[3]; // bar 4 (zero-based)
const endBar = track.staves[0].bars[7]; // bar 8

const startBeat = startBar.voices[0].beats[0];
const endBeat = endBar.voices[0].beats[endBar.voices[0].beats.length - 1];

api.playbackRange = {
startTick: api.tickCache.getBeatStart(startBeat),
endTick: api.tickCache.getBeatStart(endBeat),
};
api.isLooping = true;
api.play();
});

getAlphaTabContainer() is a placeholder for the platform-specific step of obtaining the render target โ€” a <div> on Web, an AlphaTab control on .NET, or an AlphaTabView on Android. Every other line runs unchanged on all three runtimes.

Where to look nextโ€‹