Skip to content

feat: Giant Steps + Axis Matrix (Coltrane apps) - #648

Closed
kosmar wants to merge 27 commits into
ATOVproject:mainfrom
kosmar:feat/coltrane-apps
Closed

kosmar wants to merge 27 commits into
ATOVproject:mainfrom
kosmar:feat/coltrane-apps

Conversation

@kosmar

@kosmar kosmar commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Two new Coltrane-inspired apps sharing a geometry module (coltrane_geo.rs)
  • Giant Steps (ID 44): clock-driven chord sequencer cycling through configurable tonal center intervals with ii-V-I approach patterns and Coltrane chord qualities
  • Axis Matrix (ID 45): playable fader navigator through a 3x3 grid of tonal centers and harmonic functions, with snap zones, latch and drone modes

Test checklist

  • Giant Steps: load on a channel, connect MIDI synth, verify chord cycle advances on clock
  • Giant Steps: sweep Density fader through 3/6/9 chord depths
  • Giant Steps: button tap resets, hold reverses direction
  • Giant Steps: change Interval param (m3/M3/P4/Tritone), verify center spacing changes
  • Axis Matrix: load on a channel, sweep Main fader across three center zones
  • Axis Matrix: verify approach chords sound in transition zones between centers
  • Axis Matrix: Alt fader switches between I/V/ii functions
  • Axis Matrix: tap = latch, hold = drone mode
  • Both: CV Out tracks root pitch, Follow device tonic transposes
  • Both: LED shows three distinct center hues

Made with Cursor

kosmar and others added 12 commits August 10, 2026 11:08
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
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.
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>
Review feedback on ATOVproject#639: a dropped NoteOn is silence, but a dropped
NoteOff hangs the note until something else ends it, and there is no
later message to correct it. APP_MIDI_CHANNEL is shared by all 16
channels, so the drop is not something a voice engine can avoid by
behaving well — any busy neighbour can fill the queue.

Every real caller sits in an async voice task where `.await` is
available, so falling back to the blocking send_note_off costs at most a
late NoteOff. try_send_note_on and try_send_cc stay: dropping those is
self-correcting.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kosmar
kosmar marked this pull request as draft August 14, 2026 20:17
Co-authored-by: Cursor <cursoragent@cursor.com>
@kosmar
kosmar force-pushed the feat/coltrane-apps branch from 79b327b to a025f74 Compare August 14, 2026 20:20
kosmar and others added 3 commits August 14, 2026 22:37
Map the three centers to +0/+120/+240 deg around the app Color hue so
Presetpunk/CONFIG color steers the whole triad instead of a fixed palette.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
A modulator that never reaches its rails could only nudge the target a little,
since CV Att could at most pass the input through unchanged. Allowing gain up
to 4x lets a tame LFO drive the destination across the full range, with the
existing clamp in attenuate_bipolar turning the excess into a hold at the end
stops. Stored presets keep their behaviour: the scale is linear and 100 still
means unity.

Co-authored-by: Cursor <cursoragent@cursor.com>
build_cycle and Axis Matrix's function_root_offset both placed the m7 two
semitones below the tonal center, so a C center resolved Bbm7-G7-Cmaj7 instead
of Dm7-G7-Cmaj7. The ii sits a fifth above the V, which is two semitones up.
This also makes the manuals' "subdominant approach" accurate, since a ii chord
carries subdominant function and a bVIIm7 does not.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kosmar kosmar mentioned this pull request Aug 15, 2026
7 tasks
kosmar and others added 7 commits August 15, 2026 17:25
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>
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	faderpunk/src/apps/mod.rs
Bring Giant Steps and Axis Matrix up to the playground Motion/Feel surface:
Motion shapes harmonic rhythm and opens Free-range tritone subs, Feel adds
velocity contrast and per-step swing, and voice leading keeps chord jumps
small. Feel's swing no longer yields the whole budget when the device clock
has swing — it subtracts what the clock already spends and follows its
direction. Manuals updated to match.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@kosmar

kosmar commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

Written by an AI coding agent on @kosmar's behalf.

This PR now carries the Motion/Feel surface that lived on the playground integration branch, plus the swing-budget follow-up.

efe1b405 brings Motion (harmonic rhythm + Free-range tritone subs), Feel (velocity contrast and per-step swing), and voice-led chord movement, with manuals updated to match. Feel’s swing no longer yields the whole budget when the device clock has swing — it subtracts what the clock already spends (device_swing_permille / device_swing_reverses from #641) and follows its direction.

Dependencies pulled in the same way as the other WIP apps: #641 (shared groove helpers), #638/#646 (clock_ticker), #639 (try_send_note_on). Worth landing those first.

Also still in this PR from earlier today: CV Att ceiling 100→400 on Giant Steps, and the ii-chord sign fix.

kosmar and others added 2 commits August 15, 2026 20:22
Replace the three hard density steps (3/6/9 chords) with a seven-position
gradient. The cycle now always occupies nine slots -- ii, V, I per tonal
center -- and raising density inserts one approach chord at a time: the V of
each center, then the ii of each center. Empty slots are not silent; they
fold into the preceding chord's hold, so the cycle length stays constant and
sparse settings give the long held tonic the original changes have.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
The cheatsheet prose is assembled from manual.md, so the manual for this app
needs the gradient description too. Drop the claim that the nine-slot grid
keeps bar alignment: it keeps the cycle length constant, but nine slots only
return to a downbeat every nine bars on binary divisions and every three on
triplet ones.

Also track the Giant Steps and Axis Matrix manual.md files, which a global
gitignore rule for *.md had kept out of the repo.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
kosmar and others added 2 commits August 15, 2026 21:42
…ant Steps

Axis Matrix: the Sustain param offered Staccato, but sustain_mode was only read
in the clock-stall branch, so it behaved exactly like Clock-gated and every note
rang until the next chord change. Notes now get a note-off scheduled half a
window after their note-on -- the chord's own step for block chords, the arp
spacing for Sheets runs -- and those scheduled offs are dropped wherever the
sounding set is cleared, so a stale gate cannot cut a retrigger. Clock-gated and
Legato are unchanged.

Giant Steps: Shift + fader was dead and documented as reserved. It now latches a
five-zone speed multiplier over the configured Division, from quarter speed at
the bottom through unity at centre to quadruple speed at the top, which also
lets the nine-slot cycle be pulled onto a division where it lands on a downbeat.
The value persists per scene and drives the clock divider after a scene load.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
…and density

Both apps put the clock division on the Third layer (button held + fader) as an
absolute selector across all eleven divisions, with the Division param as the
power-on position and an untouched-sentinel in storage so the param still seeds
it. Giant Steps moves Feel to the Alt layer; Axis Matrix keeps Position and
Function on Main and Alt, so Feel moves to Shift + long press as four stops,
which makes the interval config-only.

The division table is sorted by duration instead of appending triplets, so it
reads 1/1, 1/2, 1/4, 1/4t, 1/8 and so on; the default moved to keep 1/8.

The Giant Steps button LED now encodes the sounding chord: hue sways away from
the tonal center with harmonic distance, brightness tracks the seven-step
density including its CV offset, and the trigger duck scales that brightness
rather than replacing it.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kosmar
kosmar marked this pull request as ready for review August 22, 2026 08:49
@kosmar

kosmar commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Written by an AI coding agent on @kosmar's behalf.

This combined PR is not yet on Wave-1 scope (still bundles Giant Steps + Axis Matrix + shared modules + core touches — 15 files vs main).

Clean single-app branches are ready on the fork:

App Branch Scope
Giant Steps (44) feat/giant-steps 4 files
Axis Matrix (45) feat/axis-matrix 4 files

Each has inlined coltrane_geo + shared helpers, clock drain where needed, manuals under docs/apps/.

Question for @ArthurGibert: prefer two separate PRs from those branches, or should we force-push one split onto this branch and open a second PR for the other?

All other WIP app PRs were force-pushed to the 4-file Wave-1 pattern today; see their comments for the shared checklist.

@kosmar

kosmar commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

Moving this to faderpunk-community-apps, split into one app per PR as requested:

Standalone files (geometry inlined, compiles against current main App API). Closing here.

@kosmar kosmar closed this Aug 23, 2026
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.

1 participant