Skip to content

fix(player): late midiLoaded registration overflows the stack with the worker player - #2928

Merged
Danielku15 merged 2 commits into
developfrom
fix/2862-worker-midi-loaded-replay
Oct 7, 2026
Merged

Danielku15 merged 2 commits into
developfrom
fix/2862-worker-midi-loaded-replay

Conversation

@Danielku15

Copy link
Copy Markdown
Member

Note

AI-authored disclosure (alphatab-ai-authored-v1)

Portions of this content were authored by an AI agent. The agent has read
AGENTS.md and the human submitter accepts responsibility for
compliance with the rules in that document.

Issues

Fixes #2862

Proposed changes

Registering a midiLoaded handler should immediately hand it the current value. With the worker player this instead failed with RangeError: Maximum call stack size exceeded.

The value is read through a chain: AlphaTabApiBase.midiLoaded → AlphaSynthWrapper.loadedMidiInfo → AlphaSynthWebWorkerApi.loadedMidiInfo. The last getter returned itself (this.loadedMidiInfo) instead of the backing field _loadedMidiInfo, so every read recursed. The field is set correctly when the worker reports alphaSynth.midiLoaded; it was just never read. The getter has been wrong since #2284. The API and wrapper layers are correct, so the fix is only this getter.

Registering before the first load seemed to work only because, with enablePlayer: true (automatic player mode), the worker player is attached once a score exists. Before that, the wrapper has no instance and never reaches the broken getter.

The same class is also used as the worker player on C# (ManagedUiFacade) and Android (AndroidUiFacade). There the recursion is a stack overflow that kills the process, so those platforms get the fix too.

Checklist

  • I consent that this change becomes part of alphaTab under its current or any future open source license
  • This PR is linked to an accepted issue (see above)
  • Changes are implemented
  • New tests were added
  • I have read AGENTS.md if an AI helped draft any part of this PR

New test test/audio/AlphaSynthWebWorkerApi.test.ts: it simulates the worker's MIDI-loaded message, then registers midiLoaded through AlphaSynthWrapper. It checks that the handler is called once with the loaded values. It fails with the reported recursion before the fix. It is marked @target web because it passes worker messages as plain objects, which can't be built in the C#/Kotlin tests. C# and Kotlin builds pass with the changed source.

AI authorship disclosure

  • No AI agent authored any part of this PR (description, code, tests, or commit messages)
  • An AI agent contributed to this PR. The AI-authored disclosure block
    (alphatab-ai-authored-v1) is present at the top of this body, and I have
    personally reviewed every change and can explain each one

Further details

  • This is a breaking change
  • This change will require update of the documentation/website

The loadedMidiInfo getter returned itself instead of the backing field,
so any late midiLoaded registration recursed until the stack overflowed.

Fixes #2862
@Danielku15
Danielku15 merged commit 305ab1c into develop Oct 7, 2026
6 checks passed
@Danielku15
Danielku15 deleted the fix/2862-worker-midi-loaded-replay branch October 7, 2026 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

api.midiLoaded.on() registered after the MIDI is loaded throws "RangeError: Maximum call stack size exceeded" (WebWorker player)

1 participant