Files
seedbox/docs/superpowers/specs/2026-10-11-scale-root-design.md
Gee 2196633ed5
Some checks failed
check / check (push) Has been cancelled
Seedbox v0.1 + firmware, generic kit/synth, ROOT/SCALE pages
First commit of the repo. Contents beyond the v0.1 simulator and layout:

- Full Pico 2 W firmware (firmware/app, drivers, engine port, host test).
- BANK page and 404 mode A/B removed; learned pads play exactly what was learned.
- 404/MiniFreak renamed to KIT/SYNTH throughout (jacks, code, sim, docs,
  layout labels; wiring rebuilt).
- ROLL returns to page select after a re-roll; a freshly learned track turns on.
- LCD contrast 66.
- ROOT and SCALE pages: 21 scales, AUTO = the seed picks; global and sticky.

Intended music change: the scale table grew from 8 to 21 and AUTO picks from
all of them, so every seed's scale changed. Vectors regenerated with
npm run vectors, plus new key-override cases. Flash record is now version 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:39:36 +03:00

96 lines
3.7 KiB
Markdown

# Scale and root selection
2026-10-11. Status: draft for review.
## Goal
Let Gee lock the line (bass, melody, pad) to a chosen root and scale, so Seedbox can play along with an existing musical idea. The seed still makes everything else.
## Decisions
| Question | Answer |
|---|---|
| Scope | Global and sticky. SEED, ROLL and loading a slot don't change it. Slots don't store it. |
| Pages | Two: ROOT and SCALE, each with AUTO. |
| AUTO | The seed picks from all 21 scales and 12 roots. Every existing seed changes scale (an intended music change). |
| Old data | None kept. It's a prototype, so the flash record starts fresh. |
## Scales
The menu order is also the table index.
| # | Screen name | Steps |
|---|---|---|
| 0 | MAJOR | 0 2 4 5 7 9 11 |
| 1 | MINOR | 0 2 3 5 7 8 10 |
| 2 | DORIAN | 0 2 3 5 7 9 10 |
| 3 | MIXOLYDIAN | 0 2 4 5 7 9 10 |
| 4 | LYDIAN | 0 2 4 6 7 9 11 |
| 5 | PHRYGIAN | 0 1 3 5 7 8 10 |
| 6 | HARM MINOR | 0 2 3 5 7 8 11 |
| 7 | MINOR PENT | 0 3 5 7 10 |
| 8 | MAJOR PENT | 0 2 4 7 9 |
| 9 | PHRYG DOM | 0 1 4 5 7 8 10 |
| 10 | DBL HARM | 0 1 4 5 7 8 11 |
| 11 | HUNG MINOR | 0 2 3 6 7 8 11 |
| 12 | UKR DORIAN | 0 2 3 6 7 9 10 |
| 13 | LYD DOM | 0 2 4 6 7 9 10 |
| 14 | HIRAJOSHI | 0 2 3 7 8 |
| 15 | IN SEN | 0 1 5 7 10 |
| 16 | IWATO | 0 1 5 6 10 |
| 17 | PROMETHEUS | 0 2 4 6 9 10 |
| 18 | WHOLE TONE | 0 2 4 6 8 10 |
| 19 | OCTATONIC | 0 1 3 4 6 7 9 10 |
| 20 | LOCRIAN | 0 1 3 5 6 8 10 |
Scales have 5 to 8 notes. Chords stay "every other scale note" (0, 2, 4 from the chord degree), so:
- 5-note scales give open chords;
- the 6-note whole tone gives augmented chords;
- the 8-note octatonic gives diminished chords.
## Engine (`sim/engine.js`, then `firmware/engine/engine.c`)
- `SCALES` and `SCALE_NAMES` become the 21-entry table above. In C, `SCALES[21][8]` and `SCALE_LEN[21]`.
- `genome()`: `g.scale = r.below(21)`. It's still one draw, so every later draw in the genome is unchanged.
- The params get `scale` (-1 = AUTO, 0..20) and `root` (-1 = AUTO, 0..11). `renderBar` overrides `g.scale` and `g.root` when they're ≥ 0, right after `genome()`, the same way AMENIZER overrides `steps`. In C this is `sb_params.scale` and `sb_params.root`.
- `describe()` and the simulator's "Key" fact show the effective scale and root.
- Integer-only and deterministic, as before.
## Vectors
- Run `npm run vectors` (an intended music change; the commit message says so).
- Add cases to `test/cases.js` with a fixed scale and root, so the C port is tested on overrides. Cover at least:
- a 5-note scale;
- the 8-note OCTATONIC;
- a root that isn't C;
- AUTO.
## Panel (firmware `app/main.c`, simulator `app.js`)
- Pages: SEED · GEN · ROOT · SCALE · BPM · SLOT · ROLL · LEARN.
- ROOT turns through AUTO, C, C#, …, B. SCALE turns through AUTO, MAJOR, …, LOCRIAN. Edit them like GEN: push, turn, push.
- Screen when set: label `ROOT` / `SCALE`, value `D` / `HIRAJOSHI`.
- Screen on AUTO: label `ROOT AUTO` / `SCALE AUTO`, value is what the seed picked.
- A change is heard from the next rendered bar, the same as GEN.
## Storage
- `live_t` gains `scale` and `root`, saved in flash. The record version goes to 2. Old records are ignored and defaults load.
- The leftovers from BANK go: the `unused` record field and `pad_t.spare`.
- Defaults: both AUTO.
- The simulator keeps them in localStorage next to `gen`.
## Docs
- `docs/controls.md`: add ROOT and SCALE to the pages table.
- `docs/concept.md`: the scale list.
- `docs/decisions.md`: add one line on global sticky key, AUTO over all 21.
## Testing
1. `npm test` passes with the new vectors.
2. `cd firmware/test && make test` passes.
3. Bench checks:
- set ROOT D and SCALE HIRAJOSHI, and check the MiniFreak notes stay in D Hirajoshi across several SEEDs;
- check that AUTO shows the seed's own pick.