初始提交: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,50 @@
|
||||
import math
|
||||
|
||||
import torch
|
||||
|
||||
AMPLITUDE = 0.8
|
||||
|
||||
|
||||
def sine_wave(
|
||||
duration: float,
|
||||
sample_rate: int,
|
||||
channels: int = 2,
|
||||
freq: float = 440.0,
|
||||
device: str = "cpu",
|
||||
half: bool = False,
|
||||
) -> torch.Tensor:
|
||||
"""Return a [channels, samples] sine-wave tensor in [-AMPLITUDE, AMPLITUDE]."""
|
||||
t = torch.linspace(0, duration, int(duration * sample_rate), device=device)
|
||||
wave = AMPLITUDE * torch.sin(2 * math.pi * freq * t)
|
||||
if half:
|
||||
wave = wave.half()
|
||||
return wave.expand(channels, -1).clone()
|
||||
|
||||
|
||||
def assert_audio_valid(
|
||||
audio: torch.Tensor, expected_duration: float, sample_rate: int
|
||||
) -> None:
|
||||
"""Assert that an audio tensor looks like valid, non-trivial audio output.
|
||||
|
||||
Args:
|
||||
audio: Output tensor of shape [B, C, T].
|
||||
expected_duration: Expected length in seconds.
|
||||
sample_rate: Sample rate in Hz.
|
||||
"""
|
||||
assert audio is not None, "Audio output is None"
|
||||
assert audio.ndim == 3, f"Expected 3D tensor [B, C, T], got shape {audio.shape}"
|
||||
|
||||
expected_samples = int(expected_duration * sample_rate)
|
||||
actual_samples = audio.shape[-1]
|
||||
tolerance = 0.15
|
||||
relative_error = abs(actual_samples - expected_samples) / expected_samples
|
||||
assert relative_error < tolerance, (
|
||||
f"Audio length {actual_samples} samples deviates more than {tolerance * 100:.0f}% "
|
||||
f"from expected {expected_samples} samples ({expected_duration}s @ {sample_rate}Hz)"
|
||||
)
|
||||
|
||||
assert not torch.isnan(audio).any(), "Audio output contains NaN values"
|
||||
|
||||
abs_max = audio.abs().max().item()
|
||||
assert abs_max > 0.001, f"Audio output appears silent (abs_max={abs_max:.5f})"
|
||||
assert abs_max <= 1.0, f"Audio output is clipping (abs_max={abs_max:.5f})"
|
||||
Reference in New Issue
Block a user