Skip to content

Refresh real curves after phrase rendering#2175

Open
KakaruHayate wants to merge 2 commits into
openutau:masterfrom
KakaruHayate:part2
Open

Refresh real curves after phrase rendering#2175
KakaruHayate wants to merge 2 commits into
openutau:masterfrom
KakaruHayate:part2

Conversation

@KakaruHayate
Copy link
Copy Markdown
Contributor

本改动解决的问题是:DiffSinger 等支持 real curve 的 renderer 在渲染完成后,UCurve.realXs / realYs 不会自动更新,用户必须手动点击“Refresh Real Curves”批量编辑功能才能看到最新 variance/real curve。现在每个
phrase 渲染完成后会自动尝试刷新对应 phrase 的 real curve,减少手动操作。

改动逻辑

新增了 phrase 级渲染完成 API:

  • PhraseRenderedNotification
  • RealCurvesUpdatedNotification

渲染流程变为:

  1. RenderEngine 完成单个 phrase 渲染。
  2. 发送 PhraseRenderedNotification,供后续渲染进度类功能复用。
  3. 如果 renderer 支持 SupportsRealCurve,尝试调用 LoadRenderedRealCurves(phrase)。
  4. RealCurveUpdater 将结果转换成 part-local tick,并只替换该 phrase 对应的 real curve 区间。
  5. DocManager 在 UI 线程应用 realXs / realYs 更新。
  6. NotesViewModel 收到更新通知后发送 NotesRefreshEvent,表达曲线画布自动重绘。

自动刷新失败时不会影响渲染;异常只被跳过/记录,不弹窗、不打断音频渲染。

保留的行为

  • 原来的 RefreshRealCurves 按钮/批量编辑入口保留。
  • 原按钮仍可作为 fallback 手动刷新全部 real curve。
  • 未修改 DiffSinger ONNX 输入构建。
  • 未引入第一阶段插队调度。
  • 未实现第三阶段 variance 对 pitch 编辑范围的局部 patch。

文件变更

OpenUtau.Core/Commands/Notifications.cs
新增 PhraseRenderedNotification 和 RealCurvesUpdatedNotification。

OpenUtau.Core/Render/RenderEngine.cs
phrase 渲染完成后发送 phrase 通知,并尝试生成 real curve 更新。

OpenUtau.Core/Render/RealCurveUpdater.cs
新增 real curve 转换和局部替换逻辑,包含 phrase hash stale-check。

OpenUtau.Core/DocManager.cs
处理 RealCurvesUpdatedNotification,在发布通知前应用 real curve 数据。

OpenUtau/ViewModels/NotesViewModel.cs
收到 real curve 更新后触发表达曲线重绘。

OpenUtau.Core/Properties/AssemblyInfo.cs
开放 internal 给测试项目。

OpenUtau.Test/Core/Render/RealCurveUpdaterTest.cs
测试坐标转换、局部替换、stale hash 跳过逻辑。

@KakaruHayate KakaruHayate marked this pull request as ready for review June 2, 2026 12:43
Introduce RenderPhraseEvents to report rendered real-curve fragments during phrase rendering and propagate the new optional parameter through IRenderer and concrete renderers (Classic, Worldline, DiffSinger, Enunu, Vogen, Voicevox). Add a DiffSingerRealCurveScheduler that coalesces curve-edit commands (200ms debounce) and schedules RealCurvesUpdated notifications only for variance-offset curves (ene, brec, voic, tenc). Wire scheduling into DocManager (on execute/undo/redo/undo-group) and make RenderEngine consume RenderPhraseEvents to publish incremental updates when available. Also add small ExpCommand.Key assignments to enable detection, refactor DiffSinger real-curve build logic, and include unit tests for the scheduler and RenderPhraseEvents behavior.
@KakaruHayate
Copy link
Copy Markdown
Contributor Author

原实现只在 phrase 完整渲染结束后刷新 real curve。DiffSinger 中 variance 曲线实际在 acoustic model 开始前已经确定,因此 pitch 修改后不应该等 acoustic/vocoder 完成才显示更新。

另外,用户只修改 ENE/BREC/VOIC/TENC 这些 variance offset 曲线时,base variance 通常不变,显示曲线可以更早刷新,不必等待整段音频渲染结束。

设计原则

通用层只建立干净的 hook/API,不放 DiffSinger 业务逻辑:

  • RenderPhraseEvents:renderer 可在渲染中间阶段报告 real curve。
  • IRenderer.ScheduleRealCurveRefresh(...):DocManager 在文档命令 validate 后通知当前 renderer,默认实现为空。

DiffSinger 独有逻辑留在 DiffSinger 责任区:

  • 只有 DiffSingerRenderer 使用 render hook。
  • 只有 DiffSingerRealCurveScheduler 判断哪些曲线需要快速刷新。
  • 其他 renderer 不改变行为。

改动逻辑

  1. pitch 修改场景

DiffSinger 在 variancePredictor.Process(phrase) 完成后,立即构造 real curve 并通过 RenderPhraseEvents.ReportRealCurves(...) 发布。

这样 real curve 会在 acoustic model 开始前刷新,而不是等整段 phrase 渲染结束。

  1. variance offset 曲线编辑场景

新增 DiffSinger 专用去抖调度器:

DiffSingerRealCurveScheduler

它只响应 DiffSinger 下列曲线:

  • ENE
  • BREC
  • VOIC
  • TENC

不会响应:

  • PITD
  • DYN
  • 其他非 variance offset 曲线

调度器使用 200ms debounce 合并拖拽绘制产生的连续曲线命令,避免做真正鼠标级预览。

  1. fallback 保留

RenderEngine 仍保留原来的 phrase 渲染完成后刷新逻辑。

如果 renderer 没有提前报告 real curve,例如命中整段 wav cache,仍会在渲染结束后尝试加载并刷新 real curve。

改动文件

  • OpenUtau.Core/Render/IRenderer.cs

    • 新增 RenderPhraseEvents
    • 扩展 Render(...) 可选参数
    • 新增默认空实现 ScheduleRealCurveRefresh(...)
  • OpenUtau.Core/Render/RenderEngine.cs

    • 接收 renderer 中途报告的 real curve
    • 若已提前刷新,则跳过结束后的重复刷新
    • 若没有提前刷新,保留原 fallback
  • OpenUtau.Core/DiffSinger/DiffSingerRenderer.cs

    • varianceResult 生成后立即报告 real curve
    • 复用 real curve 构造逻辑
    • 实现 ScheduleRealCurveRefresh(...)
  • OpenUtau.Core/DiffSinger/DiffSingerRealCurveScheduler.cs

    • 新增 DiffSinger 专用去抖刷新调度
    • 限定只处理 variance offset 曲线
  • OpenUtau.Core/DocManager.cs

    • 在命令 validate 后调用当前 renderer 的 real curve refresh hook
    • 覆盖普通命令、undo group、undo、redo
  • OpenUtau.Core/Commands/ExpCommands.cs

    • 曲线命令复用已有 ExpCommand.Key 记录曲线 abbr
    • 用于 DiffSinger scheduler 判断曲线类型
  • 其他 renderer 文件

    • 仅补齐新增可选参数
    • 不使用 hook,不改变行为
  • 测试

    • OpenUtau.Test/Core/Render/RealCurveUpdaterTest.cs
    • OpenUtau.Test/Core/DiffSinger/DiffSingerRealCurveSchedulerTest.cs

影响范围

实际功能影响限定在 DiffSinger:

  • 其他 renderer 不会主动报告 real curve。
  • 其他 renderer 默认不响应 ScheduleRealCurveRefresh(...)。
  • UTAU/Classic/Worldline/ENUNU/Vogen/Voicevox 行为不变。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant