Files
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

73 lines
2.2 KiB
Python

import pytest
import torch
from functools import partial
from stable_audio_3 import StableAudioModel
from stable_audio_3.models.lora import (
LoRAParametrization,
add_lora,
get_lora_state_dict,
save_lora_safetensors,
)
from tests.conftest import ACCEL_DEVICE
_LORA_RANK = 4
_LORA_ALPHA = 4.0
def _lora_cfg(rank, alpha):
return {
torch.nn.Linear: {
"weight": partial(
LoRAParametrization.from_linear,
rank=rank,
lora_alpha=alpha,
adapter_type="lora",
),
},
torch.nn.Conv1d: {
"weight": partial(
LoRAParametrization.from_conv1d,
rank=rank,
lora_alpha=alpha,
adapter_type="lora",
),
},
}
@pytest.fixture(scope="session")
def synthetic_lora_ckpt(tmp_path_factory):
"""Build and save a minimal LoRA checkpoint from the small-music model for testing."""
model = StableAudioModel.from_pretrained("small-music", device=ACCEL_DEVICE)
add_lora(model.model.model, _lora_cfg(_LORA_RANK, _LORA_ALPHA))
add_lora(model.model.conditioner, _lora_cfg(_LORA_RANK, _LORA_ALPHA))
state_dict = {
**get_lora_state_dict(model.model.model),
**get_lora_state_dict(model.model.conditioner),
}
config = {"rank": _LORA_RANK, "alpha": _LORA_ALPHA, "adapter_type": "lora"}
ckpt_path = tmp_path_factory.mktemp("lora") / "synthetic.safetensors"
save_lora_safetensors(state_dict, config, ckpt_path)
del model
return ckpt_path
@pytest.fixture(scope="session")
def lora_model(synthetic_lora_ckpt):
"""Small-music model with a synthetic LoRA checkpoint loaded."""
model = StableAudioModel.from_pretrained("small-music", device=ACCEL_DEVICE)
model.load_lora([str(synthetic_lora_ckpt)])
return model
def test_lora_inference(lora_model, maybe_save_audio):
audio = lora_model.generate(prompt="drums", duration=1.0, steps=4, seed=42)
assert isinstance(audio, torch.Tensor)
assert audio.ndim == 3 # (batch, channels, samples)
assert audio.shape[0] == 1
assert audio.shape[-1] > 0
maybe_save_audio(audio, lora_model.model.sample_rate, "lora_drums")