Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 74 additions & 16 deletions DiffSingerDeclarations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static class DiffSingerDeclarations
public const string KeyMouthOpening = "shift_mouth_opening"; // SHMC alpha:键取偏移语义,给将来绝对口型轨留 "mouth_opening"
public const string KeyExpressiveness = "expressiveness"; // pitch 表现力(PEXP):仅 dspitch use_expr 时暴露
public const string KeyToneShift = "tone_shift"; // 音区偏移(SHFC):仅 pitch_controllable 声码器时暴露
public const string KeyVarianceMode = "variance_param_mode"; // part 属性:variance 参数模式(delta=偏移 / absolute=绝对值)
public const string KeySpeaker = "speaker"; // legacy:part 默认说话人下拉
public const string KeyLanguage = "language";
public const string KeyModel = "model"; // manifest:模型下拉(part 属性)
Expand Down Expand Up @@ -64,12 +65,27 @@ public static int MixSlots(PropertyObject partProperties)
// 听感音高不变(声码器吃原始 f0)、声学按偏移后的 f0 取音色——「用另一个音区的嗓子唱这个音」。
public const double ToneShiftBaseline = 0, ToneShiftMin = -12, ToneShiftMax = 12;

// variance 参数模式
public const string VarianceModeDelta = "delta"; // 偏移值编辑(当前行为)
public const string VarianceModeAbsolute = "absolute"; // 绝对值编辑(dB 分段轨)

// 声库面包装记录:将命名空间级 VarianceSpec(纯数学)与 VoicebankConfig Use/Predict 选择器组合。
// 所有数值元数据与 Delta 公式委托给纯数学规格,此处仅追加 SDK 依赖的 Use/Predict。
public readonly record struct VarianceSpec(
string Key, string Display, string Color,
Func<VoicebankConfig, bool> Use, Func<VoicebankConfig, bool> Predict,
double EditMin, double EditMax, double Neutral,
double AcousticMin, double AcousticMax,
Func<float, float, float> Delta);
global::DiffSingerForTuneLab.VarianceSpec Math,
Func<VoicebankConfig, bool> Use,
Func<VoicebankConfig, bool> Predict)
{
public string Key => Math.Key;
public string Display => Math.Display;
public string Color => Math.Color;
public double EditMin => Math.EditMin;
public double EditMax => Math.EditMax;
public double Neutral => Math.Neutral;
public double AcousticMin => Math.AcousticMin;
public double AcousticMax => Math.AcousticMax;
public Func<float, float, float> Delta => Math.Delta;
}

// 编辑轨(delta 语义)归一化到小数:energy/breath/tension 中性 0、量程 [-1,1];voicing 中性 1、量程 [0,1.25]。
// Delta(x=预测声学值, y=用户归一化值) 系数随之 ×100:y=1 等价旧 y=100(energy/breath ±12dB、tension ±5)。
Expand All @@ -81,14 +97,13 @@ public readonly record struct VarianceSpec(
// 上行(y>1)线性 +48(y−1):满偏 1.25 = +12dB(与 energy 正向满偏对齐、避开 0dBFS 过载区);
// 中性线两侧斜率相等(48)、过线无顿挫(仅二阶导跳变)。
// 预测 < −72dB 的帧(本就近静音)下行中段轻微下越 −96,由合成期 clamp 兜住。详见 schema 文档 §14.2。
// absolute 模式不经过 Delta:已编辑帧直接采用用户声学目标,未编辑 NaN 帧跟随预测。
public static readonly VarianceSpec[] Variances =
{
new("energy", "Energy", "#E573A5", c => c.UseEnergyEmbed, c => c.PredictEnergy, -1, 1, 0, -96, 0, (x, y) => x + y * 12),
new("breathiness", "Breathiness", "#73E5C2", c => c.UseBreathinessEmbed, c => c.PredictBreathiness, -1, 1, 0, -96, 0, (x, y) => x + y * 12),
new("voicing", "Voicing", "#C2E573", c => c.UseVoicingEmbed, c => c.PredictVoicing, 0, 1.25, 1, -96, 0,
(x, y) => y > 1 ? x + 48 * (y - 1)
: x - 48 * (1 - y) / (2 - y) - (x + 72) * MathF.Pow(1 - y, 12)),
new("tension", "Tension", "#A573E5", c => c.UseTensionEmbed, c => c.PredictTension, -1, 1, 0, -10, 10, (x, y) => x + y * 5),
new(VarianceMath.Variances[0], c => c.UseEnergyEmbed, c => c.PredictEnergy),
new(VarianceMath.Variances[1], c => c.UseBreathinessEmbed, c => c.PredictBreathiness),
new(VarianceMath.Variances[2], c => c.UseVoicingEmbed, c => c.PredictVoicing),
new(VarianceMath.Variances[3], c => c.UseTensionEmbed, c => c.PredictTension),
};

// manifest retake 三位(legacy → 全 false ⇒ 不暴露任何 seed 轨)。
Expand All @@ -99,9 +114,12 @@ public static (bool Acoustic, bool Pitch, bool Variance) RetakeOf(ResolvedVoice
public static bool HasPhonemeMix(PartContext pc) => pc.Resolved.Manifest?.PhonemeMix ?? false;

// —— 自动化轨(可编辑曲线)= 固定轨 + 已启用的说话人混合轨 ——
// absoluteMode=true 时 variance 轨为分段绝对轨(dB),否则为连续 delta 轨(归一化偏移)。
// 由 part 属性 variance_param_mode 驱动("delta" | "absolute"),默认 delta。
public static OrderedMap<PropertyKey, AutomationConfig> BuildAutomationConfigs(PartContext pc, PropertyObject partProperties)
{
var map = BuildFixedAutomationConfigs(pc.Config, RetakeOf(pc.Resolved));
bool absoluteMode = VarianceModeOf(partProperties) == VarianceModeAbsolute;
var map = BuildFixedAutomationConfigs(pc.Config, RetakeOf(pc.Resolved), absoluteMode);
var set = SpeakerSet.Compute(pc.Resolved);
foreach (var (suffix, display, color) in SelectedMixTracks(set, partProperties))
map.Add((KeyMixPrefix + suffix, display), Continuous(color, 0, 0, 1)); // 混合权重归一化 [0,1](0=不混入)
Expand All @@ -113,14 +131,21 @@ public static OrderedMap<PropertyKey, AutomationConfig> BuildAutomationConfigs(P
return map;
}

// 固定轨(与 part 属性无关):variance(按声库能力)+ Gender/Speed + seed(按 retake gating)。
// 固定轨(与 part 属性无关):variance(按声库能力 + 参数模式)+ Gender/Speed + seed(按 retake gating)。
// absoluteMode=true 时 variance 轨切换为分段绝对轨(dB 量程,DefaultValue=NaN,未编辑=跟随预测),
// 否则为连续 delta 轨(归一化偏移量,DefaultValue=Neutral)。
public static OrderedMap<PropertyKey, AutomationConfig> BuildFixedAutomationConfigs(
VoicebankConfig config, (bool Acoustic, bool Pitch, bool Variance) retake)
VoicebankConfig config, (bool Acoustic, bool Pitch, bool Variance) retake, bool absoluteMode = false)
{
var map = new OrderedMap<PropertyKey, AutomationConfig>();
foreach (var v in Variances)
if (v.Use(config))
map.Add((v.Key, L.Tr(v.Display)), Continuous(v.Color, v.Neutral, v.EditMin, v.EditMax));
{
AutomationConfig cfg = absoluteMode
? AbsoluteCurve(v) // 分段绝对轨:dB 量程,未编辑 NaN = 跟随预测
: Continuous(v.Color, v.Neutral, v.EditMin, v.EditMax); // 连续 delta 轨
map.Add((v.Key, L.Tr(v.Display) + (absoluteMode ? " (" + L.Tr("Absolute") + ")" : "")), cfg);
}

if (config.UseKeyShiftEmbed)
map.Add((KeyGender, L.Tr("Gender")), Continuous("#E5A573", GenderBaseline, GenderMin, GenderMax));
Expand Down Expand Up @@ -163,15 +188,21 @@ public static OrderedMap<PropertyKey, AutomationConfig> BuildFixedAutomationConf
}

// 只读回显轨:仅当声学接受该量为输入且方差器能产基线时——显示实参(预测 + 用户 delta 合成后)。
public static OrderedMap<PropertyKey, AutomationConfig> BuildReadbackConfigs(VoicebankConfig config)
// 绝对值模式下用户轨即实参,回显轨冗余,跳过。
public static OrderedMap<PropertyKey, AutomationConfig> BuildReadbackConfigs(VoicebankConfig config, bool absoluteMode = false)
{
var map = new OrderedMap<PropertyKey, AutomationConfig>();
if (absoluteMode) return map; // 绝对值模式下不暴露回显轨
foreach (var v in Variances)
if (v.Use(config) && v.Predict(config))
map.Add((v.Key, L.Tr(v.Display)), Piecewise(v.Color, v.AcousticMin, v.AcousticMax));
return map;
}

// 绝对值模式下读取回显轨配置时也需要传入 mode(会话构造期已知当前模式)
public static OrderedMap<PropertyKey, AutomationConfig> BuildReadbackConfigs(PropertyObject partProperties, VoicebankConfig config)
=> BuildReadbackConfigs(config, VarianceModeOf(partProperties) == VarianceModeAbsolute);

// part 级面板:manifest 暴露 model/version 下拉;legacy 暴露 speaker 下拉;两者皆可有混音容器 + 默认语言。
public static ObjectConfig BuildPartConfig(PartContext pc, PropertyObject mergedProps)
{
Expand Down Expand Up @@ -208,6 +239,19 @@ public static ObjectConfig BuildPartConfig(PartContext pc, PropertyObject merged
properties.Add((KeyMixSlots, L.Tr("Phoneme mix slots")),
DraggableNumberBoxConfig.Integer(0).WithRange(0, MaxMixSlots));

// variance 参数模式(仅声库有 variance 参数时暴露):delta = 偏移值编辑;absolute = 绝对声学值编辑
// (energy/breathiness/voicing 为 dB,tension 为模型声学单位)。
if (pc.Config.UseEnergyEmbed || pc.Config.UseBreathinessEmbed || pc.Config.UseVoicingEmbed || pc.Config.UseTensionEmbed)
{
properties.Add((KeyVarianceMode, L.Tr("Variance param mode")), ComboBoxConfig
.Create(new List<ComboBoxItem>
{
new(PropertyValue.Create(VarianceModeDelta), L.Tr("Variance param mode (delta)")),
new(PropertyValue.Create(VarianceModeAbsolute), L.Tr("Variance param mode (absolute)")),
})
.WithDefault(PropertyValue.Create(VarianceModeDelta)));
}

return ObjectConfig.Create(properties);
}

Expand Down Expand Up @@ -409,6 +453,20 @@ static AutomationConfig Piecewise(string color, double min, double max)
// 连续轨:WithDefault 给实数基线 → 连续;按需 WithRandomizable。
static AutomationConfig Continuous(string color, double baseline, double min, double max, bool randomizable = false)
=> AutomationConfig.Create(min, max).WithDefault(baseline).WithColor(color).WithRandomizable(randomizable);

// 绝对模式分段轨:NaN 基线(未编辑 = 跟随预测)。energy/breathiness/voicing 以 dB 标注;
// tension 是模型声学值([-10,10]),不是 dB,保持纯数值标签。
static AutomationConfig AbsoluteCurve(VarianceSpec v)
{
var config = Piecewise(v.Color, v.AcousticMin, v.AcousticMax);
return v.Key == "tension"
? config
: config.WithMinLabel($"{v.AcousticMin:0} dB").WithMaxLabel($"{v.AcousticMax:0} dB");
}

// part 属性 variance_param_mode → 当前模式(缺省 delta)
public static string VarianceModeOf(PropertyObject partProperties)
=> partProperties.GetString(KeyVarianceMode, VarianceModeDelta);
}

// 一个 part 当前的“可用说话人集合”:驱动默认说话人、混音候选/轨、嵌入解析。
Expand Down
Loading
Loading