foley.base#
Canonical data models for foley — the single source of truth (SSOT) types.
This module is stdlib-only and declarative: it defines the dataclasses, enums,
and affordance registries every other layer shares, plus generic dict/JSON
(de)serialization. It contains NO policy (see foley.licensing) and NO I/O
(see foley.stores / foley.audio).
Serialization contract:
record.to_dict()-> a plain dict (nested dataclasses recursed viadataclasses.asdict; enum members preserved, and JSON-safe because every enum subclassesstr).
record.to_json()-> a JSON string.
Cls.from_dict(d)/Cls.from_json(s)-> reconstructs, coercing enum fields from their string values and nestedLicenseRecordfrom its dict. Unknown keys are ignored (forward-compatible schema evolution); missing keys fall back to field defaults.
Module Attributes
Unified query-stage parameters (search / find / filter surface). |
|
Unified generation-stage parameters (generate backends map onto these). |
|
The named delivery targets (report 06 §5.2). |
Functions
|
Resolve a master spec (profile name, explicit profile, or |
Classes
|
How a sound entered foley (retrieval channel or origin). |
|
Descriptor for a unified parameter affordance (arioso analog). |
|
How a WEAVE |
|
A ranked, license-checked, (optionally) verified sound for one SoundEvent. |
|
Whether a candidate was retrieved from the index or freshly generated. |
|
What the caller intends to do with a sound; consumed by |
|
Mix layer (shared by |
|
Per-sound rights + provenance. |
|
Loudness master target — the delivery spec as data, not code (report 06 §5.2). |
|
WHERE/WHEN a clip sits — a symbolic anchor plus its resolved time (report 06 §6.3). |
|
HOW a clip sounds — all optional with identity defaults (report 06 §3, §6.3). |
|
How prominent a sound event is within a passage. |
Adds |
|
|
The editable, re-renderable sound-design plan — the SELECT→WEAVE bridge and render SSOT. |
|
One salient, physically-audible event decomposed from a passage. |
|
Canonical SSOT per sound. |
|
How a sound's bytes are held (DERIVED from |
|
One placed sound on the sound-design timeline — sparse seed + resolved render fields. |
|
The result of one verification rung for a candidate. |
|
Which rung of the verification ladder produced a |
- class foley.base.AcquisitionMethod(*values)[source]#
-
How a sound entered foley (retrieval channel or origin).
- class foley.base.Affordance(name, type, description, default=None, stage='query', carries_meaning=False)[source]#
Bases:
objectDescriptor for a unified parameter affordance (arioso analog).
- name#
Canonical parameter name used at the façade level.
- type#
Expected Python type.
- description#
Human-readable description.
- default#
Default value (
None= no default / required).
- stage#
'query'(search/find/filter) or'generate'.
- carries_meaning#
Dropping it would change what the caller gets (a seed they will rely on to reproduce, content they asked to exclude), so a backend that cannot honour it raises instead of dropping it (#53).
- class foley.base.Anchor(*values)[source]#
-
How a WEAVE
Placementbinds its symbolic time to the narration (report 06 §2.4).absoluteis a fixed offset; the rest resolve against the forced-alignedword_timeline—wordto a trigger word’s onset,sentenceacross a sentence span,scene/paragraphto a boundary’s first spoken word.
- class foley.base.Candidate(sound, origin=CandidateOrigin.retrieved, event=None, clap_score=None, bm25_score=None, rrf_score=None, rerank_score=None, verdict=None, license_ok=None, preview_uri=None, notes=<factory>, cost_estimate_usd=None, cost_actual_usd=None)[source]#
Bases:
SerializableMixinA ranked, license-checked, (optionally) verified sound for one SoundEvent.
Retrieval and generation return the SAME shape; only
origindiffers. Nestedsound/event/verdictdataclasses are decoded generically by_decode()— no per-field code needed.
- class foley.base.CandidateOrigin(*values)[source]#
-
Whether a candidate was retrieved from the index or freshly generated.
- foley.base.GENERATION_AFFORDANCES: dict[str, Affordance] = {'duration': Affordance(name='duration', type=<class 'float'>, description='Seconds; None => backend default', default=None, stage='generate', carries_meaning=False), 'loop': Affordance(name='loop', type=<class 'bool'>, description='Seamless-loopable clip', default=False, stage='generate', carries_meaning=False), 'negative_prompt': Affordance(name='negative_prompt', type=<class 'str'>, description='Content to exclude', default=None, stage='generate', carries_meaning=True), 'output_format': Affordance(name='output_format', type=<class 'str'>, description='wav|opus|mp3', default='wav', stage='generate', carries_meaning=False), 'prompt': Affordance(name='prompt', type=<class 'str'>, description='Sound description', default=None, stage='generate', carries_meaning=False), 'prompt_influence': Affordance(name='prompt_influence', type=<class 'float'>, description="0..1 unified adherence; None => the backend's native default", default=None, stage='generate', carries_meaning=False), 'seed': Affordance(name='seed', type=<class 'int'>, description='Reproducibility (capture in provenance)', default=None, stage='generate', carries_meaning=True), 'steps': Affordance(name='steps', type=<class 'int'>, description='Diffusion/flow steps', default=None, stage='generate', carries_meaning=False)}#
Unified generation-stage parameters (generate backends map onto these).
- class foley.base.IntendedUse(commercial=True, publish=True, redistribute_standalone=False, will_train=False, can_attribute=True, revenue_usd=0, allow_voice_or_trademark=False)[source]#
Bases:
SerializableMixinWhat the caller intends to do with a sound; consumed by
keep().
- class foley.base.Layer(*values)[source]#
-
Mix layer (shared by
SoundEventnow andTimelineItemlater).
- class foley.base.LicenseRecord(source, source_id=None, source_url=None, acquisition_method=AcquisitionMethod.user, retrieved_at=None, adapter_version=None, content_sha256=None, license_id='unknown', license_name=None, license_version=None, license_url=None, rights_holder=None, creator_name=None, creator_url=None, commercial_ok=False, embed_in_derivative_ok=True, redistribute_standalone_ok=False, cache_bytes_ok=False, modification_ok=False, ai_training_ok=False, ai_training_scope=None, gen_ai_preference=None, revenue_cap_usd=None, requires_attribution=False, attribution_text=None, notice_text_required=None, transformations=<factory>, is_ai_generated=False, generator_model=None, generator_version=None, generation_prompt=None, generation_seed=None, generation_params=<factory>, watermark=None, c2pa_manifest_ref=None, contains_recognizable_voice=False, potential_trademark=False, disclosure_recommended=False, rights_verified=False, verified_at=None, schema_version=1)[source]#
Bases:
SerializableMixinPer-sound rights + provenance. SSOT for BOTH
keep()and storage mode.The derived permission flags default fail-closed here (the bare-record baseline) — with one deliberate exception:
embed_in_derivative_okdefaultsTrue(the normal case for a licensed sound). That is not a live bypass:keep()checksrights_verifiedfirst, so an unverified record is rejected regardless. Populate the flags from thelicense_idviafoley.licensing.apply_license_flags(source overrides win). Never hand-set the derived flags — always route through the policy layer.
- foley.base.MASTER_PROFILES: dict[str, MasterProfile] = {'broadcast_atsc': MasterProfile(target_lufs=-24.0, true_peak_db=-2.0, lra=7.0), 'broadcast_ebu': MasterProfile(target_lufs=-23.0, true_peak_db=-1.0, lra=7.0), 'podcast': MasterProfile(target_lufs=-16.0, true_peak_db=-1.0, lra=11.0), 'streaming': MasterProfile(target_lufs=-14.0, true_peak_db=-1.0, lra=11.0)}#
The named delivery targets (report 06 §5.2).
resolve_master()maps a profile name to one of these; these values are the SSOT so no LUFS literal hides in code.
- class foley.base.MasterProfile(target_lufs=-16.0, true_peak_db=-1.0, lra=11.0)[source]#
Bases:
SerializableMixinLoudness master target — the delivery spec as data, not code (report 06 §5.2).
- class foley.base.Placement(anchor=Anchor.absolute, ref=None, onset=0.0, pre_roll=0.0, duration=None, loop=False)[source]#
Bases:
SerializableMixinWHERE/WHEN a clip sits — a symbolic anchor plus its resolved time (report 06 §6.3).
Filled by WEAVE’s aligner+anchor pass.
onsetis the resolved start in seconds (distinct from the sparseTimelineItem.onsetsymbolic string);pre_rollshifts the clip earlier so its salient transient — not its file start — lands on the anchor (report 06 §2.4).
- class foley.base.Processing(gain_db=0.0, pan=0.0, distance=0.0, reverb_send=0.0, fade_in=0.008, fade_out=0.012, duck_bed=False)[source]#
Bases:
SerializableMixinHOW a clip sounds — all optional with identity defaults (report 06 §3, §6.3).
Every field is a no-op at its default, so a sparse item (no
processing) renders untouched; the mixer departs from dry/centered/full-level only when a field is set.
- foley.base.QUERY_AFFORDANCES: dict[str, Affordance] = {'audioset_label': Affordance(name='audioset_label', type=<class 'str'>, description='AudioSet ontology facet (rolls up children)', default=None, stage='query', carries_meaning=False), 'commercial_ok': Affordance(name='commercial_ok', type=<class 'bool'>, description='License filter shorthand', default=None, stage='query', carries_meaning=False), 'duration_range': Affordance(name='duration_range', type=<class 'tuple'>, description='(min_s, max_s)', default=None, stage='query', carries_meaning=False), 'filters': Affordance(name='filters', type=<class 'dict'>, description='Metadata predicates (SQL-style)', default=None, stage='query', carries_meaning=False), 'k': Affordance(name='k', type=<class 'int'>, description='Number of results', default=10, stage='query', carries_meaning=False), 'license': Affordance(name='license', type=<class 'str'>, description='Explicit license id constraint', default=None, stage='query', carries_meaning=False), 'min_snr': Affordance(name='min_snr', type=<class 'float'>, description='QC filter: min SNR dB', default=None, stage='query', carries_meaning=False), 'rerank': Affordance(name='rerank', type=<class 'bool'>, description='Apply second-stage rerank', default=False, stage='query', carries_meaning=False), 'semantic_text': Affordance(name='semantic_text', type=<class 'str'>, description='Query for CLAP semantic space', default=None, stage='query', carries_meaning=False), 'sort': Affordance(name='sort', type=<class 'str'>, description='score|duration|created|downloads', default='score', stage='query', carries_meaning=False), 'text': Affordance(name='text', type=<class 'str'>, description='Natural-language query', default=None, stage='query', carries_meaning=False), 'ucs_category': Affordance(name='ucs_category', type=<class 'str'>, description='UCS CatID facet', default=None, stage='query', carries_meaning=False)}#
Unified query-stage parameters (search / find / filter surface).
- class foley.base.SerializableMixin[source]#
Bases:
objectAdds
to_dict/to_json/from_dict/from_jsonto a dataclass.Stdlib-only, DRY, no-magic (de)serialization. Every SSOT dataclass below inherits this instead of hand-rolling per-class encoders/decoders.
- classmethod from_dict(d)[source]#
Reconstruct an instance from a plain dict.
Enum fields and nested dataclasses are coerced via
_decode(). Unknown keys are ignored (forward-compatible); missing keys fall back to field defaults.- Parameters:
d (
dict) – A plain dict (typically fromto_dict()orjson.loads).- Return type:
- classmethod from_json(s)[source]#
Reconstruct an instance from a JSON string.
- Parameters:
s (
str) – A JSON string (typically fromto_json()).- Return type:
- class foley.base.SoundDesignTimeline(items=<factory>, run_manifest_ref=None, transcript_ref=None, schema_version=1, narration_ref=None, word_timeline=<factory>, master=<factory>)[source]#
Bases:
SerializableMixinThe editable, re-renderable sound-design plan — the SELECT→WEAVE bridge and render SSOT.
SELECT (#7) emits the SPARSE form (just
items+ the run/transcript joins) viafoley.agent.plan(). WEAVE (#8) grows it additively:narration_refbinds the voice audio,word_timelinecaches the forced alignment (the reproducible seed),mastercarries the loudness target, and each item gains its resolvedPlacement/Processing.render(timeline, library)is then a PURE function of this data + the library, so editing any field and re-rendering reproduces exactly that change.run_manifest_ref==foley.obs.RunManifest.run_id(the reserved #8plan_refjoin).
- class foley.base.SoundEvent(query, layer=Layer.sfx_fg, diegetic=True, salience=Salience.medium, onset=None, loop=False, ucs_catid=None, audioset=<factory>, era_place=None)[source]#
Bases:
SerializableMixinOne salient, physically-audible event decomposed from a passage.
- class foley.base.SoundRecord(id, content_sha256=None, hash_algo='sha256', uri=None, storage_mode=StorageMode.by_reference, archive_format=None, source_sample_rate=None, source_bit_depth=None, license=<factory>, caption=None, tags=<factory>, ucs_category=None, ucs_subcategory=None, audioset_labels=<factory>, duration_s=None, sample_rate=None, channels=None, loudness_lufs=None, format=None, qc=None, embedding_model=None, embedding_dim=None, embedding_ref=None, named_cue=None, schema_version=1)[source]#
Bases:
SerializableMixinCanonical SSOT per sound.
Audio bytes + CLAP vector live in SEPARATE stores keyed by the same id; this record holds a content-hash
uri, never raw bytes.
- class foley.base.StorageMode(*values)[source]#
-
How a sound’s bytes are held (DERIVED from
license.cache_bytes_ok).
- class foley.base.TimelineItem(clip_ref, onset=None, gain=0.0, layer=Layer.sfx_fg, loop=False, id=None, placement=None, processing=None, event=None, enabled=True)[source]#
Bases:
SerializableMixinOne placed sound on the sound-design timeline — sparse seed + resolved render fields.
SELECT (#7) sets only the sparse flat fields (
clip_ref·onset·gain·layer·loop); WEAVE (#8) additively fillsid/placement/processing(and may carry the originatingeventfor provenance).enabledis a non-destructive mute. The sparse flat fields are never removed — they stay SELECT’s SSOT input; the render reads the resolvedplacement/processing(falling back to the flat fields when those are absent).
- class foley.base.Verdict(match, confidence, reason='', level=VerifyLevel.clap)[source]#
Bases:
SerializableMixinThe result of one verification rung for a candidate.
- class foley.base.VerifyLevel(*values)[source]#
-
Which rung of the verification ladder produced a
Verdict.
- foley.base.resolve_master(master)[source]#
Resolve a master spec (profile name, explicit profile, or
None) to aMasterProfile.- Parameters:
master (
Union[str,MasterProfile,None]) – AMASTER_PROFILESkey (e.g.'podcast'), an explicitMasterProfile, orNone(-> the podcast default).- Return type:
- Returns:
The resolved
MasterProfile.- Raises:
ValueError – If
masteris an unknown profile name.