feat: Loop de Cay additive overdub loop - #623
Draft
kosmar wants to merge 16 commits into
Draft
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Detect Shift+long with a timer, move mute/arm LEDs off the clock path, re-arm on unmute, and re-anchor loop origin after Start/Reset so the playhead does not stick after a clock restart. Co-authored-by: Cursor <cursoragent@cursor.com>
Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
…ranch Co-authored-by: Cursor <cursoragent@cursor.com>
Holding the button and moving the fader now slides through scale degrees toward the fader position, matching the Chord Vamp gesture, so held notes can be bent while the loop keeps running. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
Carries the UX fragment (params, gestures including the Hold+Fader glissando, prose) next to the app itself, matching how Bassment and Contura ship their manuals on their own branches. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
Mode 0 always opens a CV in jack, and resolve_pitch read that jack instead of the fader whenever it existed — so the fader branch was unreachable and Span had no effect there. An open input rests near 0 V, which pinned every note to Base Note and made the fader look like it had a tiny range. Hold+Fader glissando was dead for the same reason: its target never moved. CV pitch and the fader offset now stack. Unpatched the fader keeps the span the manual documents; with a cable it transposes, and the centre position is a 0-semitone no-op, which is also the saved default. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Author
Update: Pitch→MIDI fader + Span
CV pitch and the bipolar fader offset now stack: unpatched the fader keeps the documented span; with a cable it transposes; centre = 0 semitones (also the saved default). Test on hardware
|
The Hold+Fader glissando loop resolved a fresh target every millisecond and retuned toward it unconditionally. In Pitch→MIDI the target includes the CV input, so any movement there — a patched source, or just ADC jitter across a quantizer step on an open jack — made retune_live close and re-attack the note every 35 frames. A held button machine-gunned instead of sustaining. The gesture is Hold+Fader, so the chase now waits for the existing fader_moved_while_held flag, which already has a movement threshold. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
Playback started and ended notes on an exact `== pos` match. Since the gatekeeper publishes ticks immediately, a subscriber that briefly falls behind drops ticks instead of stalling the device clock, so `pos` can jump over the position a voice was scheduled to end on. The note then sounded until its slot was stolen by a later note — "sticks until one after the next NoteOff". Both the start and the end test now ask whether the loop advanced across the target since the previous tick, wrap included. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Author
|
Pushed two fixes found while testing on the playground build:
Written and pushed by an AI coding agent on behalf of @kosmar. Verified to build; hardware test still pending. |
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.
Clock::get_ticker is gone and ClockEvent::Tick carries the tick number. The app polls the counter from several places outside the clock arm, so it uses App::clock_ticker (ATOVproject#646) and takes the tick from the payload where it is already in scope. Authored by an AI coding agent on behalf of kosmar. Co-authored-by: Cursor <cursoragent@cursor.com>
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>
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
Test plan
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:App::clock_ticker, which replaces theClock::get_tickerthis branch was written againstParamStore::update, so an app can write its own params back to the hostThis branch is still based on an older
mainthat still had the removed clockhelper, which is why it builds on its own but not after a rebase.
On top of the PRs above there is an app-side change:
ClockEvent::TickbecameTick(u64)in #579, so the match arm here has to be updated.Building any of this on a current Rust nightly also needs the toolchain fix in
#632.