Skip to content

feat: add generic setCtl(name, value) to ChiptuneJsPlayer#5

Open
indigo423 wants to merge 1 commit into
DrSnuggles:v3from
indigo423:feat/set-ctl
Open

feat: add generic setCtl(name, value) to ChiptuneJsPlayer#5
indigo423 wants to merge 1 commit into
DrSnuggles:v3from
indigo423:feat/set-ctl

Conversation

@indigo423
Copy link
Copy Markdown

Summary

Adds a generic setCtl(name, value) method to ChiptuneJsPlayer and a matching 'setCtl' case in the worklet's handleMessage_. Mirrors the existing setPitch / setTempo shape — same stackSave / stackRestore bracketing, same fail-quiet guard.

Why

There's currently no main-thread path to set a libopenmpt control value that doesn't already have a dedicated wrapper. Consumers who need a knob outside the existing setPitch / setTempo / setStereoSeparation set have to fork the worklet.

The most common real-world case is overriding the hardcoded render.resampler.emulate_amiga defaults that play() stamps onto every new module (chiptune3.worklet.js:212–219). Today those defaults are pinned to emulate_amiga="1" + emulate_amiga_type="a1200" and there's no way to expose them as a user-facing setting — the only escape is recreating the ChiptuneJsPlayer instance, which destroys the AudioContext, reloads the worklet, and gives the listener half a second of silence on every toggle.

setCtl fills the gap without committing the class API to one specific control. Name and value are passed as strings, the same encoding libopenmpt's own ctl interface expects.

Use case

CoolModFiles.com is a web-based Amiga MOD player. We want a three-state Amiga emulation toggle in the player UI — Off (modern clean resampler) / A500 (warm, ~4.9 kHz analogue filter) / A1200 (bright, ~28 kHz filter) — letting listeners A/B the sound character of two real Amiga hardware models against libopenmpt's modern path. The toggle has to work mid-track without audio interruption, which means the existing 'rebuild the player' workaround is unacceptable.

With setCtl, the toggle is two ctl_set calls and an audible filter change on the next render block:

player.setCtl('render.resampler.emulate_amiga', '1')
player.setCtl('render.resampler.emulate_amiga_type', 'a500')

The Amiga emulation toggle is already live at mods.amiga.fans, currently riding a local fork of this patch.

Diff

+15 lines, 2 files. No new dependencies, no API removals, no behaviour changes for existing consumers.

  • chiptune3.js: setCtl(name, value) { this.postMsg('setCtl', { name, value }) } placed next to setTempo.
  • chiptune3.worklet.js: new case 'setCtl' in handleMessage_ placed next to setTempo.

Notes

  • .min.js siblings are not regenerated in this PR — assuming minify.js runs as part of a release cut. Happy to include them if you'd prefer.
  • The branch is forked off v3 (current default).

Thanks for chiptune — it's the audio backbone of our site.

Add a main-thread method that posts an arbitrary libopenmpt
ctl_set(key, value) pair to the worklet, plus a matching
'setCtl' case in handleMessage_ that performs the actual
openmpt_module_ctl_set call (bracketed by stackSave/stackRestore
the same way the existing 'setPitch' / 'setTempo' cases do).

Today the only way for a consumer to set a libopenmpt control
value that doesn't already have a dedicated wrapper method (e.g.
'play.pitch_factor', 'play.tempo_factor') is to fork the worklet.
The most common case in practice is overriding the hardcoded
'render.resampler.emulate_amiga' / 'render.resampler.emulate_amiga_type'
values that play() stamps onto every new module -- consumers who
want to expose an Amiga A500/A1200/Off toggle (the warm A500 filter
~4.9 kHz vs the brighter A1200 ~28 kHz vs libopenmpt's modern
resampler) currently have no path to do it without recreating the
ChiptuneJsPlayer and incurring an AudioContext+worklet reload.

setCtl fills that gap without committing the class API to one
specific control. The name and value are passed as strings -- the
same encoding libopenmpt's own ctl interface expects.

Use case: CoolModFiles.com exposes an Amiga emulation toggle in the
player UI. With setCtl, switching A500 -> A1200 mid-track is two
ctl_set calls and an audible filter change on the next render block,
no AudioContext rebuild.

The .min.js siblings are not regenerated in this PR -- assuming
minify.js runs as part of a release cut. Happy to include them if
preferred.

Assisted-by: ClaudeCode:claude-opus-4-7
Signed-off-by: Ronny Trommer <ronny@no42.org>
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.

1 participant