Files
SoundGame/tools/stable-audio-3/stable_audio_3/factory.py
T
SoundGame Dev f0f0a9b50e 初始提交:3 款纯音频游戏 + 共享引擎 + 完整文档与资产管线
- 共享引擎(app/src/main):GestureEngine 6 手势识别、AudioEngine 三层音频
  (ExoPlayer BGM 交叉淡入 / 对白 ducking / SoundPool 低延迟)、Game/GameEngine
  状态机接口、MainActivity 全屏封面 + TalkBack
- 《声命线》storyline:末世互动广播剧,3 幕 8 抉择点 4 结局
- 《声东击西》reflex:听声辨位反应,12 波战斗 + BGM 三档 BPM 变速
- 《暗室》escape:3x3 网格密室逃脱,钥匙→铁柜→保险丝→电箱→大门谜题链
- 文档:setup(从零搭建)/ architecture(架构)/ engine-api(引擎 API)/
  asset-pipeline(资产流水线)/ games/*(三款游戏设计文档)
- 资产管线:Qwen3-TTS 对白 + 程序合成音效/BGM + Mureka BGM 的 gen 脚本与台账,
  全部 ogg 资产入库可复现
- env.d 环境脚本:android/tts 入库;sfx/mureka 含密钥不入库,仅提交 .example.sh 模板
2026-08-29 13:00:34 +08:00

158 lines
6.0 KiB
Python

import typing as tp
from stable_audio_3.models.diffusion import DiTWrapper, ConditionedDiffusionModelWrapper
from stable_audio_3.models.autoencoders import (
AudioAutoencoder,
SAMEEncoder,
SAMEDecoder,
)
from stable_audio_3.models.conditioners import (
MultiConditioner,
NumberConditioner,
T5GemmaConditioner,
)
from stable_audio_3.models.bottleneck import SoftNormBottleneck
from stable_audio_3.models.pretransforms import (
PatchedPretransform,
AutoencoderPretransform,
)
def create_diffusion_cond_from_config(config: tp.Dict[str, tp.Any]):
model_config = config["model"]
diffusion_config = model_config.get("diffusion", None)
diffusion_model_config = diffusion_config.get("config", None)
diffusion_objective = diffusion_config.get("diffusion_objective", "v")
modular_local_cond_configs = diffusion_config.get("modular_local_cond_configs", [])
diffusion_model = DiTWrapper(
diffusion_objective=diffusion_objective,
modular_local_cond_configs=modular_local_cond_configs,
**diffusion_model_config,
)
io_channels = model_config.get("io_channels", None)
sample_rate = config.get("sample_rate", None)
cross_attention_ids = diffusion_config.get("cross_attention_cond_ids", [])
global_cond_ids = diffusion_config.get("global_cond_ids", [])
input_concat_ids = diffusion_config.get("input_concat_ids", [])
local_add_cond_ids = diffusion_config.get("local_add_cond_ids", [])
modular_local_cond_ids = [c["id"] for c in modular_local_cond_configs]
prepend_cond_ids = diffusion_config.get("prepend_cond_ids", [])
distribution_shift_options = diffusion_config.get(
"distribution_shift_options", None
)
sampling_distribution_shift_options = diffusion_config.get(
"sampling_distribution_shift_options", None
)
mask_padding_attention = diffusion_config.get("mask_padding_attention", False)
use_effective_length_for_schedule = diffusion_config.get(
"use_effective_length_for_schedule", False
)
pretransform = create_pretransform_from_config(model_config, sample_rate)
min_input_length = pretransform.downsampling_ratio
conditioning_config = model_config.get("conditioning", None)
conditioner = create_multi_conditioner_from_conditioning_config(conditioning_config)
min_input_length *= diffusion_model.model.patch_size
return ConditionedDiffusionModelWrapper(
diffusion_model,
conditioner,
min_input_length=min_input_length,
sample_rate=sample_rate,
cross_attn_cond_ids=cross_attention_ids,
global_cond_ids=global_cond_ids,
input_concat_ids=input_concat_ids,
local_add_cond_ids=local_add_cond_ids,
modular_local_cond_ids=modular_local_cond_ids,
prepend_cond_ids=prepend_cond_ids,
pretransform=pretransform,
io_channels=io_channels,
distribution_shift_options=distribution_shift_options,
sampling_distribution_shift_options=sampling_distribution_shift_options,
mask_padding_attention=mask_padding_attention,
use_effective_length_for_schedule=use_effective_length_for_schedule,
diffusion_objective=diffusion_objective,
)
def create_autoencoder_from_config(config, sample_rate):
# AE-only configs (SAME-S/SAME-L) have encoder/decoder at the top of config["model"].
# Full SA3 configs nest them inside config["model"]["pretransform"]["config"].
if "encoder" in config:
autoencoder_config = config
else:
autoencoder_config = config["pretransform"]["config"]
encoder = SAMEEncoder(**autoencoder_config["encoder"]["config"])
decoder = SAMEDecoder(**autoencoder_config["decoder"]["config"])
latent_dim = autoencoder_config.get("latent_dim", None)
downsampling_ratio = autoencoder_config.get("downsampling_ratio", None)
io_channels = autoencoder_config.get("io_channels", None)
in_channels = autoencoder_config.get("in_channels", None)
out_channels = autoencoder_config.get("out_channels", None)
soft_clip = autoencoder_config["decoder"].get("soft_clip", False)
pretransform = PatchedPretransform(**autoencoder_config["pretransform"]["config"])
bottleneck = SoftNormBottleneck(**autoencoder_config["bottleneck"]["config"])
return AudioAutoencoder(
encoder,
decoder,
io_channels=io_channels,
latent_dim=latent_dim,
downsampling_ratio=downsampling_ratio,
sample_rate=sample_rate,
bottleneck=bottleneck,
pretransform=pretransform,
in_channels=in_channels,
out_channels=out_channels,
soft_clip=soft_clip,
)
def create_pretransform_from_config(config, sample_rate):
pretransform_block = config["pretransform"]
autoencoder = create_autoencoder_from_config(config, sample_rate)
chunked = pretransform_block.get("chunked", False)
iterate_batch = pretransform_block.get("iterate_batch", False)
return AutoencoderPretransform(
autoencoder, chunked=chunked, iterate_batch=iterate_batch
)
def create_multi_conditioner_from_conditioning_config(
config: tp.Dict[str, tp.Any],
) -> MultiConditioner:
"""Create a MultiConditioner from a conditioning config dictionary."""
conditioners = {}
cond_dim = config["cond_dim"]
default_keys = config.get("default_keys", {})
pre_encoded_keys = config.get("pre_encoded_keys", [])
for conditioner_info in config["configs"]:
id = conditioner_info["id"]
conditioner_type = conditioner_info["type"]
conditioner_config = {"output_dim": cond_dim}
conditioner_config.update(conditioner_info["config"])
if conditioner_type == "t5gemma":
conditioners[id] = T5GemmaConditioner(**conditioner_config)
elif conditioner_type == "number":
conditioners[id] = NumberConditioner(**conditioner_config)
else:
raise ValueError(f"Unknown conditioner type: {conditioner_type}")
return MultiConditioner(
conditioners, default_keys=default_keys, pre_encoded_keys=pre_encoded_keys
)