---
name: treble-scene-generator
description: Generate bulk, labeled audio scene datasets with the Treble SDK's scene-generation feature (SceneGenerator, SceneRules/SourceGroup, TrackGenerator, AudioScene/SceneCollection) — for Automatic Speech Recognition (ASR), Speaker Identification & Diarization, Sound Event Detection (SED/SELD), Environmental Noise Cancellation (ENC), Speech Enhancement and Denoising, Voice Activity Detection, Sound Separation, Source Localization/DOA, Acoustic Scene Classification, room-acoustic-parameter regression datasets, or similar audio-ML data needs. Use whenever a request involves combining impulse responses (IRs) with clean audio to build training/eval data, or generating audio scenes/datasets at scale.
---

# Treble SDK: scene generation

Follow AGENTS.md (https://sdk-docs.treble.tech/agent-instructions/AGENTS.md) as well; this skill adds to it and does not replace it.

**API reference** for every class/method https://sdk-docs.treble.tech/. Most relevant pages:
- Scene Generator and Audio Scene modules: https://sdk-docs.treble.tech/api/scene/index.html and all its subpages
- Scene collection: https://sdk-docs.treble.tech/api/collections/treble_tsdk.collections.scene_collection.html
- IR collection: https://sdk-docs.treble.tech/api/collections/treble_tsdk.collections.ir_collection.html
- Distributions: https://sdk-docs.treble.tech/api/collections/treble_tsdk.collections.distributions.html

**How-to documentation**:
- https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-a-scene — constructing a single audio scene manually
- https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection — automated bulk generation with `SceneGenerator` and manual assembly
- https://docs.treble.tech/treble-sdk/how-to/audio-scenes/render-a-scene-collection — rendering scenes, extracting target signals, exporting metadata
- https://docs.treble.tech/treble-sdk/how-to/audio-scenes/track-generator — picking a rules class by the nature of the audio content
- https://docs.treble.tech/treble-sdk/how-to/audio-scenes/audio-datasets — preparing and loading audio datasets

With the Treble MCP server connected, open these links with `docs_fetch` and confirm names and
signatures with `api_lookup`.

## Before writing anything: check for an application recipe

If the request names (or clearly implies) an application, **read the closest matching recipe
first** and adapt it, even if it isn't an exact match:

| Application | Recipe |
|---|---|
| ASR / transcription training data | https://docs.treble.tech/treble-sdk/use-cases/machine-learning/asr-training-data — reverberant speech with background noise, MEMS mic noise, clean/mix/transcript export |
| Multi-channel ML training data (Ambisonics, DOA labels) | https://docs.treble.tech/treble-sdk/use-cases/machine-learning/ml-training-data — spatial IR simulation, device-rendered IRs, multi-channel scenes with DOA labels |
| ML model evaluation / benchmark sets | https://docs.treble.tech/treble-sdk/use-cases/machine-learning/ml-evaluation — controlled evaluation sets with systematic IR coverage and speech enhancement benchmarking |
| Core scene generation walkthrough (manual + bulk) | https://docs.treble.tech/treble-sdk/use-cases/audio-scene-generation — manual assembly, `SceneGenerator` bulk generation, rendering, and target extraction |

## Mental model

A `SceneCollection` is built in one of two ways:

1. **`SceneGenerator`** — the primary workflow; generates the whole collection from rules. Use
   for bulk datasets, following the six steps below.
2. **Manual assembly** — build `AudioScene`s individually and `add_scene()`/`add_scenes()` them
   to an empty `SceneCollection`. Use for a small, hand-picked set.

## The six-step workflow

Every script that builds a rendered audio dataset follows these steps in order — including when
you extend or pick up someone else's.

1. **Initialize** — `tsdk = treble.TSDK()`.
2. **Audio datasets** — see https://docs.treble.tech/treble-sdk/how-to/audio-scenes/audio-datasets
   and "Track generation: picking a rule type" below. If the user will want predicted SNR,
   enrich the datasets and IR collection now — see "SNR: predicted vs calculated" below.
   For external datasets tell the user before downloading anything large.
3. **IR collection** — see "IR collections: `IRCollection`" below.
4. **Source groups** — see
   https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection#source-groups
   and "Source groups: roles and presence" below.
5. **Listener rules** — see
   https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection#listener-rules.
   **Don't silently default to no device.** A request framed around a real deployment target (a
   specific microphone, hearable, phone, array, etc.) implies a device — ask rather than assume.
   To let the user pick from existing devices, show `treble.dd.display(tsdk.device_library.get())`
   (`get_devices(group=...)` narrows by group).
6. **Generate, validate, curate, save, render**
   - Generate: https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection#automated-generation-with-scenegenerator
   - Validate: after every `generate_scenes()` call, run the checks in "Validating a generated
     collection" below and report the result before moving on.
   - Curate before rendering — e.g. filter by predicted SNR (see "SNR: predicted vs calculated").
   - Save/reload: https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection#saving-and-reloading-a-collection
   - Render: **only with the user's consent** (next section), then see
     https://docs.treble.tech/treble-sdk/how-to/audio-scenes/render-a-scene-collection.
     If the dataset needs clean/target signals (ASR, enhancement, separation, target-derived
     labels), pass the target source groups as `target_selection`; without it only the mix is
     rendered. Read rendered audio back with
     `scene_collection.get_renders_from_disk(scene_id, output_path)`.

## Never render without the user's consent

Building scenes and collections is free (no IR download, no convolution). Rendering is not:
**do not call `AudioScene.render()`, `AudioScene.render_target()`, `SceneCollection.render_to_disk()`,
`SceneCollection.render()` or `SceneCollection.start_remote_optimization()`, unless the user asks
for it or approves it.**

**Show the token cost before asking for consent.** When the listener uses a device or filters,
rendering a `SceneCollection` runs a token-costing remote optimization (`SceneCollection.render()` and
`SceneCollection.render_to_disk()` start it automatically if it hasn't run). Call
`scene_collection.print_remote_optimization_token_cost()` (or `get_remote_optimization_token_cost()`
for the value) and include the cost in the consent request.

## IR collections: `IRCollection`

Get one from `tsdk.datasets.purchase(...)`, `tsdk.collections.ir_collection(simulations)` or
`tsdk.collections.ir_collection_from_file(path)`; see
https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-a-scene#ir-collection-loading-and-filtering.

- **Browsing datasets:** `tsdk.datasets.display_all()` lists every dataset;
  `tsdk.datasets.display_catalog()` only those available for purchase. Default free collection
  for examples: `tsdk.datasets.purchase("Treble10")`.
- **Pass an unprocessed collection.** `SceneGenerator` rejects one that already carries device
  renders/filters.

## Track generation: picking a rule type

Match the rules class to what the *dataset actually is*, not the application — see
https://docs.treble.tech/treble-sdk/how-to/audio-scenes/track-generator.

If a dataset meant for `ConversationRules` is long-form, tell the user and propose slicing it or
switching to a pre-sliced dataset; don't silently wire long clips into `ConversationRules`.

## Validating a generated collection

`generate_scenes()` draws scenes from a set of valid **configurations** — (receiver, simulation,
per-group IR selection) combinations. Get the count, `n_configs`, with `generate_logs=True`: it is
`context["valid_candidates"]` on the log entry whose message is `"Feasibility planning completed."`;
`n_scenes` is `len(scene_collection)` (see
https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection#analyzing-generation-coverage).
Scenes sharing a configuration still differ in audio samples, levels, timing and orientation, so
`n_configs` caps *acoustic* diversity, not scene diversity. A smaller IR collection or stricter
`receiver_selection`/`source_selection`/`n_sources`/`min_n_sources` lowers it.

- `n_scenes > n_configs` (only possible with `allow_config_reuse=True`): configurations repeat.
  Tell the user, keeping the distinction above clear; more acoustic diversity needs a larger IR
  collection or looser rules.
- `n_scenes <= n_configs`: the default `allow_config_reuse=True` may still repeat configurations.
  If each scene needs its own acoustic layout, regenerate with `allow_config_reuse=False`.
- Very small `n_configs` (a few, or fewer than `max_n_scenes`): the IR collection is small or the
  rules are stricter than intended. Show the user the count before building on the collection.

## Source groups: roles and presence

Valid audio can still be useless training data. Before generating:

- **Roles.** Agree with the user which source groups are targets and which are interference or
  background, and set `group_tag=treble.scene.GroupTag.<role>`. Don't make interference a label
  unless the user asks.
- **Group presence.** Not randomized: in one `generate_scenes()` run, every `SourceGroup` with
  eligible IRs appears in every scene. Set `n_sources` when the count matters. Without it, a group
  takes all its eligible IRs; groups that also set no `min_n_sources`, `source_selection` or
  priority split the remaining IRs evenly.

## Do not parallelize a single `generate_scenes()` call

It shares stateful random engines across draws, so splitting it breaks `random_seed`
reproducibility and sampling coverage. To scale out, run `generate_scenes(random_seed=seed_i)`
per batch in separate processes and merge with `add_scenes()`. (`render_to_disk()` is already
threaded.)

## SNR: predicted vs calculated

Two distinct SNR paths — do not confuse them:
- **Predicted** — fast, metadata-only estimate; no render required. For prerequisites, usage,
  accuracy limits, and worked examples, see
  https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection#predicted-scene-snr
  and https://docs.treble.tech/treble-sdk/how-to/audio-scenes/create-scene-collection#filter-by-predicted-snr.
- **Calculated** (`calculate_snr=True` on `render_to_disk()`) — measured from rendered audio;
  the ground truth. Requires `target_selection` and is not supported with
  `render_mode=treble.scene.RenderMode.SPATIAL`. Returns `None` if no active speech is detected
  in the target. See
  https://docs.treble.tech/treble-sdk/how-to/audio-scenes/render-a-scene-collection#snr-calculation.

**Predicted SNR must be decided before generation.** It needs
`enrich_with_acoustic_parameters(acoustic_parameters=["spl"])` on the IR collection and
`enrich_with_spl()` on every `AudioDataset` (target and noise), both **before**
`generate_scenes()` — tracks snapshot metadata at generation, so enriching later means
regenerating. `enrich_with_spl()` is slow: only do it when the user wants SNR (ask if unclear).
Noise defined by `from_noise_type_and_microphone_snr()` can't be predicted. Keep it and use
calculated SNR after rendering; switch to `level_db_spl` only if the user accepts an absolute-SPL
noise level instead of the microphone-SNR model.

## Exception to the private-method rule: custom audio loaders

Subclasses of `BaseAudioLoader` may use its `_`-prefixed members (e.g. `self._id_column`,
`self._row_for_id()`) — that is the documented extension protocol; see the audio-datasets how-to.
Call `super().__init__(...)` in the constructor and `super().__call__(id, metadata)` before any
row lookup: they load and materialize the loader's dataframe.
