Skip to content

Commit 34a2485

Browse files
committed
enhancements
1 parent 9cf06ac commit 34a2485

40 files changed

Lines changed: 1016 additions & 1338 deletions

‎TODO.md‎

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ Open items only. Finished work is recorded in the plugin docs and `MISTAKES.md`.
1515
either. Low urgency, since `include/downspout/test_assert.h` already makes a lost
1616
`-UNDEBUG` a compile error. Touches root glue and ~36 plugin CMake files, so it needs
1717
approval and a full test run.
18-
* **Add `-Wall -Wextra` to `downspout-project-options`** and clear the remaining noise
19-
plugin by plugin so it cannot regress. Needs approval and a full 62-suite run.
2018

2119
## Session state (found 2026-10-06)
2220

@@ -54,12 +52,9 @@ Standalone `g++ -std=c++20 -Wall -Wextra -fsyntax-only` over `plugins/*/src/*.cp
5452
`-Iplugins/generative-common/include` or conductor, drift, ghost, guardian, harmonic-atlas
5553
and others will not compile). No `-Wswitch` warnings remain. What was left on purpose:
5654

57-
* `cadence` (2) and `drumgen` (1): `-Wclass-memaccess` on `memset` of structs with default
58-
member initialisers. Safe in practice. One wrinkle to decide: `cadence_clear_progression`
59-
zeroes `ChordSlot`, whose `velocity` defaults to 96, so a cleared slot has velocity 0
60-
rather than the constructed default.
61-
* `mnemosyne`, `mosaic`: `-Wmisleading-indentation`. The cores are dense one-line
62-
statements; reformatting is churn, not a fix.
55+
* `cadence` and `drumgen` `memset` calls are `void*`-cast, so they no longer warn. (Re-swept
56+
2026-10-10: zero warnings across `plugins/*/src/*.cpp`.) `cadence_clear_progression` now
57+
resets slots to `ChordSlot{}` (velocity 96) instead of zeroing; cadence tests pass.
6358
* `campione` loader: the `smpl` loop end is inclusive in the WAV spec, but the engine wraps at
6459
`position >= loopEnd`, so the last loop sample is skipped (one frame). Changing it means
6560
adjusting load, save and the engine together; decide whether it is worth it. (The ignored
@@ -85,6 +80,12 @@ and others will not compile). No `-Wswitch` warnings remain. What was left on pu
8580
cutoff position linearly (t = 0.5 is a notch at the cutoff), and it only reshapes the
8681
forward filter, not the Scream feedback high-pass.
8782

83+
* **Damiano Linked/Split stereo** is in and tested (per-channel Mode, Drive, Tone, Folds; CC Drive and
84+
CC Shape per channel on a shared CC channel; see `plugins/damiano/docs/porting-notes.md`). Not yet
85+
auditioned in a host: try Split with Soft left and Fuzz right, and two Drift lanes on CC Drive / CC
86+
Drive R. Verify an old project (pre-split state) loads Linked. Open: "shape" is the stepped waveshaper
87+
mode; a continuous shape (asymmetry/bias) would be new DSP. Tone and Folds are not CC-controlled.
88+
8889
* `voxmod`: host validation in REAPER still pending.
8990
* `keyframe`: the leash diagram is static at unity rates because drift is genuinely ~0 there;
9091
a splice halo was added so it reads live during crossfades. If it still reads dead at
@@ -99,8 +100,8 @@ Remaining:
99100
* **Verify in a host (REAPER):** load, play notes, filter an audio track, save/reopen state.
100101
Nothing has been listened to. Also confirm the host accepts an instrument with audio inputs.
101102
* Listen to drum levels (normalised per hit, consistent at ~0.15); check voice-stealing clicks.
102-
* GM Program mode warms only the last requested voice; other voices build on first note
103-
(~1.9 ms). Warm several if this is audible.
103+
* GM Program mode now queues a warm-up per Program Change (last 8 voices); host-check that
104+
switching programs on several channels no longer glitches on first notes. Offline-tested only.
104105
* `scripts/capture-plugin-screenshots.sh` captures the real desktop if `DISPLAY` is set
105106
(see `MISTAKES.md`). Make it always use Xvfb. Shared script, needs approval.
106107
* Catalogue screenshot shows Synth mode (filter dimmed); consider a Synth + Filter capture.
@@ -155,11 +156,11 @@ Remaining:
155156
shared (`include/downspout/cellular_automaton.hpp`, tested in `tests/cellular_automaton_tests.cpp`) and used
156157
by `polymeter`, `drumgen` and `xoxolo`. Open: xoxolo's grid shows the programmed pattern, not the
157158
evolved row now playing.
158-
* **Magneto look and feel:** Retune, Sprout and Markov use a plugin-local `MagnetoKit.hpp` (identical
159-
copies in `plugins/retune/src/dpf/`, `plugins/sprout/src/dpf/` and `plugins/markov/src/dpf/`) built on
160-
`downspout/look_and_feel.hpp`, matching Pratt and Magneto. Moving it to a shared header
161-
would remove the duplicate but is shared code and needs approval. Older generator
162-
plugins still use `GenerativePanelUI` (mosaic, polymeter, etc.); restyle if wanted.
159+
* **Magneto look and feel:** the kit is now shared, `include/downspout/dpf/MagnetoKit.hpp`, used by
160+
Retune, Sprout, Markov and Damiano (new hooks: overridable `sendValue()` for plugins that carry
161+
values as state, `setValue()` and `setDim()`). Older generator plugins still use
162+
`GenerativePanelUI` (mosaic, polymeter, etc.); restyle if wanted. Retune, Sprout and Markov were
163+
rebuilt against the shared header but not re-screenshotted; confirm they look unchanged.
163164
* **Gravity** is in `harmonic-atlas`. `cadence` (learned harmony) has not had it; its progression
164165
model is different, so decide whether a gravity bias on the learned transitions makes sense.
165166
* **Atlas voice-leading** is local to `harmonic-atlas`. Listen to it; the chords sit low (around
@@ -172,8 +173,10 @@ Remaining:
172173
not pass incoming MIDI through; the editor does not move while a CC drives a control.
173174
* **Conductor awareness** was added to `lifeform`, `luma`, `polymeter` and `xoxolo` (off by default; not yet auditioned
174175
in a host). `counterpointer` and `cadence` followed (the CC mapping is a tested pure function,
175-
`applyConductorCc`, in their core-types headers; CC 24 relearns). Still without it among the generators:
176-
`arpgen`, `mnemosyne` (only Novelty and a seed re-roll would fit, and its core takes parameters const, so it needs wrapper-level handling), `m-mix`, `sidecar` (its wrapper is tangled up with the server path),
176+
`applyConductorCc`, in their core-types headers; CC 24 relearns). `arpgen` followed (CC 21 Density -> Octaves,
177+
CC 22 Energy -> Rate; `applyConductorCc` in `arpgen_core.hpp`, tested; screenshot recaptured; not yet auditioned
178+
in a host). `m-mix` followed (CC 21 Density -> Open Bias, CC 22 Energy -> Maintain inverted; tested; UI slider added and
179+
the window made taller because its sixth slider row had been hidden under the toggles). Still without it among the generators: `mnemosyne` (only Novelty and a seed re-roll would fit, and its core takes parameters const, so it needs wrapper-level handling), `sidecar` (its wrapper is tangled up with the server path),
177180
`tuney-vst`. Worth adding where a density or energy knob exists.
178181
* Later candidate: chord-graph walker. A shared voice-leading helper in
179182
generative-common is only worth it if a second plugin needs it (shared code, needs approval).

‎docs/midi-mapping.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,34 @@ Cadence gains one parameter, **Conductor Ch** (`conductor_ch`, 0-16, default 0 =
211211

212212
CC 20 (Scene) is not mapped.
213213

214+
## Arpgen mapping
215+
216+
Arpgen gains one parameter, **Conductor Ch** (`conductor_ch`, 0-16, default 0 = off), appended after
217+
its status outputs. The CCs set the controls directly, as if you had moved them, so a later change on
218+
the panel or from host automation takes over until the next CC arrives.
219+
220+
| CC | Conductor name | Arpgen control | Notes |
221+
|----|---------------|----------------|-------|
222+
| 21 | Density | `octaves` | 1-4, four equal steps over 0-127 |
223+
| 22 | Energy | `rate` | 1/4, 1/8, 1/8T, 1/16, 1/16T, 1/32: six equal steps, slow to fast |
224+
225+
CC 20 (Scene), 23 (Mutation) and 24 (Reset) are not mapped. With **Pass Input** on, the Conductor's CCs
226+
are passed through with the rest of the input.
227+
228+
## M-Mix mapping
229+
230+
M-Mix gains one parameter, **Conductor Ch** (`conductor_ch`, 0-16, default 0 = off), appended after
231+
Mute. As with Arpgen the CCs move the controls directly, so a later panel or automation change takes
232+
over until the next CC.
233+
234+
| CC | Conductor name | M-Mix control | Notes |
235+
|----|---------------|---------------|-------|
236+
| 21 | Density | `bias` (Open Bias) | 0-100%: the chance a gate change opens, so higher density passes more notes |
237+
| 22 | Energy | `maintain`, inverted | 100% to 0%: higher energy holds the gate state less often, so it changes more |
238+
239+
CC 20 (Scene), 23 (Mutation) and 24 (Reset) are not mapped. Non-note MIDI already passes through
240+
M-Mix, so the Conductor's CCs continue downstream.
241+
214242
## Markov mapping
215243

216244
Markov has one parameter for Conductor reception, **Conductor ch** (`conductor_ch`, 0-16, default 0 = off).

‎docs/pages/_products/arpgen.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ Scale mode uses held notes as register anchors for in-key runs, triads, or
2121
sevenths. Both modes support one to four octaves, velocity following, gate
2222
control, straight and triplet rates, and endpoint-safe alternating patterns.
2323

24+
### Conductor
25+
26+
Set **Conductor Ch** to the channel Conductor sends on (it defaults to 16; 0 is off) and Conductor shapes the arpeggio over the song: CC 21 (Density) sets Octaves from 1 to 4 and CC 22 (Energy) steps Rate from 1/4 up to 1/32. The CCs move the controls as if you had, so you can still override them by hand.
27+
2428
### Status
2529

2630
The portable core, deterministic tests, VST3 wrapper, and custom UI are in

‎docs/pages/_products/damiano.md‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ kind: Audio effect
66
category: processor
77
role: Stereo distortion
88
screenshot: /assets/plugins/damiano.png
9-
summary: Six-mode stereo distortion with drive, tone shelf, wet/dry mix, output gain, and real-time MIDI CC override of drive from Drift or any CC source.
9+
summary: Six-mode stereo distortion with drive, tone shelf, wet/dry mix and output gain. Linked or Split left/right processing for a binaural effect, with Drift CC control of each channel's drive and shape.
1010
---
1111

1212
## Opinion
@@ -37,8 +37,12 @@ Damiano is a stereo distortion with six selectable waveshaping modes. Each mode
3737
| Folds | 1–8 | 2 | Cascade depth in Wavefold mode; greyed out in other modes |
3838
| Mix | 0–100 % | 100 % | Wet/dry blend |
3939
| Output Gain | −24 to +24 dB | 0 dB | Post-distortion level trim |
40-
| CC Number | off / 1–127 | off | Which MIDI CC number overrides Drive in real time |
41-
| CC Channel | 1–16 | 1 | MIDI channel to listen on |
40+
| CC Drive | off / 1–127 | off | MIDI CC number that overrides Drive in real time (left, or both when Linked) |
41+
| CC Shape | off / 1–127 | off | MIDI CC number that selects the Mode in six steps (left, or both when Linked) |
42+
| CC Channel | 1–16 | 1 | MIDI channel to listen on (shared) |
43+
| Stereo | Linked / Split | Linked | Split enables the right-channel settings below |
44+
| Right Mode, Drive, Tone, Folds | as left | Tanh, 2, 50 %, 2 | Used only in Split |
45+
| CC Drive R, CC Shape R | off / 1–127 | off | Right-channel CC numbers (Split only) |
4246

4347
### Tone shelf
4448

@@ -50,10 +54,19 @@ When CC Number is set to anything other than off, incoming MIDI CC messages on t
5054

5155
This is designed to work directly with the Drift MIDI modulator. Route Drift's MIDI output to Damiano's MIDI input and assign the same CC number in both.
5256

57+
### Stereo: Linked and Split
58+
59+
The **Stereo** switch chooses how the two channels are processed.
60+
61+
- **Linked** (default): the right channel mirrors the left settings. This is the behaviour of earlier versions, and old sessions load as Linked.
62+
- **Split**: the right channel has its own Mode, Drive, Tone and Folds, so each ear can be distorted differently. Fed the same signal on both sides, a Split setting such as Soft on the left and Fuzz on the right widens and detunes the image. Mix, Output Gain and the CC channel stay shared.
63+
64+
Each channel has its own **CC Drive** and **CC Shape** numbers (off / 1-127), all read on the shared CC Channel. CC Shape selects the waveshaper mode: the 0-127 range is divided into six equal steps (Soft, Tanh, Fuzz, Overdrive, Tube, Wavefold). In Linked mode the left CC numbers drive both channels and the right ones are ignored. Point two Drift lanes at the two CC Drive numbers to modulate the channels independently; a slow lane on one and a fast lane on the other gives a moving binaural beat.
65+
5366
### Wavefold notes
5467

5568
The triangle wavefolder applies the fold transfer function in series, re-driving the signal at each stage. High Drive combined with many Folds produces dense harmonic content that can sound noise-like at extreme settings — this is the intended character of the mode rather than an artefact. For cleaner folding tones, keep Drive below 5 and Folds at 2–4.
5669

5770
### Status
5871

59-
All six distortion modes and the MIDI CC drive link are functional and tested. A fresh screenshot is needed.
72+
All six distortion modes, the MIDI CC drive link and the Linked/Split stereo processing are functional and covered by core tests (channel independence, CC mapping, state round-trip, pre-split state loading). The screenshot shows Split mode. Not yet auditioned in a host.

‎docs/pages/_products/m-mix.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ M-Mix processes incoming MIDI notes rather than audio. Notes pass only when the
1919
current probability and Euclidean gates are open, making it useful for rhythmic
2020
note thinning, comping variation, and transport-locked MIDI movement.
2121

22+
### Conductor
23+
24+
Set **Conductor Ch** to the channel Conductor sends on (it defaults to 16; 0 is off). CC 21 (Density) sets Open Bias, so denser sections let more notes through, and CC 22 (Energy) sets Maintain inverted, so more energetic sections change the gate more often. The CCs move the sliders as if you had, so you can still override them by hand.
25+
2226
### Status
2327

2428
Functional but awaiting review in practical application.
766 Bytes
Loading
14.5 KB
Loading
3.13 KB
Loading

‎docs/pages/plugins-summary.md‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ prose and example chains see `docs/summary.md`; for scale tables see `docs/scale
3535
by default so Drift needs no configuration. Conductor emits CC 20-24 on channel 16
3636
(Scene, Density, Energy, Mutation, Reset); bassgen, drumgen, ground, melgen, worms, bubbles,
3737
floozy, harmonic-atlas, sprout, lifeform, luma, polymeter, xoxolo, markov, counterpointer
38-
and cadence listen through a **Conductor Ch**
38+
cadence, arpgen and m-mix listen through a **Conductor Ch**
3939
parameter (0 = off). Mixgen drives T-Mix with CC
4040
20-27 (strips 1-8), Loopdelay with CC 30/31, Lightverb with CC 32/33; CC 19 claims or
4141
releases the producer bus. Details: `docs/midi-mapping.md`,
@@ -285,7 +285,8 @@ alters the host graph. Targets: bassgen, drumgen, ground, worms, bubbles.
285285
Transport-synced arpeggiator. **Chord** mode captures incoming chord slices; **Scale**
286286
mode derives scale runs, triads or sevenths from held register anchors. Rates quarter
287287
through thirty-second, straight and triplet; one to four octaves; up, down and alternating
288-
orders. Latch and capture state are internal. Requires transport.
288+
orders. Latch and capture state are internal. Requires transport. **Conductor Ch** (0 = off):
289+
CC 21 Density sets Octaves (1-4), CC 22 Energy sets Rate (1/4 up to 1/32).
289290

290291
### cadence
291292
Transport-aware harmoniser and comping generator that learns harmony from incoming MIDI
@@ -306,7 +307,8 @@ Persistent motif state; requires transport.
306307

307308
### m-mix
308309
Transport-aware MIDI gate combining probabilistic P-Mix-style transitions with E-Mix-style
309-
Euclidean blocks: removes or passes notes before they reach an instrument.
310+
Euclidean blocks: removes or passes notes before they reach an instrument. **Conductor Ch**
311+
(0 = off): CC 21 Density sets Open Bias, CC 22 Energy sets Maintain inverted (busier gating).
310312

311313
### retune
312314
MIDI effect that retunes a note stream to a Scala `.scl` scale. For each held note it
@@ -496,8 +498,11 @@ selectable channel; CC 0 disables) so Drift drives it directly.
496498
### damiano
497499
Six-mode stereo distortion (Soft, Tanh, Fuzz, Overdrive, Tube, Wavefold) with Drive 1-10,
498500
Tone (one-pole high shelf before the shaper, about 3 kHz, 50% = flat), Folds 1-8
499-
(Wavefold only), Mix and Output Gain (+-24 dB). One selectable CC number overrides Drive
500-
in real time.
501+
(Wavefold only), Mix and Output Gain (+-24 dB). **Stereo Linked/Split** (default Linked,
502+
identical to before): Split gives the right channel its own Mode, Drive, Tone and Folds
503+
for a binaural effect. Selectable CC numbers (all on one CC channel, 0 = off): CC Drive and
504+
CC Shape (waveshaper mode in six steps) for the left or both channels, and CC Drive R and CC Shape R
505+
for the right channel (Split only), so two Drift lanes can modulate the channels independently.
501506

502507
### skream
503508
Scream filter: input through an ADAA2 anti-aliased tanh saturator and an SVF low-pass,
Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33
// Magneto-style panel toolkit for a NanoVG DPF UI: flat surface panels with
44
// accent-coloured headers, horizontal bar sliders, stepper and segmented
55
// controls, and a dark/light theme toggle, all drawn from downspout/look_and_feel.hpp.
6-
// Plugin-local on purpose (shared code needs approval); retune, sprout and markov keep
7-
// identical copies of this file.
6+
// Shared by retune, sprout, markov and damiano. This header depends on DPF, which is why
7+
// it lives under downspout/dpf/ rather than beside the portable headers.
8+
//
9+
// A plugin derives from MagnetoUI, calls beginFrame()/drawHeader()/drawPanel() and the
10+
// draw* controls from onNanoDisplay(), and handles buttons in onAction(). By default a
11+
// control change goes to the host with setParameterValue(); override sendValue() when a
12+
// plugin carries its values some other way (damiano sends state keys).
813

914
#include "DistrhoUI.hpp"
1015

@@ -77,6 +82,9 @@ class MagnetoUI : public UI {
7782
// A button, stepper half or segment was pressed. `id` is the caller's own number.
7883
virtual void onAction(int id) = 0;
7984

85+
// Delivers a value the user just set. Default: a host parameter change.
86+
virtual void sendValue(const std::uint32_t parameter, const float v) { setParameterValue(parameter, v); }
87+
8088
bool onMouse(const MouseEvent& ev) override
8189
{
8290
if (ev.button != 1)
@@ -141,10 +149,23 @@ class MagnetoUI : public UI {
141149
if (r.integer)
142150
v = std::round(v);
143151
values_[parameter] = v;
144-
setParameterValue(parameter, v);
152+
sendValue(parameter, v);
145153
repaint();
146154
}
147155

156+
// Updates the displayed value without sending it anywhere (for state or host echoes).
157+
void setValue(const std::uint32_t parameter, const float v)
158+
{
159+
if (parameter < count_) {
160+
values_[parameter] = v;
161+
repaint();
162+
}
163+
}
164+
165+
// Fades everything drawn until the next call, to show a control or panel is inactive.
166+
// Controls drawn while dimmed still respond to the mouse.
167+
void setDim(const bool dim) { globalAlpha(dim ? 0.38f : 1.0f); }
168+
148169
// ── Frame ───────────────────────────────────────────────────────────────
149170

150171
void beginFrame()

0 commit comments

Comments
 (0)