Conversation
Grooves, Chord Vamp, and Bassment each carried their own copy of these helpers on their feature branches, and the copies had already started to diverge: genre_palette gained GENRE_PROG_8 on some branches while others still shipped the unused GENRE_COLORS table. Landing them once, ahead of the apps, gives the three a single source of truth and lets each app PR shrink to its own app file. The files are taken from the flashed playground state, which is ahead of every feature branch for groove.rs. Purely additive: three new modules plus their declarations. register_apps! is untouched and no existing app or platform file changes, so stock app behaviour cannot be affected. The modules are dead code until the first consumer app lands, hence the allow(dead_code) on the declarations. Authored by an AI coding agent on behalf of kosmar.
This was referenced Aug 12, 2026
Closed
Same reasoning as the genre helpers next to it: Bassment, Contura, Chord Vamp, Venn and Arp de Lévy all resolve the device Key/Tonic, and landing it once ahead of the app PRs keeps the copies from diverging. Note-generating apps each carried their own idea of Root and Scale, so the device-wide Key/Tonic — live on the Scene button plus Fader 4/5 — could not act as a transpose. This gives one place to resolve it: the normalized device Key, the tonic pitch class, a root retuned onto it keeping its octave, and a combined call that costs a single GlobalConfig copy instead of two. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
clippy::chunks_exact_to_as_chunks fires on the constant chunk size in the USB RX loop, and CI runs clippy with -D warnings, so main does not pass its own gate on a current toolchain. Feature branches have been carrying this same one-line fix inside unrelated app commits to stay green; landing it here means they no longer have to. as_chunks::<4>() yields &[[u8; 4]], so the packet indexing below is unchanged. The discarded remainder matches the previous behaviour: chunks_exact dropped a trailing partial packet too, and a USB MIDI bulk transfer is always a multiple of four bytes. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
Fourteen apps carry their own copy of the 24 PPQN division table and five repeat the free-running LFO speed curve, so the magic numbers and the bounds checks drift independently. Centralise them as CLOCK_DIVISIONS, division_at, lfo_step, lfo_step_modulated, quant_step and signal_brightness with unit tests. The tests uncovered a wrap in the brightness curve that every caller shared: a bipolar 4095 divides to 256 and cast to u8 as 0, dimming the button at the very peak of the wave. It clamps now. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Aug 13, 2026
Apps that add their own swing on top of the device clock had no way to ask how much the clock has already moved a step, so they could only switch their own timing off whenever global swing was non-zero. device_swing_permille reports that displacement as a fraction of the app's grid step, and returns zero for grids coarser than the swing window half, where the clock never moves the step at all. device_swing_reverses tells an app which parity to delay so its feel leans with the clock rather than against it, with a threshold so a global swing of a few percent stays straight instead of flipping parity for a displacement that is barely audible. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Author
|
Written by an AI coding agent on @kosmar's behalf.
Apps that layer their own swing on the device clock had no way to ask how much the clock had already moved a step, so they could only switch their own timing off whenever global swing was non-zero. The new helpers report that displacement as a fraction of the app’s grid step (zero when the grid is coarser than the swing window half) and which parity to delay so Feel leans with the clock. Consumed by #633 and #648. |
10 tasks
This was referenced Aug 22, 2026
Closed
Closed
This branch has not been deployed
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.
Summary
Adds small shared helpers that the upcoming WIP apps all need, so each app PR
can shrink to its own app file plus a registry line.
Under
faderpunk/src/apps/, for the genre-based apps (Grooves, Chord Vamp,Bassment):
genre_palette.rs— shared genre names and 8-bar tropesgroove.rs— swing/feel curves and swing delay mathsled_fx.rs— spectrum colour helpers for the genre scrub axisfollow_key.rs— shared helper for following the device tonalityIn
libfp::utils, for the clocked and LFO-style apps (Super LFO, Manifold,Venn, Contura, Hold Sam):
CLOCK_DIVISIONSanddivision_at— one division table, and an even mappingfrom a fader to a prefix of it, replacing the per-app tables and the ad-hoc
value / 500style lookupslfo_step/lfo_step_modulated— the exponential rate curve, with andwithout CV modulation
quant_step— phase increment for a clock-synced cyclesignal_brightness— the LED brightness curve for a unipolar or bipolarsignal
Each of those apps currently carries its own copy on its feature branch, and
the copies have already diverged —
genre_palettegainedGENRE_PROG_8onsome branches while others still ship the now-unused
GENRE_COLORStable.Landing the helpers once, ahead of the apps, gives them a single source of
truth. The contents are taken from the integration branch these apps are
flashed from, which is ahead of every feature branch for
groove.rs.Centralising
signal_brightnessalso fixed a bug the copies shared: at fullscale a bipolar value produced
(4095 - 2047) / 8 = 256, which wrapped to0in
u8and dimmed the LED instead of lighting it. The shared version clampsbefore the cast, and the unit tests cover it.
Scope
Additive. New app-side modules plus their
moddeclarations, and new functionsplus unit tests in
libfp::utils.register_apps!is untouched and no existingapp or platform file is modified, so stock app behaviour cannot be affected.
The app-side modules are dead code until the first consumer app lands, hence
the
#[allow(dead_code)]on the declarations; the first app PR to use them candrop it.
Test plan
No hardware checklist: this change adds no reachable code path and no runtime
behaviour.
cargo build --releaseandcargo test --lib -p libfpagainstcurrent
mainare the whole verification.Made with Cursor