Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ソング:フレーズのレンダリング処理をリファクタリング #2248

Merged
merged 15 commits into from
Sep 3, 2024

Conversation

sigprogramming
Copy link
Contributor

@sigprogramming sigprogramming commented Aug 24, 2024

内容

以下を行います。

  • PhraseRendererを追加
  • QueryGenerationStageを追加
  • SingingVolumeGenerationStageを追加
  • SingingVoiceSynthesisStageを追加
  • 以下の関数をphraseRendering.tsに移動
    • createNotesForRequestToEngine
    • shiftKeyOfNotes
    • getPhonemes
    • shiftPitch
    • shiftVolume
    • muteLastPauSection
  • フレーズのレンダリング処理をPhraseRendererを使用して行うように変更
  • フレーズの開始時間(startTime)をPhraseに持たせ、算出をフレーズ生成時に行うように変更
  • PhraseStateSINGER_IS_NOT_SETを追加
  • 型を整理

レンダリングの流れ

  1. 重なっているノートを除外
  2. searchPhrasesを実行
  3. 新しいフレーズまたは既存のフレーズに対して以下を行う
    1. シンガーが未設定の場合、stateSINGER_IS_NOT_SETに設定
    2. シンガーが設定されている場合、以下を行う
      1. 新しいフレーズまたはstateCOUND_NOT_RENDERの場合、レンダリング開始ステージを一番最初のステージに設定
      2. 既存のフレーズの場合、適切なレンダリング開始ステージを決定する
      3. stateWAITING_TO_BE_RENDEREDに設定
  4. 無くなったフレーズに対して、以下を行う
    1. シーケンスが存在する場合、シーケンスを削除する
  5. stateSINGER_IS_NOT_SETまたはWAITING_TO_BE_RENDEREDのフレーズに対して、以下を行う
    1. シーケンスが存在する場合、シーケンスを削除する
    2. ノートシーケンスを生成して登録する
  6. stateWAITING_TO_BE_RENDEREDのフレーズに対して以下を行う
    1. フレーズのレンダリングを行う
    2. シーケンスが存在する場合、シーケンスを削除する
    3. オーディオシーケンスを作成して登録する

関連 Issue

ref #2247

その他

Comment on lines +27 to +30
/**
* リクエスト用のノーツ(と休符)を作成する。
*/
const createNotesForRequestToEngine = (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

以下の関数と変数はsinging.tsRENDERから持ってきたもので、ほとんど変更していません。

  • createNotesForRequestToEngine
  • shiftKeyOfNotes
  • getPhonemes
  • shiftPitch
  • shiftVolume
  • muteLastPauSection
  • singingTeacherStyleId
  • lastRestDurationSeconds
  • fadeOutDurationSeconds

@sigprogramming sigprogramming marked this pull request as ready for review August 25, 2024 03:48
@sigprogramming sigprogramming requested a review from a team as a code owner August 25, 2024 03:48
@sigprogramming sigprogramming requested review from Hiroshiba and removed request for a team August 25, 2024 03:48
@Hiroshiba
Copy link
Member

プルリクエストありがとうございます!

もしよかったら @sevenc-nanashi さんもレビューいただけると・・・・!!

Copy link
Member

@Hiroshiba Hiroshiba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

すみません、+-2000行が圧巻で、かつアーキテクチャ結構変わっているのでレビューの手がつけづらく 🙇
ということでいくつかお聞きできると・・・!

あ、質問に番号振ってますが、特に順番とかは意識しておらず、知りたい観点を分けてみた次第です!

  1. どこから追っていくのがおすすめでしょうか 👀

RENDER()action? src/sing/phraseRendering.ts
上から見ていく? render()から? Stageから?

  1. 既存のRENDER関数で行っていた処理の流れは変わったか

(ほぼ)変わってないという認識だけど念の為

  1. phraseRenderingの責務範囲

PRのdescriptionに書いてくださってるレンダリングの流れの中のどこがどっちなのかわからない感じです!

RENDER関数側にも結構処理が残ってるので、「フレーズレンダリングの処理全部を移した」ということではなさそう?
キャッシュ用のキー作成部分・キャッシュする部分・エンジンリクエスト等はどちらかなど。
そもそもそういった一連の処理を行うのか、データの依存(順番)だけ制御するのかとか。

  1. Stageとは

phraseごとに持つ? メインプロセスが1つずつ持ってる?
ここがデータの依存関係をうまいこと解決する?
RENDER関数側からはあんまり気にしなくていい?


いろいろ聞いてしまってすみません!設計思想だけ教えていただけると・・・!
(どういう処理を追加・消えたのかや最終的に流れがどうなったかに加え、どういうやり方で整理をつけたのか知りたい感じです)

@sigprogramming
Copy link
Contributor Author

sigprogramming commented Aug 27, 2024

@Hiroshiba
変更行数が多くなりすみません…

  1. Stageとは

Stageは、エンジンリクエスト部分とその周辺の処理をまとめたもので、PhraseRendererが1つずつ持っています。
このPRで実装したステージは以下の3つです。

  1. クエリ生成(フェッチ)ステージ
  2. ボリューム生成ステージ
  3. 音声合成ステージ

これらのステージがこの順序で保持されていることを前提に、フレーズレンダラーが各ステージの処理を呼び出す感じになっています。
キャッシュ用のキー作成部分・キャッシュする部分・エンジンリクエスト(の関数を呼ぶ)等はステージが行います。

以前はrender関数内にひと続きに書いていて、どこまでがクエリ生成に関係する処理で、どこからがボリューム生成に関係する処理なのかが分かりにくくなっていたので、ステージとして分割しました。

  1. phraseRenderingの責務範囲

PhraseRendererはフレーズのレンダリング(各ステージの処理の実行)を制御する責務を負っています。
具体的には以下を行います。

  • 各ステージの処理の実行が必要かどうかのチェックを行う
  • 各ステージの処理を実行する前に、前回のレンダリング結果の削除を行う
  • 各ステージの処理を正しい順序で実行する

例えば、ピッチの編集を行ったときは以下を行います。

  1. 各ステージの処理の実行が必要かどうかをチェック
    → ボリューム生成ステージと音声合成ステージの処理の実行が必要
  2. 前回のレンダリングで生成されたボリュームと音声を削除
  3. ボリューム生成ステージと音声合成ステージの処理を実行

PRのdescriptionに書いてくださってるレンダリングの流れの中のどこがどっちなのかわからない感じです!

以下の2つはPhraseRendererが行う処理で、それ以外はrender関数が行う処理になります!

  • 既存のフレーズの場合、適切なレンダリング開始ステージを決定する
  • フレーズのレンダリングを行う
  1. どこから追っていくのがおすすめでしょうか

ひとまずphraseRendering.tsの型定義を読んで、その後PhraseRendererと各Stageの実装を読んでいくのが良いと思います…!

フレーズレンダラーと各ステージは、SnapshotPhraseからFrameAudioQuery等を生成しPhraseにセットするということを行っています。
queryGenerationStage.execute()の前後で変化するのは以下の3つです。他のステージも同様です。

  • state.phraseQueries ←生成されたクエリがセットされる
  • phrase.queryKey ←生成されたクエリのキーがセットされる
  • queryCache ←生成されたクエリとそのキーがセットされる

state.phraseQueriesはキャッシュではなく(クリアするとバグります)、フレーズのクエリを保持します。
queryCacheはキャッシュ(どのタイミングでクリアしても問題ない)で、これまでに生成されたクエリを保持します。
ボリュームや音声も同様です。

  1. 既存のRENDER関数で行っていた処理の流れは変わったか

以前は音声の再合成が必要な場合、フレーズ更新のタイミングで音声の削除を行っていましたが、このPRではフレーズレンダリングの直前で行うように変更しています。
また、track.singer == undefinedのときにphrase.stateSINGER_IS_NOT_SETになるように変更しています。
それ以外はほぼ変わっていないはずです…!

Copy link
Member

@Hiroshiba Hiroshiba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ほぼLGTMです!!

解説ありがとうございます!!!よくわかりました!!

かなり初見で迷いやすいコードになっているので、ドキュメント足しを提案してみました。
あとはコードのちょっとした提案が主です!

そろそろdocs辺りにソング周りの全体設計を書いた方が良さそうという思いが強くなってきました。
処理の細かい部分は実装を見てもらうことにして、なぜこういう実装になっているのかを数行ずつで紹介していく、みたいなのを想像しました!

(ドキュメントではなく、コードのファイルの一番上に書いてもいいかも。)

src/components/Sing/SequencerPitch.vue Outdated Show resolved Hide resolved
src/sing/phraseRendering.ts Outdated Show resolved Hide resolved
src/sing/phraseRendering.ts Outdated Show resolved Hide resolved
src/sing/phraseRendering.ts Outdated Show resolved Hide resolved
src/sing/phraseRendering.ts Outdated Show resolved Hide resolved
src/store/singing.ts Outdated Show resolved Hide resolved
src/store/singing.ts Show resolved Hide resolved
src/sing/phraseRendering.ts Show resolved Hide resolved
src/sing/phraseRendering.ts Outdated Show resolved Hide resolved
src/sing/phraseRendering.ts Show resolved Hide resolved
@sigprogramming
Copy link
Contributor Author

@Hiroshiba
レビューありがとうございます!
確かにそろそろドキュメントを書いていった方が良さそうですが、タイミング編集機能の実装のためにとりあえずで設計して実装した感じで、要件や設計についての議論をissueで行っていないので、もっと良い設計・モデルにするために議論を行った方が良いかもと思っています。
ひとまずこのPRの設計で一旦タイミング編集機能を実装できればと思います。

@Hiroshiba
Copy link
Member

@sigprogramming ドキュメントに関して了解です!!

議論を重ねてより良いドキュメントを作ればというのもなるほどです!
ただよくよく考えると、設計を議論するためにはそもそも現状の設計を理解する必要があって、そのためにはなんだかんだ今の設計図があると便利かもです 😇 😇 😇
逆に最初は、新規の参入者の方が理解できるような良いドキュメントでなくても、ちょっとソング実装を知っていれば想像できるようなレベルのものでも良さそうかも。

再度レビューしたいと思います!

Copy link
Member

@Hiroshiba Hiroshiba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!!!

リファクタリングありがとうございます!!

@Hiroshiba Hiroshiba merged commit d3904c4 into VOICEVOX:main Sep 3, 2024
9 checks passed
@sigprogramming sigprogramming deleted the refactor_phrase_rendering branch September 8, 2024 14:35
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.

2 participants