From 0c276ea409a5636c8226de1c664871c574de6eaf Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Fri, 16 Oct 2026 23:46:38 +0200 Subject: [PATCH 1/2] fix(player): keep sync point times exact to avoid drift on non-integer tempos (#2952) MidiUtils.ticksToMillis truncated its result to whole milliseconds. The MIDI generator accumulates the synthesizer time of sync points and beat timers bar by bar with this helper, so every bar whose duration is not an integer millisecond value (e.g. 1621.62ms for a 4/4 bar at 148 BPM) lost the fractional part. The sequencer maps synth time back to ticks with exact math, so the position reported for a given backing track or external media time fell further behind over the song (~123ms after 200 bars at 148 BPM). ticksToMillis now returns exact milliseconds (multiplying before dividing keeps whole-number results exact). The Guitar Pro writer rounds beat timers since the format stores integer milliseconds. The alphaTex \sync tag now parses its millisecond offset as float so fractional offsets also work without parentheses (e.g. `\sync 1 0 1621.62` was previously split into a sync point and a note). The interpolated end sync point of the sync point test file now keeps the sync BPM of the previous segment, updating the related snapshots and the audio export reference. Co-Authored-By: Claude Opus 5.5 (1M context) --- packages/alphatab/src/exporter/GpifWriter.ts | 2 +- .../alphaTex/AlphaTex1LanguageDefinitions.ts | 2 +- packages/alphatab/src/midi/MidiUtils.ts | 2 +- .../test-data/audio/export-sync-points.pcm | Bin 14817280 -> 14817792 bytes .../test/audio/MidiFileGenerator.test.ts | 22 ++++ .../alphatab/test/audio/SyncPoint.test.ts | 81 ++++++++++++ .../__snapshots__/SyncPoint.test.ts.snap | 122 +++++++++--------- .../test/exporter/Gp7Exporter.test.ts | 14 ++ .../test/importer/AlphaTexImporter.test.ts | 25 ++++ packages/alphatex/src/metadata/bar/sync.ts | 2 +- 10 files changed, 207 insertions(+), 65 deletions(-) diff --git a/packages/alphatab/src/exporter/GpifWriter.ts b/packages/alphatab/src/exporter/GpifWriter.ts index b5eb34d08f..a087482bd6 100644 --- a/packages/alphatab/src/exporter/GpifWriter.ts +++ b/packages/alphatab/src/exporter/GpifWriter.ts @@ -664,7 +664,7 @@ export class GpifWriter { } if (beat.showTimer) { - beatNode.addElement('Timer').innerText = (beat.timer ?? 0).toString(); + beatNode.addElement('Timer').innerText = Math.round(beat.timer ?? 0).toString(); } this._writeBeatProperties(beatNode, beat); diff --git a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts index c2c23b33d8..be18148493 100644 --- a/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts +++ b/packages/alphatab/src/importer/alphaTex/AlphaTex1LanguageDefinitions.ts @@ -472,7 +472,7 @@ export class AlphaTex1LanguageDefinitions { [ [[106], 0], [[106], 0], - [[106], 0], + [[106], 2], [[106], 3] ] ] diff --git a/packages/alphatab/src/midi/MidiUtils.ts b/packages/alphatab/src/midi/MidiUtils.ts index 7b27059cf5..773133a3a3 100644 --- a/packages/alphatab/src/midi/MidiUtils.ts +++ b/packages/alphatab/src/midi/MidiUtils.ts @@ -16,7 +16,7 @@ export class MidiUtils { * @returns The converted duration in milliseconds. */ public static ticksToMillis(ticks: number, tempo: number): number { - return (ticks * (60000.0 / (tempo * MidiUtils.QuarterTime))) | 0; + return (ticks * 60000.0) / (tempo * MidiUtils.QuarterTime); } /** diff --git a/packages/alphatab/test-data/audio/export-sync-points.pcm b/packages/alphatab/test-data/audio/export-sync-points.pcm index 39c6e11e24025a3d65ddb2b41d4b91ed2c162de7..148a4c94cf1f4fe3539499a55f2f56a73e62bc33 100644 GIT binary patch delta 481 zcmWN=<#vbx007Wq!?fw1?(Sx~ySux)8LrQCcQc#(4C|im_7QS3^y;)K*7~y6UN~frc7stcj+YX|9Eq zT4}9~w%Td0gN{1stc$L?>8^*Kdg-l?zGC&$-v9#*GT0D94Kv&bBaJfJ7-Nky-UJg( zGT9VUO*7pLGtDyF9COVx-vSFQve*(!EwkJTE3LBH8f&ey-Ub_Ove_0}ZL{4DJMFUD z9&z^CXFm=I92D=6!;U!WnBz`3>6FvXIP0AAF1YBD%dWWUn(J=3>6Y8>NN`u8B=_9+ zz(bEb7J4GtQ_nn?B2}7n88T(bmLpf5d<6=<@X{-Y$@YAn^ u-+zNJH3-v!Fg*w}f-o}(vw|=?2y=okHwg2BFh2+j62ronr07495&r;F$>#w8 delta 78925 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 s?on)45=&Vu6|q#sQWHy^Dz { expect(actualTimers.join(',')).toBe(expectedTimers.join(',')); }); + /** + * See #2952 + */ + it('beat-timer-non-integer-bar-duration', () => { + // a 4/4 bar at 148 BPM lasts 1621.6216...ms + const barCount = 200; + const score: Score = parseTex(` + \\tempo 148 + . + ${new Array(barCount).fill('C4.4 { timer } C4.4 * 3').join(' | ')} + `); + + const handler: FlatMidiEventGenerator = new FlatMidiEventGenerator(); + const generator: MidiFileGenerator = new MidiFileGenerator(score, null, handler); + generator.generate(); + + const bars = score.tracks[0].staves[0].bars; + for (let i = 0; i < barCount; i++) { + expect(bars[i].voices[0].beats[0].timer, `bar ${i}`).toBeCloseTo((i * 4 * 60000) / 148, 6); + } + }); + describe('metronome', () => { function testMetronome(tex: string, expectedClicks: string) { const score: Score = parseTex(tex); diff --git a/packages/alphatab/test/audio/SyncPoint.test.ts b/packages/alphatab/test/audio/SyncPoint.test.ts index 8526753d61..27da8ddce1 100644 --- a/packages/alphatab/test/audio/SyncPoint.test.ts +++ b/packages/alphatab/test/audio/SyncPoint.test.ts @@ -6,6 +6,7 @@ import type { AlphaTabMetronomeEvent } from '@coderline/alphatab/midi/MidiEvent' import { MidiFile } from '@coderline/alphatab/midi/MidiFile'; import { MidiFileGenerator } from '@coderline/alphatab/midi/MidiFileGenerator'; import type { BackingTrack } from '@coderline/alphatab/model/BackingTrack'; +import type { Score } from '@coderline/alphatab/model/Score'; import { Settings } from '@coderline/alphatab/Settings'; import { BackingTrackPlayer, type IBackingTrackSynthOutput } from '@coderline/alphatab/synth/BackingTrackPlayer'; import { @@ -13,6 +14,7 @@ import { type IExternalMediaHandler, type IExternalMediaSynthOutput } from '@coderline/alphatab/synth/ExternalMediaPlayer'; +import type { IAlphaSynth } from '@coderline/alphatab/synth/IAlphaSynth'; import type { IAudioSampleSynthesizer } from '@coderline/alphatab/synth/IAudioSampleSynthesizer'; import type { ISynthOutputDevice } from '@coderline/alphatab/synth/ISynthOutput'; import { MidiFileSequencer } from '@coderline/alphatab/synth/MidiFileSequencer'; @@ -357,6 +359,85 @@ describe('SyncPointTests', () => { expect(events.map(e => `${e.currentTime},${e.originalTempo},${e.modifiedTempo}`)).toMatchSnapshot(); expect(testOutput.seekTimes).toMatchSnapshot(); }); + + /** + * See #2952 + */ + describe('non-integer-bar-duration', () => { + // a 4/4 bar at 148 BPM lasts 1621.6216...ms + const tempo = 148; + const barCount = 201; + const ticksPerBar = 3840; + const barMillis = (4 * 60000) / tempo; + const lastSyncTime = (barCount - 1) * barMillis; + + function createScore(): Score { + return ScoreLoader.loadAlphaTex(` + \\tempo ${tempo} + . + ${new Array(barCount).fill('C4.4 * 4').join(' | ')} + . + \\sync 0 0 0 + \\sync ${barCount - 1} 0 ${lastSyncTime} + `); + } + + function createGenerator(score: Score, midi: MidiFile): MidiFileGenerator { + const generator = new MidiFileGenerator(score, new Settings(), new AlphaSynthMidiFileHandler(midi)); + generator.generate(); + return generator; + } + + function expectPlayerInSync(player: IAlphaSynth, seek: (time: number) => void) { + const score = createScore(); + const midi = new MidiFile(); + const generator = createGenerator(score, midi); + + player.loadMidiFile(midi); + player.loadBackingTrack(score); + player.updateSyncPoints(generator.syncPoints); + + let tick = -1; + player.positionChanged.on(e => { + tick = e.currentTick; + }); + player.play(); + + for (let bar = 0; bar < barCount; bar++) { + seek(bar * barMillis); + const expectedTick = bar * ticksPerBar; + expect(Math.abs(tick - expectedTick), `bar ${bar}: tick ${tick}`).toBeLessThanOrEqual(1); + } + } + + it('sync-point-times', () => { + const generator = createGenerator(createScore(), new MidiFile()); + + const syncPoints = generator.syncPoints; + expect(syncPoints[1].synthTick).toBe((barCount - 1) * ticksPerBar); + expect(syncPoints[1].syncTime).toBe(lastSyncTime); + expect(syncPoints[1].synthTime).toBeCloseTo(lastSyncTime, 6); + expect(syncPoints[0].syncBpm).toBeCloseTo(tempo, 6); + }); + + it('external-media-position', () => { + const player = new ExternalMediaPlayer(500); + const output = player.output as IExternalMediaSynthOutput; + const mediaHandler = new TestExternalMediaHandler(output); + mediaHandler.backingTrackDuration = lastSyncTime + barMillis; + output.handler = mediaHandler; + + expectPlayerInSync(player, time => mediaHandler.simulateSeek(time)); + }); + + it('backing-track-position', () => { + const output = new TestBackingTrackOutput(); + output.backingTrackDuration = lastSyncTime + barMillis; + const player = new BackingTrackPlayer(output, 500); + + expectPlayerInSync(player, time => output.simulateSeek(time)); + }); + }); }); describe('MidiFileSequencerCountInTests', () => { diff --git a/packages/alphatab/test/audio/__snapshots__/SyncPoint.test.ts.snap b/packages/alphatab/test/audio/__snapshots__/SyncPoint.test.ts.snap index 99ad5e9795..3e01356c2f 100644 --- a/packages/alphatab/test/audio/__snapshots__/SyncPoint.test.ts.snap +++ b/packages/alphatab/test/audio/__snapshots__/SyncPoint.test.ts.snap @@ -10,7 +10,7 @@ exports[`SyncPointTests > modified-tempo-lookup 1`] = ` "22010.34013605442 => 120.04899959166994", "24009.52380952381 => 120.04899959167003", "30007.074829931975 => 80.01088583480758", - "33006.666666666664 => 80.01778172927317", + "33006.666666666664 => 80.01088583480758", ] `; @@ -50,15 +50,15 @@ exports[`SyncPointTests > playback-fast-backing-track 1`] = ` "18496.530140155122,80,160.02177166961516", "18996.59817662267,80,160.02177166961516", "19496.66621309022,80,160.02177166961516", - "19996.77706156924,80,160.03556345854633", - "20496.888197377197,80,160.03556345854633", - "20996.999333185155,80,160.03556345854633", - "21497.11046899311,80,160.03556345854633", - "21997.221604801067,80,160.03556345854633", - "22497.332740609025,80,160.03556345854633", - "22997.443876416983,80,160.03556345854633", - "23497.55501222494,80,160.03556345854633", - "23997.6661480329,80,160.03556345854633", + "19996.734249557765,80,160.02177166961516", + "20496.80228602531,80,160.02177166961516", + "20996.87032249286,80,160.02177166961516", + "21496.938358960408,80,160.02177166961516", + "21997.006395427954,80,160.02177166961516", + "22497.0744318955,80,160.02177166961516", + "22997.14246836305,80,160.02177166961516", + "23497.210504830597,80,160.02177166961516", + "23997.278541298143,80,160.02177166961516", ] `; @@ -98,15 +98,15 @@ exports[`SyncPointTests > playback-fast-external-media 1`] = ` "18496.530140155122,80,160.02177166961516", "18996.59817662267,80,160.02177166961516", "19496.66621309022,80,160.02177166961516", - "19996.77706156924,80,160.03556345854633", - "20496.888197377197,80,160.03556345854633", - "20996.999333185155,80,160.03556345854633", - "21497.11046899311,80,160.03556345854633", - "21997.221604801067,80,160.03556345854633", - "22497.332740609025,80,160.03556345854633", - "22997.443876416983,80,160.03556345854633", - "23497.55501222494,80,160.03556345854633", - "23997.6661480329,80,160.03556345854633", + "19996.734249557765,80,160.02177166961516", + "20496.80228602531,80,160.02177166961516", + "20996.87032249286,80,160.02177166961516", + "21496.938358960408,80,160.02177166961516", + "21997.006395427954,80,160.02177166961516", + "22497.0744318955,80,160.02177166961516", + "22997.14246836305,80,160.02177166961516", + "23497.210504830597,80,160.02177166961516", + "23997.278541298143,80,160.02177166961516", ] `; @@ -179,24 +179,24 @@ exports[`SyncPointTests > playback-normal-backing-track 1`] = ` "37993.19635324534,80,80.01088583480758", "38493.26438971289,80,80.01088583480758", "38993.33242618044,80,80.01088583480758", - "39493.44298733052,80,80.01778172927317", - "39993.55412313848,80,80.01778172927317", - "40493.665258946436,80,80.01778172927317", - "40993.77639475439,80,80.01778172927317", - "41493.88753056235,80,80.01778172927317", - "41993.99866637031,80,80.01778172927317", - "42494.10980217827,80,80.01778172927317", - "42994.22093798622,80,80.01778172927317", - "43494.332073794176,80,80.01778172927317", - "43994.443209602134,80,80.01778172927317", - "44494.55434541009,80,80.01778172927317", - "44994.66548121805,80,80.01778172927317", - "45494.77661702601,80,80.01778172927317", - "45994.887752833965,80,80.01778172927317", - "46494.99888864192,80,80.01778172927317", - "46995.11002444988,80,80.01778172927317", - "47495.22116025784,80,80.01778172927317", - "47995.3322960658,80,80.01778172927317", + "39493.40046264798,80,80.01088583480758", + "39993.46849911553,80,80.01088583480758", + "40493.53653558308,80,80.01088583480758", + "40993.60457205062,80,80.01088583480758", + "41493.67260851817,80,80.01088583480758", + "41993.74064498572,80,80.01088583480758", + "42493.808681453265,80,80.01088583480758", + "42993.876717920815,80,80.01088583480758", + "43493.94475438836,80,80.01088583480758", + "43994.01279085591,80,80.01088583480758", + "44494.08082732346,80,80.01088583480758", + "44994.148863791,80,80.01088583480758", + "45494.21690025855,80,80.01088583480758", + "45994.2849367261,80,80.01088583480758", + "46494.35297319364,80,80.01088583480758", + "46994.42100966119,80,80.01088583480758", + "47494.48904612874,80,80.01088583480758", + "47994.557082596286,80,80.01088583480758", ] `; @@ -269,24 +269,24 @@ exports[`SyncPointTests > playback-normal-external-media 1`] = ` "37993.19635324534,80,80.01088583480758", "38493.26438971289,80,80.01088583480758", "38993.33242618044,80,80.01088583480758", - "39493.44298733052,80,80.01778172927317", - "39993.55412313848,80,80.01778172927317", - "40493.665258946436,80,80.01778172927317", - "40993.77639475439,80,80.01778172927317", - "41493.88753056235,80,80.01778172927317", - "41993.99866637031,80,80.01778172927317", - "42494.10980217827,80,80.01778172927317", - "42994.22093798622,80,80.01778172927317", - "43494.332073794176,80,80.01778172927317", - "43994.443209602134,80,80.01778172927317", - "44494.55434541009,80,80.01778172927317", - "44994.66548121805,80,80.01778172927317", - "45494.77661702601,80,80.01778172927317", - "45994.887752833965,80,80.01778172927317", - "46494.99888864192,80,80.01778172927317", - "46995.11002444988,80,80.01778172927317", - "47495.22116025784,80,80.01778172927317", - "47995.3322960658,80,80.01778172927317", + "39493.40046264798,80,80.01088583480758", + "39993.46849911553,80,80.01088583480758", + "40493.53653558308,80,80.01088583480758", + "40993.60457205062,80,80.01088583480758", + "41493.67260851817,80,80.01088583480758", + "41993.74064498572,80,80.01088583480758", + "42493.808681453265,80,80.01088583480758", + "42993.876717920815,80,80.01088583480758", + "43493.94475438836,80,80.01088583480758", + "43994.01279085591,80,80.01088583480758", + "44494.08082732346,80,80.01088583480758", + "44994.148863791,80,80.01088583480758", + "45494.21690025855,80,80.01088583480758", + "45994.2849367261,80,80.01088583480758", + "46494.35297319364,80,80.01088583480758", + "46994.42100966119,80,80.01088583480758", + "47494.48904612874,80,80.01088583480758", + "47994.557082596286,80,80.01088583480758", ] `; @@ -311,7 +311,7 @@ exports[`SyncPointTests > seek-fast-backing-track 2`] = ` 4000, 8001.292517006803, 23343.12925170068, - 36006, + 36006.258503401354, ] `; @@ -336,7 +336,7 @@ exports[`SyncPointTests > seek-fast-external-media 2`] = ` 4000, 8001.292517006803, 23343.12925170068, - 36006, + 36006.258503401354, ] `; @@ -398,8 +398,8 @@ exports[`SyncPointTests > sync-point-generation 1`] = ` "8,0,80,120.04899959166994,24000,22010.34013605442", "9,0,80,120.04899959167003,27000,24009.52380952381", "8,1,80,80.01088583480758,36000,30007.074829931975", - "9,1,80,80.01778172927317,39000,33006.666666666664", - "11,0,80,80.01088583480758,48000,42004.666666666664", + "9,1,80,80.01088583480758,39000,33006.666666666664", + "11,0,80,80.01088583480758,48000,42005.44217687073", ] `; @@ -422,7 +422,7 @@ exports[`SyncPointTests > sync-point-update 1`] = ` "8,0,80,120.04899959166994,24000,22010.34013605442", "9,0,80,120.04899959167003,27000,24009.52380952381", "8,1,80,80.01088583480758,36000,30007.074829931975", - "9,1,80,80.01778172927317,39000,33006.666666666664", - "11,0,80,80.01088583480758,48000,42004.666666666664", + "9,1,80,80.01088583480758,39000,33006.666666666664", + "11,0,80,80.01088583480758,48000,42005.44217687073", ] `; diff --git a/packages/alphatab/test/exporter/Gp7Exporter.test.ts b/packages/alphatab/test/exporter/Gp7Exporter.test.ts index af7ded3912..eaa1e4459d 100644 --- a/packages/alphatab/test/exporter/Gp7Exporter.test.ts +++ b/packages/alphatab/test/exporter/Gp7Exporter.test.ts @@ -184,6 +184,20 @@ describe('Gp7ExporterTest', () => { expect(gpif).toContain('1>'); }); + it('beat-timer-as-integer', () => { + const score = ScoreLoader.loadAlphaTex(` + C4.4 { timer } C4.4 { timer } + `); + const beats = score.tracks[0].staves[0].bars[0].voices[0].beats; + beats[0].timer = 1621.4; + beats[1].timer = 3243.6; + + const gpif = readExportedGpif(exportGp7(score)); + + expect(gpif).toContain('1621'); + expect(gpif).toContain('3244'); + }); + it('alphatex-drums-to-gp7', () => { const tex = `\\track "Drums" { instrument percussion } \\clef neutral diff --git a/packages/alphatab/test/importer/AlphaTexImporter.test.ts b/packages/alphatab/test/importer/AlphaTexImporter.test.ts index c37fd57fa7..58880c5537 100644 --- a/packages/alphatab/test/importer/AlphaTexImporter.test.ts +++ b/packages/alphatab/test/importer/AlphaTexImporter.test.ts @@ -2241,6 +2241,31 @@ describe('AlphaTexImporterTest', () => { testExportRoundtrip(score); }); + it('sync-float-millisecond-offset', () => { + const score = parseTex(` + \\tempo 148 + . + 3.3.4*4 | 3.3.4*4 | 3.3.4*4 | 3.3.4*4 + . + \\sync 0 0 0 + \\sync 1 0 1621.6216216216217 + \\sync 2 0 3243.25 0.5 + \\sync (3 0 4864.865) + `); + + expect(score.masterBars.length).toBe(4); + expect(score.tracks[0].staves[0].bars[3].voices[0].beats.length).toBe(4); + const syncPoints = score.exportFlatSyncPoints(); + expect(syncPoints.map(p => `${p.barIndex},${p.barOccurence},${p.barPosition},${p.millisecondOffset}`)).toEqual([ + '0,0,0,0', + '1,0,0,1621.6216216216217', + '2,0,0.5,3243.25', + '3,0,0,4864.865' + ]); + + testExportRoundtrip(score); + }); + it('tuning-name', () => { const score = parseTex(` \\tuning E4 B3 G3 D3 A2 E2 "Default" diff --git a/packages/alphatex/src/metadata/bar/sync.ts b/packages/alphatex/src/metadata/bar/sync.ts index 03cf2eb864..cdb24edfbf 100644 --- a/packages/alphatex/src/metadata/bar/sync.ts +++ b/packages/alphatex/src/metadata/bar/sync.ts @@ -34,7 +34,7 @@ export const sync: MetadataTagDefinition = { { name: 'millisecondOffset', shortDescription: 'The absolute millisecond offset within the external media', - parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.Required, + parseMode: alphaTab.importer.alphaTex.ArgumentListParseTypesMode.RequiredAsFloat, type: alphaTab.importer.alphaTex.AlphaTexNodeType.Number }, { From 83fb8644f93c8a95d92e00cc634114d224560060 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sat, 17 Oct 2026 13:07:40 +0200 Subject: [PATCH 2/2] test: build repeated alphaTex bars with a loop for Kotlin compatibility --- packages/alphatab/test/audio/MidiFileGenerator.test.ts | 6 +++++- packages/alphatab/test/audio/SyncPoint.test.ts | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/alphatab/test/audio/MidiFileGenerator.test.ts b/packages/alphatab/test/audio/MidiFileGenerator.test.ts index 3e908ddf5d..15b67ca6d7 100644 --- a/packages/alphatab/test/audio/MidiFileGenerator.test.ts +++ b/packages/alphatab/test/audio/MidiFileGenerator.test.ts @@ -1939,10 +1939,14 @@ describe('MidiFileGeneratorTest', () => { it('beat-timer-non-integer-bar-duration', () => { // a 4/4 bar at 148 BPM lasts 1621.6216...ms const barCount = 200; + const barTex: string[] = []; + for (let i = 0; i < barCount; i++) { + barTex.push('C4.4 { timer } C4.4 * 3'); + } const score: Score = parseTex(` \\tempo 148 . - ${new Array(barCount).fill('C4.4 { timer } C4.4 * 3').join(' | ')} + ${barTex.join(' | ')} `); const handler: FlatMidiEventGenerator = new FlatMidiEventGenerator(); diff --git a/packages/alphatab/test/audio/SyncPoint.test.ts b/packages/alphatab/test/audio/SyncPoint.test.ts index 27da8ddce1..95cd902db1 100644 --- a/packages/alphatab/test/audio/SyncPoint.test.ts +++ b/packages/alphatab/test/audio/SyncPoint.test.ts @@ -372,10 +372,14 @@ describe('SyncPointTests', () => { const lastSyncTime = (barCount - 1) * barMillis; function createScore(): Score { + const barTex: string[] = []; + for (let i = 0; i < barCount; i++) { + barTex.push('C4.4 * 4'); + } return ScoreLoader.loadAlphaTex(` \\tempo ${tempo} . - ${new Array(barCount).fill('C4.4 * 4').join(' | ')} + ${barTex.join(' | ')} . \\sync 0 0 0 \\sync ${barCount - 1} 0 ${lastSyncTime}