# Multi-voice (a cast per project) — what it would take

The Studio mockup shows a **cast** (Sarah, Bill, Élodie) and lets you **add a
voice**, with each line spoken by whichever cast member you choose. The live
site cannot do this today, and it is not a small add. This is the honest
scope so the decision can be made with eyes open.

## The blocker, in one line

A project stores **one voice**. `projects.voice_id` is a single column, and
everything downstream assumes it: pricing, the dialect (which cues a voice
understands), the clone-vs-stock engine choice, generation, and the build.

To let different lines use different voices, the voice has to move from the
**project** down to the **line**.

## What has to change

**1. Schema**
- Add `voice_id` to `script_segments` (the line's speaker). Backfill every
  existing line with its project's current `voice_id` so nothing breaks.
- Keep `projects.voice_id` as the default for new lines, or drop it in favour
  of a "cast" (the set of voices used across the project's lines). A cast list
  is nicer but a bigger change; the default-voice approach is the safe first
  step.

**2. Generation** (`src/generation.php`, `src/tts.php`)
- Read the **line's** voice, not the project's. The dialect, the clone/stock
  engine path, the speed support, and the price multiplier all become
  per-line. Most of this already flows from a voice row — it just has to be
  the line's voice row, loaded per segment.
- This is the part most likely to hide surprises: a project could now mix a
  Fish clone (square-bracket cues, honours speed) and a stock v3 voice
  (audio-tag cues, ignores speed) in one script. The per-line cue menu and
  speed control already key off the voice's dialect, so they are mostly ready,
  but every place that read `project.voice_*` has to be found and switched to
  the segment's voice.

**3. Pricing and the estimate**
- "Cost to voice all" is currently one multiplier. It becomes a sum across
  lines at each line's rate. The creation-flow mockup already quotes the
  dearest voice as a safe upper bound; the real total is a per-line sum.

**4. The editor UI**
- The cast strip on the slate, with **Add a voice** (opens the voice library,
  adds to the cast).
- A speaker control on each line (the avatar in the lead column becomes a
  picker), which writes the line's `voice_id`. Changing a line's voice makes
  its take stale, same as a cue change.
- The `start.php` creation flow already has the casting step designed; it
  would finally be wired to real data.

**5. The build**
- No change in principle — it stitches the chosen takes regardless of which
  voice made each. Worth checking loudness matches across voices; the existing
  broadcast-level polish already normalises the whole program, so this is
  probably fine.

## Effort and risk

- **Schema + backfill:** small and safe (one migration, one UPDATE).
- **Generation per-line voice:** the real work. Not hard conceptually, but it
  touches the most important code path (the thing that spends money and makes
  the audio), so it needs careful testing per engine — a Fish line and an
  ElevenLabs line in the same project, generated and built, listened to.
- **UI:** moderate. The pieces exist as mockups; wiring them is the job.
- **Biggest risk:** a mixed-engine project surfacing an assumption we did not
  know we had. Mitigation is to test the mixed case early and hard.

## A phased way in (lowest risk first)

1. **Schema + backfill.** `script_segments.voice_id`, every line set to its
   project's voice. Nothing changes visibly. Ships safely on its own.
2. **Generation reads the line's voice.** Still one voice per project in the
   UI, but the pipeline is now per-line. Prove it is identical to today.
3. **The speaker picker + cast strip.** Now a project can genuinely mix
   voices. Test the mixed-engine case thoroughly here.
4. **Pricing as a per-line sum**, and the creation-flow casting step wired up.

Steps 1 and 2 are invisible groundwork that de-risks everything after. If the
appetite is there, that is where to start; the visible payoff arrives at
step 3.

## Recommendation

Worth doing — it is the single most distinctive feature in the mockup and the
thing a marketplace of voices is built to sell. But it is a project, not an
afternoon, and it changes the data model. Do it deliberately, phased as above,
with the mixed-engine test as the gate between step 2 and step 3. Not something
to squeeze in beside smaller polish.
