Check and Windows preview / check (patina) (push) Successful in 2m20s
Check and Windows preview / check (rivet) (push) Successful in 1m38s
Check and Windows preview / previews (push) Successful in 1m6s
Check and Windows preview / windows (push) Successful in 1m50s
Independent plugin release / publish (push) Successful in 8s
Independent plugin release / plan (push) Successful in 7s
Independent plugin release / build (push) Successful in 2m21s
150 lines
8.6 KiB
Markdown
150 lines
8.6 KiB
Markdown
# Rivet
|
|
|
|
Rivet joins short motifs into connected musical phrases, like a fastener joining
|
|
individual pieces. Formerly **Motif Storyboard**; current version **0.3.0**.
|
|
|
|
|
|
A Rust composition companion for an experienced producer developing their own
|
|
melodic ideas. Version 0.3 explores rhythm, space, contour, harmonic arrivals, and
|
|
returns, with reusable gestures, branching ideas, and two sound roles.
|
|
|
|

|
|
|
|
## Write with it
|
|
|
|
1. Import a monophonic MIDI motif of up to two bars in 4/4, or load the demo.
|
|
2. Choose a task: **Develop the motif**, **Write an answer**, **Make room**, or
|
|
**Find a return**. Choose a settled or open ending and a four/eight-bar length.
|
|
3. Decide what defines the idea. **Keep groove** fixes note positions and lengths;
|
|
**Keep contour** protects the direction of movement, allowing flattened steps
|
|
at register limits. Click source notes to lock the whole note, pitch only, or
|
|
rhythm only. Clicking uses the currently selected lock mode. Locks
|
|
and identity constraints take precedence over the proposed transformations.
|
|
4. Optionally open **Harmony** and import a chord/bass MIDI track (up to eight
|
|
bars), or create and edit a four-chord progression. Imported overlapping notes
|
|
become pitch-class regions with the actual lowest held pitch; the tool does
|
|
not guess chord roots or chord names. Empty regions remain gaps, and short
|
|
contexts repeat. Harmony guides strong notes and arrivals; the preview plays
|
|
the melody only. Supplied chord tones may extend beyond the selected scale.
|
|
5. Explore alternatives. A deterministic pool of eight transformation families
|
|
supplies up to three distinct proposals, selected for the task and differences
|
|
in rhythm, density, duration, and pitch. Fully constrained motifs may yield
|
|
fewer than three; cosmetic velocity differences do not count as new ideas.
|
|
6. Select a proposal and pin its two-bar sections. Select another to fill the
|
|
remaining sections, or explore another take. Preview and export the combined
|
|
phrase from the fixed bottom toolbar. Keep a combined result to retain it
|
|
independently of new proposals; undo/redo switches the kept result and its
|
|
previous value. Individual proposals and kept results can also be exported.
|
|
|
|
The opening quotation stays intact. Later sections use displaced entries,
|
|
repeated pickups, fragments, subtraction, short/long answers, changed endings,
|
|
register contrast, and returns. These are compositional suggestions, not promises
|
|
of an emotion or of commercial originality. Different seeds choose structured
|
|
alternatives; they do not independently randomize every pitch.
|
|
|
|
Pins survive task/seed/harmony changes and regeneration. Changing the motif,
|
|
its locks, or the phrase length clears pins. Pinned sections override newly
|
|
proposed material. Unsafe boundaries in legacy candidates are rejected instead
|
|
of truncating sustained notes. Changing generation inputs clears current
|
|
proposals while retaining kept work.
|
|
|
|
## Audition and commit
|
|
|
|
**Internal voice** provides two simple reference voices. **MIDI output** sends
|
|
notes and optional CC curves on the configured channels to routed external synths
|
|
and mutes the internal voice. Solo defaults to channel 1.
|
|
Looping is optional and enabled for new sessions. When audition is already
|
|
running, another selection waits until the next two-bar boundary or current
|
|
phrase end. Note-offs precede repeated same-pitch note-ons; stop, replacement,
|
|
loop boundaries, reset, restoration, and mode changes release active output notes
|
|
on the processing thread. Queued auditions are canceled by Stop.
|
|
|
|
**Host tempo** follows tempo, with the local BPM as fallback. It does not align
|
|
the initial audition to the DAW's song position: start it at the desired point
|
|
in the project loop. Host start never initiates audition; host stop silences it.
|
|
Exported MIDI is in musical ticks and carries the local BPM as its tempo event.
|
|
Native OS MIDI drag-out is not implemented; export files to commit a phrase.
|
|
See [FL Studio setup and acceptance checks](fl-studio.md).
|
|
|
|
Open **Gestures, moves, and branches** to save a source or selected two-bar
|
|
section with its performance choices. Export/import a gesture library between
|
|
projects. Save a branch before experimenting; restore any branch and make a new
|
|
child with subtraction, a delayed entry, longer gates, or transposition.
|
|
Moves respect pins and locks, reject unsafe overlaps, and report when constraints
|
|
leave nothing to change. Libraries and histories each hold up to 16 entries;
|
|
remove a gesture or a leaf branch to make room.
|
|
|
|
Open **Sound roles and expressive gestures** to pass existing notes between two
|
|
patches: alternate events, alternate question/answer bars, or divide strong beats
|
|
from replies. These modes distribute a monophonic phrase rather than generate
|
|
a second independent melody. Assign separate MIDI channels and explicitly map
|
|
each optional CC lane to a synth macro. Curves are normalized over the whole
|
|
phrase, with editable points and rise/fall/arch/pulse starting shapes.
|
|
Names describe your intent; the plugin does not infer feelings.
|
|
|
|
Patch profiles set register offset, gate, velocity, and estimated attack/release.
|
|
MIDI audition uses a short warmup for early triggers. Re-audition after a tempo
|
|
change to recompile millisecond offsets. Compensation estimates trigger timing;
|
|
it does not measure patch latency or model its sound. Default export retains
|
|
musical positions; compensated export adds one bar of lead-in. Role tracks carry
|
|
names, channels, and CC curves. Stop resets mapped controllers to their chosen
|
|
stop values. Internal audition does not reproduce mapped timbre.
|
|
See [the theory and producer workflow](theory/README.md).
|
|
|
|
Sessions save inside the host project and can be saved/loaded as JSON. Version-1/2
|
|
sessions and the original host field identifier remain supported; older sessions
|
|
retain one-shot audition. New sessions persist harmony, task, lock modes on notes,
|
|
pins, proposals, kept history, gestures, branches, patch profiles, CC curves, and
|
|
audition settings. JSON state is bounded at 16 MiB; gesture libraries at 2 MiB. File export/save refuses to
|
|
silently overwrite an existing file.
|
|
|
|
## Build and offline preview
|
|
|
|
Run from the repository root:
|
|
|
|
```sh
|
|
cargo run -p rivet-preview -- demo /tmp/rivet-demo
|
|
cargo run -p rivet-preview -- develop motif.mid 0 /tmp/phrase
|
|
cargo run -p rivet-preview -- develop motif.mid 0 /tmp/with-chords chords.mid 0
|
|
cargo run -p rivet-preview -- session saved-session.json /tmp/rendered-session
|
|
python scripts/build-plugin.py --plugin rivet --target x86_64-pc-windows-gnu
|
|
```
|
|
|
|
The preview writes source/candidate MIDI, a session JSON, and WAV using the same
|
|
engine as the plugin. Track indices exclude conductor-only tracks and start at
|
|
zero. Optional harmony arguments accept a separate polyphonic MIDI file.
|
|
See [development](../development.md) for checks, dependencies, architecture, and
|
|
[releases](../releases.md) for independent release tags.
|
|
|
|
## Design and references
|
|
|
|
[Theory findings and implemented design](theory/README.md) connect the research
|
|
to practical controls. [Implementation plan](implementation.md) records the musical and technical
|
|
choices. [Devath reference measurements](research/devath.md) document
|
|
analysis of the seven supplied FLACs, with reproducible plots and explicit limits.
|
|
Original reference audio is excluded from source distribution.
|
|
|
|
- `rivet-core`: musical model, harmonic context, structured proposals, section
|
|
composition, session migration, and bounded playback clips.
|
|
- `rivet-midi`: bounded SMF 0/1 import/export. Rejects SMPTE, unsupported meters,
|
|
incomplete notes, and timing not exactly representable at 960 PPQ. Reports
|
|
ignored controllers/pitch bends. Polyphonic tracks work as harmonic context;
|
|
motif import requires monophony.
|
|
- `rivet-app`: worker jobs, revision handling, bounded queues, sample-accurate
|
|
preview/MIDI scheduling, and Windows/Zenity dialogs.
|
|
- `rivet`: CLAP wrapper, host persistence, editor, and standalone.
|
|
|
|
Tests cover musical constraints/diversity, harmony, legacy state, section seams,
|
|
MIDI round trips, sample timing, looping, queued switches, note releases, and
|
|
zero allocation/deallocation during rendering and queued clip replacement. The
|
|
CLAP ABI test verifies discovery, note-output port exposure, state restoration,
|
|
and silent startup at several sample rates and buffer sizes.
|
|
|
|
## Existing projects
|
|
|
|
The name, Cargo packages, source paths, and output filename have changed.
|
|
The CLAP ID `io.storyboard.motif`, `story-session-v1` host field, and session
|
|
JSON format are preserved. Rescan FL Studio after replacing the old plugin file
|
|
with `Rivet.clap`; remove the old copy from scanned folders to avoid duplicate
|
|
instances with the same ID. Project recall still needs a check in the target host.
|