Skip to content

DLS: fix the pitch scale conversions which saturated#217

Merged
git-moss merged 1 commit into
git-moss:mainfrom
douglas-carmichael:fix-dls-pitch-scale
Jul 24, 2026
Merged

DLS: fix the pitch scale conversions which saturated#217
git-moss merged 1 commit into
git-moss:mainfrom
douglas-carmichael:fix-dls-pitch-scale

Conversation

@douglas-carmichael

Copy link
Copy Markdown
Contributor

DlsDetector.normalizeEG2ToPitch clamps the raw 32-bit connection value to ±1200 and divides by 1200 — but that value is a relative pitch stored as a fixed point number with 65536 representing one cent, the same convention the file's own absoluteTimeToSeconds already divides out. So every non-zero value saturates to full scale.

The helper was used for three different quantities, each with a different correct unit, so all three were wrong:

  • Pitch envelope depth — now divided by 65536 and normalized over MAX_ENVELOPE_DEPTH like every other format, so a one-octave envelope is 1200 cent rather than ten octaves.
  • Pitch tuning — now converted to semi-tones (65536 per cent, 100 cent per semi-tone).
  • Modulation-envelope sustain — now routed through the sustain-level conversion, the same path the first envelope already uses. This branch is currently unreached (the envelope is only ever built for EG1), but fixing it lets the broken helper be removed.

The now-unused normalizeEG2ToPitch is deleted. One file, DlsDetector.java.

Validation

Measured against the Roland GS set that ships with macOS (gs_instruments.dls), converted DLS → SFZ before and after:

  • Before, 522 zones wrote their pitch-envelope depth as exactly pitcheg_depth=±12000 (the saturated maximum, ten octaves).
  • After, those same 522 zones spread across their real values — 1200, 1000, 200, -95, -63, -29, ... cent — matching the raw connection values decoded straight from the file.
  • The full before/after diff touches only pitcheg_depth; loops, key ranges, amplitude envelopes and everything else are byte-identical, so there is no collateral change.

The tuning and sustain paths are not exercised by this particular set (it has no region-level pitch tuning connection, and the sustain branch is unreached as noted), so their fix is by unit analysis rather than a visible diff here.

Note

Independent of #216 (the pitch-LFO PR): different concern, and #216 touches DlsDetector only by adding a separate block, so the two can merge in either order.

DlsDetector.normalizeEG2ToPitch clamped the raw 32-bit connection value
to +-1200 and divided by 1200, but that value is a relative pitch stored
as a fixed point number with 65536 representing one cent. Every non-zero
value therefore saturated to full scale.

* Pitch envelope depth: divided by 65536 first and normalized over the
  same range as every other format, so a one octave envelope is 1200
  cent and not ten octaves. Measured on the Roland GS set that ships with
  macOS (gs_instruments.dls): 522 zones that were all written as +-12000
  cent are now spread across their real -1200..1200 cent values.
* Pitch tuning: converted to semi-tones (65536 per cent, 100 cent per
  semi-tone) instead of the saturated value.
* Modulation envelope sustain: routed through the sustain level
  conversion like the first envelope instead of the pitch conversion.
  This branch is currently unreached because the envelope is only ever
  created for the first EG, but it removes the last use of the helper.

The now unused normalizeEG2ToPitch is removed.
@douglas-carmichael
douglas-carmichael marked this pull request as ready for review July 24, 2026 12:08
@git-moss
git-moss merged commit 47214ab into git-moss:main Jul 24, 2026
@douglas-carmichael
douglas-carmichael deleted the fix-dls-pitch-scale branch July 25, 2026 14:11
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.

2 participants