Skip to content

Feature: machine-readable CLI progress on stderr (pct + phase + detail) #141

@cjslickmusic-max

Description

@cjslickmusic-max

Summary

When ConvertWithMoss runs in CLI mode on a large Kontakt library (one .nki with hundreds of samples), the only live feedback is a stream of . dots on stdout (IDS_NOTIFY_PROGRESS). That is fine for humans, but automation hosts and DAW plugins that spawn CWM as a child process cannot derive a numeric percentage or current item from dots alone.

We hit this integrating CWM into a proprietary DAW plugin (Kontakt import via SFZ). On a typical .nki import the UI stayed at 0% for minutes, then jumped to 100% when conversion finished.

We implemented a small, opt-in extension and would like to upstream it (or something equivalent) so all CLI users benefit.


Proposal

Add an opt-in machine-readable progress protocol on stderr, separate from the existing human-oriented stdout dots.

Activation (opt-in, zero cost when off)

  • CLI flag: -P / --machine-progress
  • Environment (optional): CWM_MACHINE_PROGRESS=1 or true (for wrappers that cannot pass flags easily)

When disabled, behaviour is unchanged.

Line format

One ASCII line per event, newline-terminated, stderr, flushed immediately:

CWM_PROGRESS pct=<0..100> phase=<token> detail=<text>
  • pct: integer 0..100
  • phase: sanitized token, e.g. start, convert, sample, done
  • detail: short ASCII-safe snippet (filename / path tail)

Example session:

CWM_PROGRESS pct=0 phase=start detail=C:/Libraries/MyBank
CWM_PROGRESS pct=12 phase=convert detail=Enigma.nki
CWM_PROGRESS pct=14 phase=sample detail=Kick_01.wav
CWM_PROGRESS pct=15 phase=sample detail=Snare_02.wav
...
CWM_PROGRESS pct=100 phase=done detail=

Hosts grep stderr for the prefix; humans can ignore unknown lines.

Where to emit (minimal hooks)

We found AbstractDetector is the right central place:

  1. Before detect(): count matching instrument files recursively (machineProgressTotal), emit phase=start.
  2. Per instrument file: emit phase=convert at file start (non-zero pct inside the file's slice) and after file finish.
  3. Per sample zone: in createSampleZone() emit phase=sample after each WAV/NCW load.
  4. After detect(): emit phase=done at 100%.

Percentage model

  • Between files: linear by completed file count (done / total * 100).

  • Inside one big file: interpolate within the current file's pct slice. Total sample count per .nki is unknown upfront, so we use a smooth asymptote toward the slice ceiling:

    withinPct = fileLo + span * (1 - exp(-samplesDone / 25))

    This gives steady forward motion on large libraries without lying that we know the final sample count.


Reference implementation (public)

We ship a working patch set (LGPL-compatible, tested on CWM 17.2.0 tip) in our public ConvertWithMoss fork:

Piece Location
Patches + protocol docs https://github.com/cjslickmusic-max/ConvertWithMoss/tree/main/rus-contrib/machine-progress
Full patched sources https://github.com/cjslickmusic-max/ConvertWithMoss/tree/rus-patched-2026-05
Pre-built Windows CLI (zip) https://github.com/cjslickmusic-max/ConvertWithMoss/releases/tag/rus-patched-17.2.0

Our fork uses prefix RUS_CWM_PROGRESS for host-side namespacing; for upstream we'd happily rename to CWM_PROGRESS and align env/flag naming with your preference.

The patch touches:

  • CLIBackend.java — add -P / --machine-progress, call MachineProgressReporter.setCliRequested()
  • new MachineProgressReporter.java — stderr emitter + sanitization
  • AbstractDetector.java — file/sample counting + pct helpers + hooks in detect loop and createSampleZone()

No GUI changes required; GUI can ignore the reporter entirely.


Why stderr?

CLI stdout already carries dots and completion text. Structured progress on stderr keeps parsers simple and matches common Unix tooling (2>&1 merge optional).


Offer

Happy to open a PR against main with:

  • neutral CWM_PROGRESS prefix
  • -P flag + optional env gate
  • unit-free reporter class under core
  • short manual / CLI doc paragraph

We maintain a patched build for our users today; upstreaming would let us drop the fork-specific prefix and rely on official installers.

Thank you for ConvertWithMoss — it is the backbone of our Kontakt import path. Issue #139 (loop tune) was also very helpful on our side.

— Alex (cjslickmusic-max on GitHub)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions