Audio scenes
An AudioScene combines audio tracks, a set of room impulse responses (IRs), and a listener configuration into a single serializable recipe. It represents one capture scenario: audio sources placed at specific positions in a room, recorded at a single receiver using a defined device. No audio is rendered until you call render(), so a scene can be built, inspected, and stored before any computation runs. Once assembled, it can be rendered individually or added to a SceneCollection for batch processing.
The examples on this page show how to build a scene manually. For automated, large-scale scene generation, see the Scene collections how-to.
IR collection
IR collection loading and filtering
A scene is built around a single receiver position. Start by loading an IRCollection, then filter it to the receiver you want, leaving one IR per source position in the room.
import polars as pl
from treble_tsdk import treble
import treble_tsdk.scene as sc
tsdk = treble.TSDK()
ir_collection = tsdk.datasets.purchase("Treble10")
# Select a single receiver.
# The resulting IR collection will contain IRs for just one receiver and one simulation.
rec = ir_collection[68].receiver
ir_collection = ir_collection.filter_collection(pl.col("receiver_id") == rec.id)
Custom metadata columns
Add metadata columns to the IR collection to simplify source selection. The example below flags elevated sources as noise candidates:
from treble_tsdk.collections.ir_info import IRInfo
# Sources above 1.9 m are treated as noise emitters.
def is_noise_source(ir_info: IRInfo):
return ir_info.source.z > 1.9
# The new column is attached to the IR collection dataframe and can be in source_selection later.
ir_collection.add_column("IS_NOISE_SOURCE", is_noise_source)
Audio datasets
Dataset loading
Treble supports loading audio datasets from Hugging Face and from local directories of WAV files. See the Audio datasets how-to for the full set of built-in audio loaders and dataset-loading patterns.
The example below loads three datasets: a speech dataset for foreground tracks, a local music dataset, and a background noise dataset.
from pathlib import Path
# Pre-sliced LibriSpeech — shorter utterances give more realistic conversational timing.
speech_dataset = sc.AudioDataset.from_huggingface(
repo_id="treble-technologies/librispeech_asr_sliced",
split="test",
audio_loader_class=sc.LibriSpeechAudioLoader,
schema_mapping={"transcript": "text"},
drop_columns=["audio"],
)
# Local music dataset loaded from a directory of WAV files.
music_dataset = sc.AudioDataset.from_local_wav_directory(
wav_dir=Path("my_music_wav_dir")
)
# AudioSet loaded from Hugging Face.
hvac_dataset = sc.AudioDataset.from_huggingface(
repo_id="agkphysics/AudioSet",
config="full",
split="bal_train",
audio_loader_class=sc.AudioSetAudioLoader,
schema_mapping={"id": "video_id"},
drop_columns=["audio"],
max_parquet_files=1,
)
Track generation
TrackGenerator produces audio tracks from an AudioDataset according to a set of rules. The rules determine the track type and generation behavior:
ConversationRules— producesAudioTrackobjects with timedAudioBlockreferences, modelling turn-taking, overlap, and per-block level variation across multiple talkers.NoiseSourceRules— producesRepeatedAudioTrackobjects that loop a single audio sample at a fixed free-field level to a defined duration. Use this for continuous background sources such as HVAC or music.StaticNoiseRules— producesStaticNoiseTrackobjects containing synthetically generated frequency-shaped noise. No audio file is required.
The examples below use ConversationRules. For NoiseSourceRules in the context of automated scene generation, see the Scene collection how-to.
Conversation track generation with explicit rules
ConversationRules controls conversational timing — turn-taking, overlap, and per-block levels. The result is a set of AudioTrack objects, each containing timed AudioBlock references. Pass a seed for reproducible output.
duration_s = 20
conversation_rules = sc.ConversationRules(
block_duration_range=(1.5, 5.0), # duration range for candidate audio blocks in s
overlap_range=(0.2, 0.5), # Fractional overlap between consecutive blocks, in [0, 1]
in_track_level_range_db_spl=(60, 65), # Free-field level range for audio blocks within the same talker in dB SPL
)
track_generator = sc.TrackGenerator(
audio_dataset=speech_dataset,
rules=conversation_rules,
talker_identifier="speaker_id",
)
tracks = track_generator.generate_tracks(
n_tracks=2,
duration_s=duration_s,
seed=21, # fix seed for reproducible track layouts
)
Call plot_audio_tracks() to inspect the generated timelines before assembling the scene:
sc.plot_audio_tracks(tracks, duration_s)

Conversation tracks with a preset
For common conversation patterns, use a predefined preset via ConversationRules.from_preset() rather than specifying all parameters manually:
conversation_rules = sc.ConversationRules.from_preset(
sc.ConversationRulesPresets.sequential_talkers_no_overlap
)
Track and source assignment
Track-to-source assignment
Each track is paired with an IR from the collection through a TrackMap, which binds the track to a spatial position in the room. GroupTag categorizes tracks as TARGET or BACKGROUND. Use group_name to group related tracks in the visualization.
# Add two conversation (speech) tracks to the scene, each mapped to a different source position in the room.
track_maps = [
sc.TrackMap(
track=tracks[0],
ir=ir_collection[0],
group_name="conversation",
tag=sc.GroupTag.TARGET,
),
sc.TrackMap(
track=tracks[1],
ir=ir_collection[2],
group_name="conversation",
tag=sc.GroupTag.TARGET,
),
]
Looped background track
Use RepeatedAudioTrack for sources that should play continuously throughout the scene. The sample is looped to fill the required duration at the specified free-field level.
track_maps.append(
sc.TrackMap(
track=sc.RepeatedAudioTrack(hvac_dataset[0], free_field_level_db_spl=55),
ir=ir_collection[3],
group_name="hvac",
start_time_s=1,
duration_s=18,
tag=sc.GroupTag.BACKGROUND,
)
)
Listener configuration
Scene listener configuration
SceneListener defines how the scene is captured at the receiver. It combines a rendering device, a device orientation, optional per-channel noise floors, and optional output filters.
device = tsdk.device_library.get_device_by_name("KEMAR051123_1")
# One StaticNoiseTrack per device channel — models self-noise from each microphone element.
device_noise = [
sc.StaticNoiseTrack(sc.StaticNoiseProfile.pink_noise(), level_db_spl=40),
sc.StaticNoiseTrack(sc.StaticNoiseProfile.pink_noise(), level_db_spl=41),
]
listener = sc.SceneListener(
receiver=rec,
device=device,
orientation=treble.Rotation(azimuth=180), # rotate device 180° around the vertical axis
noise_definitions=device_noise,
)
Scene assembly
Scene assembly and inspection
An AudioScene brings together the track-to-source mappings and the listener definition. Call plot() to display the track timeline and a 3D room view for quick inspection.
my_scene = sc.AudioScene(
track_map=track_maps,
scene_listener=listener,
duration_s=duration_s,
)
my_scene.plot()

At this point my_scene is a serializable recipe — no audio waveforms have been computed yet.
Scene rendering
Single scene rendering
Call render() on an AudioScene to produce the mixed audio signal. Set output_separated_tracks=True to also receive per-track rendered outputs.
mixed = my_scene.render(
sampling_rate=32000,
render_mode=sc.RenderMode.DEVICE,
)
mixed.plot()
mixed.playback()
Target signal extraction
Call render_target() to produce the clean target signal. Pass a track index, a list of track indices, or a source group name as target_selection. When a group name or index list is given, each matching track is rendered individually and the results are summed.
Use get_track_indices_by_tag() or get_track_indices_by_group_name() to look up track indices by tag or group name.
# Resolve the first TARGET-tagged track index before passing it to render_target().
target_idx = my_scene.get_track_indices_by_tag(sc.GroupTag.TARGET)[0]
target = my_scene.render_target(
target_selection=target_idx,
sampling_rate=32000,
render_mode=sc.TargetRenderMode.WET_MONO, # room-convolved, mono output
)
Metadata and transcripts
Export scene metadata — source positions, receiver properties, device info, track timing, and levels — as a JSON-serializable dictionary with to_struct():
scene_metadata = my_scene.to_struct()
To extract transcripts from speech tracks, use transcript(). Pass track_index=None to retrieve the full scene transcript, or a specific index to retrieve the transcript for one track:
full_transcript = my_scene.transcript(track_index=None)
target_transcript = my_scene.transcript(track_index=target_idx)