第二批反馈:引擎改造(限幅/SoundTouch不变调变速/长按快进/跳句/iOS闪光降级) + 6游戏状态BGM与试玩测试全绿
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""爆音资产排查(R6):扫描 6 游戏全部 .ogg。
|
||||
|
||||
检测项:
|
||||
1. 峰值 > -1dBFS(有损编码过冲/归一不足)
|
||||
2. 首尾 5ms 内电平突变(无淡入淡出 → 爆豆声)。loop 类(bgm/ 与 sfx/amb_*)按
|
||||
首尾交叉淡化工艺制造,边界连续是特性,只做 DC/峰值检查,不报爆豆、不修。
|
||||
3. 直流偏置(|DC| > 0.001)
|
||||
输出 JSON 行到 stdout 供汇总;--fix 模式见 fix_clicks.py 逻辑(本文件只扫)。
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import soundfile as sf
|
||||
|
||||
ROOT = "/home/ubuntu/SoundGame/web"
|
||||
GAMES = ["storyline", "escape", "simon", "rhythm", "space", "rpg"]
|
||||
EDGE_MS = 5
|
||||
DC_THRESH = 0.001
|
||||
PEAK_THRESH = 10 ** (-1.0 / 20) # -1dBFS
|
||||
|
||||
|
||||
def is_loop(relpath):
|
||||
parts = relpath.split(os.sep)
|
||||
return "/bgm/" in "/" + relpath or os.path.basename(relpath).startswith("amb_")
|
||||
|
||||
|
||||
def scan(path):
|
||||
y, sr = sf.read(path, always_2d=True)
|
||||
mono = y.mean(axis=1)
|
||||
peak = float(np.max(np.abs(mono)))
|
||||
dc = float(np.mean(mono))
|
||||
n5 = max(1, int(sr * EDGE_MS / 1000))
|
||||
n1 = max(1, int(sr * 1 / 1000))
|
||||
n50 = max(1, int(sr * 50 / 1000))
|
||||
head = float(np.max(np.abs(mono[:n5])))
|
||||
tail = float(np.max(np.abs(mono[-n5:])))
|
||||
# 爆豆判定(突变而非渐变):首/末 1ms 内的最大幅值 与 相邻 50ms 窗口峰值之比。
|
||||
# 正常淡入(8ms cos²)首 1ms 幅值 < 局部峰值 15%;硬边/步进则趋近 1。
|
||||
loc_h = float(np.max(np.abs(mono[:n50])))
|
||||
loc_t = float(np.max(np.abs(mono[-n50:])))
|
||||
FLOOR = 0.01 # 局部窗口低于 -40dB 视为静音区,不判爆豆(编解码底噪残余)
|
||||
step_head = loc_h > FLOOR and float(np.max(np.abs(mono[:n1]))) > 0.15 * loc_h
|
||||
step_tail = loc_t > FLOOR and float(np.max(np.abs(mono[-n1:]))) > 0.15 * loc_t
|
||||
return {
|
||||
"path": os.path.relpath(path, ROOT),
|
||||
"loop": is_loop(os.path.relpath(path, ROOT)),
|
||||
"peak_db": round(20 * np.log10(max(peak, 1e-9)), 2),
|
||||
"dc": round(dc, 5),
|
||||
"head5ms_db": round(20 * np.log10(max(head, 1e-9)), 2),
|
||||
"tail5ms_db": round(20 * np.log10(max(tail, 1e-9)), 2),
|
||||
"hot_peak": peak > PEAK_THRESH,
|
||||
"dc_bad": abs(dc) > DC_THRESH,
|
||||
"click_head": step_head,
|
||||
"click_tail": step_tail,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for g in GAMES:
|
||||
base = os.path.join(ROOT, g, "audio")
|
||||
for dirpath, _d, files in os.walk(base):
|
||||
for f in sorted(files):
|
||||
if f.endswith(".ogg"):
|
||||
results.append(scan(os.path.join(dirpath, f)))
|
||||
import json
|
||||
for r in results:
|
||||
print(json.dumps(r, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user