- 模型 17/17 文件经镜像全量缓存(gated+token,直连本机不通;sfx.md/setup.md/asset-pipeline.md 镜像结论同步更新) - 修复迁移遗留:stable_audio_3/models/ 源码子包被 .gitignore models/ 规则误伤丢失,从上游恢复并加白名单 - radio:arg_muffled/brake_screech 等叙事件落地(接线原有 L111/L154 零改动)+ phone_ring SYN→SA3 升级;dungeon 13 源 A/B 对齐(RMS 偏差 ≤0.3dB)全量同名替换,SYN 原版备份 tools/asset_fix_backup/sa3_ab_20260902/ - 关键玩法语义达标:echo 距离档 0.83<1.43<2.18<2.98s 严格递增;one-shot 真峰值全 ≤-3dBFS(解码回读法) - check_all_assets 8 游戏全绿(radio 254/254、dungeon 303/303);playtest radio 221/dungeon 1610 全绿
85 lines
3.3 KiB
Python
85 lines
3.3 KiB
Python
import torch
|
|
import torch.nn as nn
|
|
from einops import rearrange
|
|
from torchaudio.transforms import Resample
|
|
from .blocks import ResidualUnit, WNConv1d
|
|
|
|
|
|
class AutoencoderPretransform(nn.Module):
|
|
def __init__(self, model, scale=1.0, iterate_batch=False, chunked=False):
|
|
super().__init__()
|
|
self.model = model
|
|
self.model.requires_grad_(False).eval()
|
|
self.scale = scale
|
|
self.downsampling_ratio = model.downsampling_ratio
|
|
self.io_channels = model.io_channels
|
|
self.enable_grad = False
|
|
self.iterate_batch = iterate_batch
|
|
self.chunked = chunked
|
|
|
|
def encode(self, x, **kwargs):
|
|
return self.model.encode_audio(x, chunked=self.chunked, iterate_batch=self.iterate_batch, **kwargs) / self.scale
|
|
|
|
def decode(self, z, chunked=None, **kwargs):
|
|
chunked = self.chunked if chunked is None else chunked
|
|
return self.model.decode_audio(z * self.scale, chunked=chunked, iterate_batch=self.iterate_batch, **kwargs)
|
|
|
|
def fold_channels_into_batch(x):
|
|
x = rearrange(x, 'b c ... -> (b c) ...')
|
|
return x
|
|
|
|
def unfold_channels_from_batch(x, channels):
|
|
if channels == 1:
|
|
return x.unsqueeze(1)
|
|
x = rearrange(x, '(b c) ... -> b c ...', c = channels)
|
|
return x
|
|
|
|
|
|
class PatchedPretransform(nn.Module):
|
|
def __init__(self, channels, patch_size, oversampling = 1, postfilter_channels = 0, **kwargs):
|
|
super().__init__()
|
|
self.channels = channels
|
|
self.patch_size = patch_size
|
|
self.oversampling = oversampling
|
|
|
|
self.downsampling_ratio = patch_size
|
|
self.io_channels = channels
|
|
self.encoded_channels = channels * patch_size
|
|
self.enable_grad = False
|
|
|
|
if self.oversampling > 1:
|
|
self.input_upsampler = Resample(1, self.oversampling)
|
|
self.output_downsampler = Resample(self.oversampling, 1)
|
|
|
|
if postfilter_channels > 0:
|
|
self.postfilter = nn.Sequential(
|
|
WNConv1d(in_channels=channels, out_channels=postfilter_channels, kernel_size=7, padding=3, bias=True),
|
|
ResidualUnit(in_channels=postfilter_channels, out_channels=postfilter_channels,
|
|
dilation=1, use_snake=True, bias = True),
|
|
ResidualUnit(in_channels=postfilter_channels, out_channels=postfilter_channels,
|
|
dilation=3, use_snake=True, bias = True),
|
|
ResidualUnit(in_channels=postfilter_channels, out_channels=postfilter_channels,
|
|
dilation=9, use_snake=True, bias = True),
|
|
WNConv1d(in_channels=postfilter_channels, out_channels=channels, kernel_size=7, padding=3, bias=False))
|
|
|
|
def _pad(self, x):
|
|
seq_len = x.shape[-1]
|
|
pad_len = (self.patch_size - (seq_len % self.patch_size)) % self.patch_size
|
|
if pad_len > 0:
|
|
x = torch.cat([x, torch.zeros_like(x[:, :, :pad_len])], dim=-1)
|
|
return x
|
|
|
|
def encode(self, x):
|
|
if self.oversampling > 1:
|
|
x = self.input_upsampler(x)
|
|
x = self._pad(x)
|
|
x = rearrange(x, "b c (l h) -> b (c h) l", h=self.patch_size)
|
|
return x
|
|
def decode(self, x):
|
|
x = rearrange(x, "b (c h) l -> b c (l h)", h=self.patch_size)
|
|
if hasattr(self, 'postfilter'):
|
|
x = self.postfilter(x)
|
|
if self.oversampling > 1:
|
|
x = self.output_downsampler(x)
|
|
return x
|