Repository navigation
Add a keyboard row in OUTPUT - #113
Merged
Merged
Conversation
So the key number can scale a partial's level
benjamindehli
deleted the
feature/106-a-keyboard-row-in-output-so-the-key-number-can-scale-a-partials-level
branch
November 3, 2026 23:48
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.
I wanted each channel's level to follow where on the keyboard a note is played, so a patch can be voiced across the keyboard the way an organ builder voices a stop: the fundamental weaker on the low keys, bell partials only on the top keys, the noise only in one range, or a partial that only sounds on one side of a near split. TRACK makes high notes duller, but it is the same for every partial and only works one way. This row is set per channel and can go either way.
The row
KEYBOARD sits in OUTPUT between VELOCITY and AFTERTOUCH, on every channel and on noise. It runs from -200% to 200% and only ever turns keys down, so a partial is never louder than its fader. Zero is the default and does nothing.
It reads the key number, not the pitch, so bend, TUNE, the temperament and drift leave the level alone. Under a glide the key slides with the pitch from the old key to the new one, so a legato line does not jump in level. The noise channel takes its key from the first partial, as the resonator does. The row scales AFTERTOUCH's part of the level too, so pressure cannot bring a partial back on keys the row has faded it out of. The gain is worked out again only when the amount or the key changes, so a held note costs nothing extra.
The DSP side is
Source/dsp/Keyboard.h:keyboardTilt,keyboardDecibels,keyboardGain, andKeyboardCache, which keeps the last gain per partial.The lamp
The OUTPUT rule now has one long lamp in three parts instead of two round lamps: velocity, keyboard and aftertouch, in the order of the rows. I rendered three round lamps at 7 and 6 px first. On a 38 px strip each gets about 12 px, and since each lamp is its own opaque component, its glow was cut off in a straight line at its edge. One slot, like the PITCH MOD needle's, keeps all three glows inside one component. The seams between the parts mix the colours on either side and darken them, so it reads as one lamp. The keyboard part shows what the row leaves on the key being played, full at rest like the velocity part, and it follows a glide.
Older patches and automation
valueInOlderFilessets them to zero there too. The factory presets set zero in their shared base.A correction to how older files load
While testing this I found that the comments from the velocity curve were wrong about JUCE. A session that does not name a parameter puts it at its default. It does not leave it where it was. Only a preset file keeps the last patch's value. The velocity curve behaves correctly either way, since its default is dB and an old session has to load on Classic. I corrected the comments in
PluginParameters.handPluginProcessor.cppand the paragraph in DESIGN.md.What changes for users
How it was checked
DSP suite, a new test:
Runtime suite, a new test:
Breaking it on purpose:
The runtime suite passes with 1548 checks and the DSP suite with 1418, both with no failures. The DSP core builds on its own with
-Werror. clang-format, prettier,build_site.py --check, the counts and structured data checks and the lambda scan pass too.Closes #106