Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,19 @@ the version and stamps it with the date.
`c64cast[all]` rather than one extra at a time. The chapters have always named
an extra where a feature needs one; nothing collected them. The glossary moves
to Appendix J.
- **The books keep the promise their notation section makes.** A setting that
can move while a show is running now says so where it is defined: Appendices A
and B mark a field *live-tunable* and name the target a knob reaches it by
(`[color].dither` is `mode.dither_method`, which is exactly the pairing a
reader could not guess), and mark it *menu-live* when the on-C64 menu carries
it as a knob. Appendix E writes each generator's and effect's parameters the
way a `cc_map` has to spell them — `source.speed`, not `speed` — so a line can
be copied straight into a mapping.
- **The performance card's live-target list says who declares each target.** A
knob mapped to `source.ring_freq` does nothing unless `moire2` is the
generator on screen, and the column that says so was the one the card dropped
for space. It is back, compressed to fit: the sole owner where there is one,
otherwise a count — `14 generators`. Still two pages.

### Fixed

Expand Down
3 changes: 3 additions & 0 deletions docs/card/01-controls.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ over a fixed set of values it selects across the set, and a pad steps through
it. A target the running scene does not have is a silent no-op, so a whole knob
bank can stay mapped across a mixed playlist.

*Declared by*, overleaf, is who has a target — a name when only one does, else
a count. `source.ring_freq` says `moire2`: dead until `moire2` is on screen.

| Holder | Reaches |
|---|---|
| `source` | The generative scene's generator |
Expand Down
68 changes: 34 additions & 34 deletions docs/card/02-live-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,46 @@ generated: true

## Color pipeline

| Target | Range |
|---|---|
| `mode.auto_fit_strength` | 0 – 1 |
| `mode.color_match` | 2 values |
| `mode.dither_strength` | 0 – 2 |
| `mode.dither_method` | 5 values |
| `mode.palette_mode` | 4 values |
| `mode.motion_smoothing` | 0 – 1 |
| `mode.cell_strategy` | 4 values |
| Target | Range | Declared by |
|---|---|---|
| `mode.auto_fit_strength` | 0 – 1 | 3 modes |
| `mode.color_match` | 2 values | 4 modes |
| `mode.dither_strength` | 0 – 2 | 3 modes |
| `mode.dither_method` | 5 values | 3 modes |
| `mode.palette_mode` | 4 values | 2 modes |
| `mode.motion_smoothing` | 0 – 1 | `mhires` |
| `mode.cell_strategy` | 4 values | `mhires` |

## Effect

| Target | Range |
|---|---|
| `effect.decay` | 0 – 0.96 |
| `effect.intensity` | 0 – 2.5 |
| `effect.duty` | 0.05 – 1 |
| `effect.rate` | 1 – 16 |
| `effect.mix` | 0 – 1 |
| `effect.axis` | 3 values |
| `effect.levels` | 2 – 32 |
| Target | Range | Declared by |
|---|---|---|
| `effect.decay` | 0 – 0.96 | `trails` |
| `effect.intensity` | 0 – 2.5 | 3 effects |
| `effect.duty` | 0.05 – 1 | `strobe` |
| `effect.rate` | 1 – 16 | `strobe` |
| `effect.mix` | 0 – 1 | `invert` |
| `effect.axis` | 3 values | `mirror` |
| `effect.levels` | 2 – 32 | `posterize` |

## Generator

| Target | Range |
|---|---|
| `source.speed` | 0 – 2 |
| `source.scale` | 0.1 – 4 |
| `source.scroll_speed` | 0 – 4 |
| `source.intensity` | 0.2 – 2 |
| `source.zoom_speed` | 0.02 – 1 |
| `source.cycle_speed` | 0 – 2 |
| `source.ring_freq` | 10 – 80 |
| `source.drift_speed` | 0 – 2 |
| `source.pulse_speed` | 0 – 3 |
| `source.a` | -2 – 2 |
| `source.grow_speed` | 0 – 4 |
| Target | Range | Declared by |
|---|---|---|
| `source.speed` | 0 – 2 | 14 generators |
| `source.scale` | 0.1 – 4 | 11 generators |
| `source.scroll_speed` | 0 – 4 | `fire` |
| `source.intensity` | 0.2 – 2 | `fire` |
| `source.zoom_speed` | 0.02 – 1 | `mandelbrot` |
| `source.cycle_speed` | 0 – 2 | `mandelbrot` |
| `source.ring_freq` | 10 – 80 | `moire2` |
| `source.drift_speed` | 0 – 2 | 3 generators |
| `source.pulse_speed` | 0 – 3 | `halo` |
| `source.a` | -2 – 2 | `hopalong` |
| `source.grow_speed` | 0 – 4 | `rorschach` |

## Scope

| Target | Range |
|---|---|
| `scene.gain` | 0.25 – 3 |
| Target | Range | Declared by |
|---|---|---|
| `scene.gain` | 0.25 – 3 | `voice_scope` |
11 changes: 9 additions & 2 deletions docs/reference/01-introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,15 @@ number does not. Where a key takes one of a fixed set of values, the set is
listed in full; where it takes a free string, the shape of that string is
given by example.

A parameter marked *live* can be moved while a show is running, by a MIDI
knob, a pad, or the web console. Appendix F lists every one of them.
Two marks say that a setting can change while a show is running, and they are
different powers. A parameter marked *live-tunable* can be moved by a MIDI
knob, a pad or the web console; the mark names the `holder.name` target string
that reaches it, and Appendix F lists every one of them. A key marked
*menu-live* is one the on-C64 menu offers as a knob, applying the change to the
running scene; a key without the mark is not in the panel at all, because
changing it would mean rebuilding the scene. A setting can carry both: a
scene's `palette_mode` is on a MIDI knob as `mode.palette_mode` and is in the
menu.

A command-line flag is written as it is typed, with its leading dashes, as
`--config`. Flags are introduced beside the behaviour they change rather than
Expand Down
5 changes: 5 additions & 0 deletions docs/reference/07-inputs-and-outputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ cursor keys drive the menu instead. On exit with unsaved changes,
into the configuration you launched from; `false` applies them to the running
scene and never persists, which is what a convention stand wants.

Which knobs the panel offers is a property of the key rather than of the menu:
the ones Appendices A and B mark *menu-live* are the ones a running scene can
take a change to in place. Everything else would need the scene rebuilt, so it
is not in the panel.

It needs a backend that can read memory — the Ultimate, or a cycle-clean
TeensyROM+ — because SPACE is not a modifier and has to be read out of the
kernal's keyboard buffer. Text-valued parameters are shown read-only.
Expand Down
14 changes: 7 additions & 7 deletions docs/reference/20-appendix-a-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ generated: true
*Generated from the code by `scripts/gen_reference_appendices.py`.
Edits here are overwritten; run `make reference-appendices`.*

Every section of a configuration file: 19 sections and 149 fields, with the type each takes and the value it holds when you say nothing. `c64cast --describe section:NAME` prints any one of these at the terminal.
Every section of a configuration file: 19 sections and 149 fields, with the type each takes and the value it holds when you say nothing. A field a knob can move mid-show says so, and names the target Appendix F lists it under. `c64cast --describe section:NAME` prints any one of these at the terminal.

## `[hardware]`

Expand Down Expand Up @@ -191,14 +191,14 @@ Global pre-quantize color shaping for mcm/mhires/petscii: static channel boost +
| **`hue_corrections`**<br>`list[dict[str, Any]]`<br>`[]` | List of [[color.hue_corrections]] bands applied before quantize (keys: hue_lo_deg, hue_hi_deg, sat_thresh, val_thresh, sat_mult, val_mult, hue_target_deg, name). Empty = built-in purple rescue only. |
| **`hue_corrections_replace_defaults`**<br>`bool`<br>`False` | If true, user hue_corrections REPLACE the built-in defaults instead of extending them. |
| **`auto_fit`**<br>`bool`<br>`True` | Per-source adaptive color fit for video + slideshow scenes: pre-scan the source and stretch its contrast + saturation to fill the C64 gamut (faithful — hue preserved). Ignored by webcam scenes (can't pre-scan). |
| **`auto_fit_strength`**<br>`float`<br>`1.0` | Strength of the auto_fit transform, 0..1 (1 = full, 0 = off). Lerps the derived stretch toward identity. |
| **`auto_fit_strength`**<br>`float`<br>`1.0` | Strength of the auto_fit transform, 0..1 (1 = full, 0 = off). Lerps the derived stretch toward identity. *Live-tunable* while a show runs, as `mode.auto_fit_strength` — Appendix F. |
| **`force_palette`**<br>`bool`<br>`False` | EXTREME forced-palette remap (mcm/mhires): k-means the source into N clusters and map each to a DISTINCT C64 color so all N colors are used. Pre-scanned for video + slideshow; adapts live (rolling, warm-start + hysteresis) for webcam/wled/generative. Deliberate false-color (NOT faithful) — off by default; also reachable via the SHIFT cycle's 'percell+forced' stop once enabled. Tip: `--suggest-palette FILE` ranks a good force_palette_colors set. |
| **`force_palette_colors`**<br>`int \| list[int \| str]`<br>`16` | How force_palette allocates C64 colors: either an int count of distinct colors to spread the source across (2..16), OR an explicit list of colors to whitelist — each a color name (fuzzy + case-insensitive, e.g. "light blue", "lgrn", "blk") or an index 0..15. A list's length sets the color count. |
| **`dither`**<br>`str`<br>`'auto'` | Spatial dither applied before nearest-palette quantization on mhires/mcm/hires. 'auto' picks the best method that's actually useful for the scene: floyd-steinberg (highest quality) for static scenes (slideshow), blue_noise (vectorized, temporally stable — no added shimmer, and no Bayer grid structure) for motion scenes (video/webcam/generative). Any value can be forced on any scene; floyd-steinberg/atkinson are a Python-level per-pixel loop and can shimmer frame-to-frame on motion; 'ordered' (Bayer) is the older motion default and still available if the cross-hatch pattern is wanted (see docs/caveats.md). Choices: `auto`, `none`, `ordered`, `blue_noise`, `floyd-steinberg`, `atkinson`. |
| **`dither_strength`**<br>`float`<br>`0.5` | Dither strength, roughly 0..2.0. For 'ordered'/'blue_noise' it scales the threshold spread (same scale for both, so switching between them doesn't need a strength retune); for floyd-steinberg/atkinson it scales how much of each pixel's quantization error is diffused to its neighbors (1.0 = the textbook kernel weights). |
| **`color_match`**<br>`str`<br>`'auto'` | Color space for the nearest-palette match on the quantizing modes (mcm/mhires/hires/petscii). 'perceptual' measures nearest-color in CIE-Lab (perceptually uniform — picks the color the eye calls closest, e.g. a warm gray → orange/brown, not muddy gray). 'rgb' is the classic brightness-weighted BGR metric. Both keep the channel_boost + gray-penalty shaping; only the distance space differs. 'auto' (default) picks perceptual on every quantizing mode (a no-op on hires edges / blank, which pick no colors). Choices: `auto`, `rgb`, `perceptual`. |
| **`cell_strategy`**<br>`str`<br>`'auto'` | How mhires percell mode fills each 4×8 cell's 3 per-cell color slots from the colors present in that cell. 'frequency' = the 3 most-common (temporally stable). 'luminance' = darkest/median/brightest (preserves a cell's full tonal span). 'contrast' = the two luma extremes plus the color farthest from both. 'error-min' = the trio minimizing the cell's reconstruction error (best quality, costlier). 'auto' (default) uses error-min for static scenes (slideshow — composed once) and frequency for motion scenes (video/webcam/generative, where frequency's stability avoids per-frame slot churn). Only affects mhires with palette_mode=percell. Choices: `auto`, `frequency`, `luminance`, `contrast`, `error-min`. |
| **`motion_smoothing`**<br>`float`<br>`0.25` | Temporal smoothing for mhires percell mode, 0..1. The percell path smooths its per-cell color choices over time (an EMA over color counts plus per-pixel/per-cell decision hysteresis) to suppress frame-to-frame flicker on noisy video. That smoothing trades motion-tracking for stability, so on a hard shot cut an outline from the previous shot lingers as an after-image for a moment. 1.0 (full smoothing) is the most stable but ghostiest; 0.0 tracks the source exactly (no after-image) but can flicker on grainy content. The default 0.25 was picked by hardware A/B as the best ghost/flicker balance. Lower it if after-images still bother you, raise it if motion shimmers. No effect on other modes or palette_modes. |
| **`dither`**<br>`str`<br>`'auto'` | Spatial dither applied before nearest-palette quantization on mhires/mcm/hires. 'auto' picks the best method that's actually useful for the scene: floyd-steinberg (highest quality) for static scenes (slideshow), blue_noise (vectorized, temporally stable — no added shimmer, and no Bayer grid structure) for motion scenes (video/webcam/generative). Any value can be forced on any scene; floyd-steinberg/atkinson are a Python-level per-pixel loop and can shimmer frame-to-frame on motion; 'ordered' (Bayer) is the older motion default and still available if the cross-hatch pattern is wanted (see docs/caveats.md). Choices: `auto`, `none`, `ordered`, `blue_noise`, `floyd-steinberg`, `atkinson`. *Live-tunable* while a show runs, as `mode.dither_method` — Appendix F. |
| **`dither_strength`**<br>`float`<br>`0.5` | Dither strength, roughly 0..2.0. For 'ordered'/'blue_noise' it scales the threshold spread (same scale for both, so switching between them doesn't need a strength retune); for floyd-steinberg/atkinson it scales how much of each pixel's quantization error is diffused to its neighbors (1.0 = the textbook kernel weights). *Live-tunable* while a show runs, as `mode.dither_strength` — Appendix F. |
| **`color_match`**<br>`str`<br>`'auto'` | Color space for the nearest-palette match on the quantizing modes (mcm/mhires/hires/petscii). 'perceptual' measures nearest-color in CIE-Lab (perceptually uniform — picks the color the eye calls closest, e.g. a warm gray → orange/brown, not muddy gray). 'rgb' is the classic brightness-weighted BGR metric. Both keep the channel_boost + gray-penalty shaping; only the distance space differs. 'auto' (default) picks perceptual on every quantizing mode (a no-op on hires edges / blank, which pick no colors). Choices: `auto`, `rgb`, `perceptual`. *Live-tunable* while a show runs, as `mode.color_match` — Appendix F. |
| **`cell_strategy`**<br>`str`<br>`'auto'` | How mhires percell mode fills each 4×8 cell's 3 per-cell color slots from the colors present in that cell. 'frequency' = the 3 most-common (temporally stable). 'luminance' = darkest/median/brightest (preserves a cell's full tonal span). 'contrast' = the two luma extremes plus the color farthest from both. 'error-min' = the trio minimizing the cell's reconstruction error (best quality, costlier). 'auto' (default) uses error-min for static scenes (slideshow — composed once) and frequency for motion scenes (video/webcam/generative, where frequency's stability avoids per-frame slot churn). Only affects mhires with palette_mode=percell. Choices: `auto`, `frequency`, `luminance`, `contrast`, `error-min`. *Live-tunable* while a show runs, as `mode.cell_strategy` — Appendix F. |
| **`motion_smoothing`**<br>`float`<br>`0.25` | Temporal smoothing for mhires percell mode, 0..1. The percell path smooths its per-cell color choices over time (an EMA over color counts plus per-pixel/per-cell decision hysteresis) to suppress frame-to-frame flicker on noisy video. That smoothing trades motion-tracking for stability, so on a hard shot cut an outline from the previous shot lingers as an after-image for a moment. 1.0 (full smoothing) is the most stable but ghostiest; 0.0 tracks the source exactly (no after-image) but can flicker on grainy content. The default 0.25 was picked by hardware A/B as the best ghost/flicker balance. Lower it if after-images still bother you, raise it if motion shimmers. No effect on other modes or palette_modes. *Live-tunable* while a show runs, as `mode.motion_smoothing` — Appendix F. |

## `[dsp]`

Expand Down
Loading