Repository navigation
SoundFont 2: apply preset-level generators to defaults, fix the resonance decade and keep negative envelope amounts - #255
Merged
git-moss merged 2 commits intoJul 29, 2026
Conversation
…ance decade and keep negative envelope amounts Generators which only appear on the preset level were dropped entirely when the instrument level did not carry the same generator, although the specification defines them as offsets to the default value in that case. A preset whose global zone transposes a plain instrument down an octave was read an octave too high, preset-level attenuation and envelope offsets vanished, and a preset-level filter offset never created a filter. The offset is now applied to the instrument value or to the generator's default, and it is sign-converted on the unsigned lookup path as well. The filter resonance was read as centibels divided by 100 instead of 10, so every resonance came out ten times too small and each round trip divided it by ten again; writing was already correct. Negative pitch and filter envelope modulation amounts (downward sweeps) were dropped when writing although both generators are signed in the format and reading them was already correct.
The open fix PRs all inserted their changelog entries near the same lines, so every merged PR turned the remaining ones into conflicts. The entries of the whole batch are collected in PR git-moss#283 and quoted in each PR's description; the fix branches no longer touch the changelog, so they merge cleanly in any order.
git-moss
pushed a commit
that referenced
this pull request
Sep 25, 2026
…ance decade and keep negative envelope amounts (#255) * SoundFont 2: apply preset-level generators to defaults, fix the resonance decade and keep negative envelope amounts Generators which only appear on the preset level were dropped entirely when the instrument level did not carry the same generator, although the specification defines them as offsets to the default value in that case. A preset whose global zone transposes a plain instrument down an octave was read an octave too high, preset-level attenuation and envelope offsets vanished, and a preset-level filter offset never created a filter. The offset is now applied to the instrument value or to the generator's default, and it is sign-converted on the unsigned lookup path as well. The filter resonance was read as centibels divided by 100 instead of 10, so every resonance came out ten times too small and each round trip divided it by ten again; writing was already correct. Negative pitch and filter envelope modulation amounts (downward sweeps) were dropped when writing although both generators are signed in the format and reading them was already correct. * Move the changelog entry to the collected changelog PR #283 The open fix PRs all inserted their changelog entries near the same lines, so every merged PR turned the remaining ones into conflicts. The entries of the whole batch are collected in PR #283 and quoted in each PR's description; the fix branches no longer touch the changelog, so they merge cleanly in any order.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three related reading/writing defects in the SoundFont 2 support.
Preset-level generators were dropped when the instrument level does not carry the same generator.
GeneratorHierarchy.getSignedValue/getUnsignedValuereturned the generator's default as soon as neither instrument-level map held a value, without ever consulting the preset zones - but the specification (SF2 2.04, section 9.4) defines preset generators as additive offsets which apply to the instrument value or to the default when the instrument omits the generator; FluidSynth implements exactly that. A preset whose global zone carriescoarseTune=-12over a plain instrument was read an octave too high, preset-levelinitialAttenuation/fineTune/envelope offsets vanished, and a preset-levelinitialFilterFcoffset never created a filter (the untouched default 13500 is the "no filter" gate). Such generators are routine in commercial and General MIDI SoundFonts. On the unsigned lookup path the offset was additionally added without the signed conversion, so a negative offset was added as a huge positive number.The filter resonance was read a decade too small.
initialFilterQis centibels; the writer stores dB x 10 (with a comment saying so), but the reader divided by 100 - every resonance came out ten times too small (20 dB read as 2 dB) and each SoundFont-to-SoundFont round trip divided by ten again.Negative envelope modulation amounts were dropped on write.
modEnvToPitchandmodEnvToFilterFcare signed generators and the reader takes them signed, but the writer gated both on> 0- a downward filter sweep or the pitch drop of an 808-style kick lost its whole modulation envelope.Verified with crafted SoundFonts (a preset-level-offset zone over a bare instrument, and an instrument-level resonance case), before vs. after:
modEnvToFilterFc = -1200plus the envelope timesThe read side of the negative amounts and all other generator laws were already correct and are untouched. (The SFZ creator has the same
> 0gate on its own output side; that is a separate format and will come separately.)Changelog entry (all entries of this PR batch are collected in #283, so the fix PRs themselves do not touch the changelog and merge conflict-free in any order):