Skip to content

feat: add Arp de Lévy app - #607

Draft
kosmar wants to merge 26 commits into
ATOVproject:mainfrom
kosmar:feat/arp-de-levy
Draft

feat: add Arp de Lévy app#607
kosmar wants to merge 26 commits into
ATOVproject:mainfrom
kosmar:feat/arp-de-levy

Conversation

@kosmar

@kosmar kosmar commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds Arp de Lévy (app ID 34): one-channel generative arpeggiator with Lévy-flight pool mutation, texture macro, octave span, and classic arp playback modes (Up / Down / UpDown / DownUp / Random / Converge).
  • Configurator params: MIDI Channel, Base Note, Color, MIDI Out, V/Oct, Bypass quantizer.
  • Manual entry with gesture/LED/mode tables; includes markdown table rendering.
  • Lists Arp de Lévy under long-press mute in the Apps muting overview.

IDs 28–31 reserved for Heat Pump (#603), Grooves (#604), Golden Gate (#605), Super LFO (#606). Independent from main.

Test plan

  • Flash firmware; load Arp de Lévy on a channel
  • Confirm CV pitch + MIDI notes fire together on hits
  • Fader: mutation (bottom freezes pool); Shift+fader: texture; Button+fader: 1–4 octaves
  • Short press rerolls pool; long press mutes
  • Shift+short reverses; Shift+long cycles arp modes (Button LED color)
  • V/Oct Standard vs Buchla; Bypass quantizer changes pitch behaviour
  • Configurator Manual → Arp de Lévy tables render correctly

Prerequisites

The platform pieces this app needs are under review as their own PRs, so that
each app PR stays small enough to review on its own.

Required — these APIs do not exist on current main:

This branch is still based on an older main that still had the removed clock
helper, which is why it builds on its own but not after a rebase.

One more dependency is deliberately not proposed yet:
App::wait_while_perf_muted, which this branch calls. That mechanism does not
exist on main at all, and on the integration branch it is used by seven stock
apps — so it needs its own PR and its own review rather than riding along here.
The call will be dropped from this branch until that PR exists.

Building any of this on a current Rust nightly also needs the toolchain fix in
#632.

kosmar added 2 commits July 23, 2026 00:14
Lévy-flight generative arpeggiator (app ID 32) with classic arp modes,
V/Oct + bypass quantizer, and configurator manual with gesture tables.
@kosmar
kosmar marked this pull request as draft July 24, 2026 14:17
kosmar and others added 5 commits July 25, 2026 20:13
Short press (and CV Dest Reroll) picks a new expression amount that scales per-note velocity and gate-length randomness.

Co-authored-by: Cursor <cursoragent@cursor.com>
Mirror Chord Vamp: schedule hits on the clock path, await MIDI/quantizer
only in a separate voice loop so USB MIDI cannot stall clock ticks.

Co-authored-by: Cursor <cursoragent@cursor.com>
Tighter local steps, wilder leaps (up to 4 octaves), and a lean curve so
Third-layer alpha extremes separate more clearly.

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

kosmar commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

Pushed latest: CV Out Pitch/Gate/Velocity + LED feedback polish.

kosmar and others added 19 commits July 31, 2026 17:59
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
The branch still used the ID it was first drafted with. ID 32 now belongs to
another app in docs/wip-app-ids.md, and 28 is reserved for Sift, so two of these
app branches would have collided on merge.

Authored by an AI coding agent on behalf of kosmar.
…ream

App::wait_while_perf_muted does not exist on main. The mechanism behind it
gates the shared MIDI path and is used by several stock apps on the
integration branch, so it needs its own PR and its own review rather than
arriving as a side effect of an app. Without a host perf mute on main there is
nothing for this call to wait on, so removing it changes no behaviour here.

Authored by an AI coding agent on behalf of kosmar.
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 adds one shared 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.

Resolving copies the whole GlobalConfig, so the module documents that callers
must cache per bar or phrase rather than per note.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
…g it

The note pool holds absolute MIDI notes and is persisted, so following a
transpose has to move it. Shifting by the interval keeps the melodic shape the
pool has evolved into; rerolling would have thrown it away. Resolved once per
phrase, and the resolved root travels to the voice task through a global.

Also pins the historical-layout check in from_values, which tested values.len()
>= PARAMS and would have misread the old layout as soon as PARAMS grew.

Authored by an AI coding agent on behalf of kosmar.

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>
The integration branch exposes the same counter twice, as Clock::get_ticker and
as App::clock_ticker; only the latter is on its way upstream. Both hand out the
same fn() -> u64 reading TICK_COUNTER, so this is a rename at the call site.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
Review feedback on ATOVproject#639: a dropped NoteOff hangs the note with no later
message to correct it, and APP_MIDI_CHANNEL is shared by all 16
channels, so a busy neighbour can cause the drop. Every NoteOff here
already runs in the async voice task, where awaiting queue space costs
at most a late NoteOff in this app's own loop.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
Upstream PR ATOVproject#601 asserts at compile time that CONFIG strings are pure
ASCII, because postcard-bindgen JavaScript codec cannot round-trip anything
else. Doc and inline comments keep their typography.

Authored by an AI coding agent on behalf of kosmar.
Same mutate+save API as ATOVproject#640 so WIP apps can call params.update now.
Host AppState push stays out until the real writeback lands.

Authored by an AI coding agent on behalf of kosmar.

Co-authored-by: Cursor <cursoragent@cursor.com>
ParamStore::update polyfill (mutate+FRAM, no host push).

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>
@kosmar kosmar mentioned this pull request Aug 15, 2026
7 tasks
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