初始提交: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 模板
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
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")
|
||||
Reference in New Issue
Block a user