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

feat: VST版エディタをマージ #2521

Open
wants to merge 137 commits into
base: main
Choose a base branch
from

Conversation

sevenc-nanashi
Copy link
Member

@sevenc-nanashi sevenc-nanashi commented Feb 6, 2025

内容

自リポジトリのVST版エディタをマージします。

関連 Issue

スクリーンショット・動画など

(なし)

その他

  • project-vstに向ける

@voicevox-preview-pages
Copy link

voicevox-preview-pages bot commented Feb 19, 2025

🚀 プレビュー用ページを作成しました 🚀

更新時点でのコミットハッシュ:43cc349

@sevenc-nanashi sevenc-nanashi changed the base branch from project-vst to main February 20, 2025 07:16
@sevenc-nanashi
Copy link
Member Author

project-vstに向けてるとproject-vstを作ってからのmainのコミットがここに出ちゃうので一旦mainに向けます。マージ直前にproject-vstに向ける感じで。

@@ -135,6 +135,7 @@ export interface Sandbox {
validateEngineDir(engineDir: string): Promise<EngineDirValidationResult>;
reloadApp(obj: { isMultiEngineOffMode?: boolean }): Promise<void>;
getPathForFile(file: File): string;
fetchCachedSingingVoices(): Promise<Record<SingingVoiceKey, SingingVoice>>;
Copy link
Member

Choose a reason for hiding this comment

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

キャッシュについてAI君に聞いてみたら、思った以上に考慮ポイントありそうだったので共有です。
将来的に対応しないといけないかもなので、あとで無理なく実装できるよう今のうちから知っておくと良いかも。
https://chatgpt.com/share/67b9dd73-7840-8008-a794-388584af6283

Comment on lines 248 to 263
async fetchCachedSingingVoices() {
// キャッシュされた歌声を読み込む。
log.info("Loading cached voices");
const encodedVoices = await getVoices();
return Object.fromEntries(
await Promise.all(
Object.entries(encodedVoices).map(
async ([key, encodedVoice]) =>
[
SingingVoiceKey(key),
new Blob([await toBytes(encodedVoice)]),
] satisfies [SingingVoiceKey, SingingVoice],
),
),
);
},
Copy link
Member

@Hiroshiba Hiroshiba Feb 26, 2025

Choose a reason for hiding this comment

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

ここ、ストレージのIOとbase64が絡んでて流石にだいぶ時間かかりそうな気がするので、現段階でなんとかしないといけない気がしています。

とりあえず2点気になってます。

  • 無限にキャッシュがたまり続けてしまう
  • キャッシュが最大まで溜まっているときにどれくらい時間かかるのか

後者は1秒かかるならかなりまずい、くらいの気持ちです。
僕の環境だと立ち絵が開始から3秒くらいで編集可能になるのでこれくらいの基準かなと。特にVSTだとon/offを切り替えるたびにこの秒数かかるので、結構UXにも関わってくるはず?

仮に実装するならどのように実装するのか悩みどころですが、一旦考えを聞けると 🙏

(もしやるなら・・・例えばLRUを導入して、あとファイルごとに保存して、遅延読み込みにするとか・・・?LRUはライブラリ使ってもいいけど、細かい仕様を相当把握しないといけず、そこまでドキュメント書かれてないなら結局コードを読むことになりそうで、自前実装のが楽かもな予感。)

Copy link
Member Author

@sevenc-nanashi sevenc-nanashi Feb 26, 2025

Choose a reason for hiding this comment

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

無限にキャッシュがたまり続けてしまう

フレーズが消えていたらキャッシュも消えます(プラグインでの再生用に保存している波形を起動時に持ってきてる感じ)

キャッシュが最大まで溜まっているときにどれくらい時間かかるのか

3分程度の曲なら差はほとんどありませんでした。

init.mp4
init2.mp4

Copy link
Member

Choose a reason for hiding this comment

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

あーーーなるほどです!!!!セッションが切れるまで前提の設計なんですね!

現状汎用的な機能ではなく、VST専用の機能という感じになりそうですね!
エディタの場合空のプロジェクトファイルから始まるから最初にキャッシュが全部吹き飛んでしまうので。

この認識が合ってそうであれば、vst専用の関数であることをもっとわかりやすい形にしたいかもです。
理想的にはbackendがVSTのときのみfetchCachedSingingVoicesがあるという状況にできると良さそうですが、どうでしょう・・・?

あるいは汎用的な機能を改めて目指すのもとても良いと個人的には思います!
セッションが閉じても大丈夫なように設計し直す感じになるかなと。
だいぶ大変だし別PRが必要そうですが、使い勝手は結構上がるかなぁと。

もしくは、他のソングエディタがプロジェクトファイルに音声を保存してそうであれば、僕達もその方向性を目指すのもありかもです。
実際に作ってみてファイル容量を見るとわかるかも・・・?

ちょっとまた一旦考え聞けると 🙏

Copy link
Member Author

Choose a reason for hiding this comment

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

セッションが切れるまで前提の設計なんですね!

そういうわけでも無いですね。
フレーズの音声は全部vst内のストレージに保存しているので、セッションが切れても(dawを立ち上げ直しても)キャッシュは残ると思います。

Copy link
Member

@Hiroshiba Hiroshiba Feb 26, 2025

Choose a reason for hiding this comment

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

フレーズの音声は全部vst内のストレージに保存しているので、セッションが切れても(dawを立ち上げ直しても)キャッシュは残ると思います。

あれ、なるほど・・・?
あ、これ前提として「vst版は」という理解であってそうでしょうか?
通常エディタで使う場合は実質「セッション切れるまで」・・・?もしくは別のプロジェクトファイルを開いた状態でor空の状態でエディタを閉じるまで・・・?

まあ何にせよここの提案は変わらずです!

Copy link
Member Author

Choose a reason for hiding this comment

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

通常エディタで使う場合は

LRUとか1GB制限とかをつけて全体でキャッシュを作るイメージでした。

Copy link
Member

@Hiroshiba Hiroshiba Feb 26, 2025

Choose a reason for hiding this comment

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

LRUとか1GB制限とかをつけて全体でキャッシュを作るイメージでした。

この場合初期化の際のロードが遅くなるので、たぶん全部持ってくる設計だと難しい気がしてます。
(理由はストレージのIOとbase64が絡んでて流石にだいぶ時間かかりそうな気がする

となるとインターフェイスが変わってくる(個別読み込みが必要)のと、ファイル形式も変えないといけないので、通常エディタ用に拡張できない設計になってるかも?

Copy link
Member Author

Choose a reason for hiding this comment

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

singingVoiceCacheが無い時だけ問い合わせるようにしました。

Copy link
Contributor

Choose a reason for hiding this comment

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

VSTのときはWebAudioAPIでの音声出力はしない方が良いかもです。
(DAWでの音声出力のみ有効になるようにする)
今はAudioContextがundefinedでないこと前提のコードになっているので、一旦別PRでAudioContextがundefinedでも動くようにするのが良いかなと思います。

Comment on lines +2376 to +2388
const cachedSingingVoice = await actions.FETCH_CACHED_SINGING_VOICE(
{
key: singingVoiceKey,
},
);
if (cachedSingingVoice != undefined) {
logger.info(`Loaded singing voice from backend cache.`);
singingVoice = cachedSingingVoice;
} else {
singingVoice = await synthesizeSingingVoice(singingVoiceSource);
logger.info(`Generated singing voice.`);
singingVoiceCache.set(singingVoiceKey, singingVoice);
}
Copy link
Contributor

@sigprogramming sigprogramming Mar 1, 2025

Choose a reason for hiding this comment

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

キャッシュは上の

let singingVoice = singingVoiceCache.get(singingVoiceKey);

で既に取得済みなので、この変更は必要ないかも…?

Copy link
Member Author

Choose a reason for hiding this comment

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

VST版は頻繁にsingingVoiceCacheが吹き飛ぶのでバックエンドにもキャッシュを保存できるようにしよう、がこれですね。

...が、歌い方の方も頻繁に変わるっぽいので意味をなしてないです(どうしたものが)

Copy link
Member

@Hiroshiba Hiroshiba Mar 1, 2025

Choose a reason for hiding this comment

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

VST版は頻繁にsingingVoiceCacheが吹き飛ぶ

補足すると、トラックごとにVSTを起動していて、今表示が不要だとしてそのトラックのVSTウィンドウを消したあとまたウィンドウを開くと、キャッシュが飛んでいるので全部のレンダリングが走り直す、という感じですよね。

歌い方の方も頻繁に変わるっぽいので意味をなしてないです

こーーーーーーーーーーーーーーーーーーれ本当どうしようって感じですね。。。。。。。。

  1. もうキャッシュが吹き飛ぶ(再レンダリングが全て走り直す)のは仕様だとして諦める
    • 毎回レンダリングが走るのは結構重そう。。。
  2. 歌い方含め全てキャッシュを作るようにする
    • 正当手段な気もするけど、かなり大掛かりな気もする
    • まあでも抽象化すればシンプルに見える・・・・・・・・・?
  3. エンジン側にキャッシュを作るようにする
    • 今起きてる問題は色々解消するけど、これが本当に良い設計なんだろうか。。。。
    • エディタとVSTを行き来するときにキャッシュがあって便利、みたいなことはあり得るかも
    • エンジンだけ再起動した時にエディタ側のキャッシュと同期が取れてなくて不都合が起きる、みたいなのとか、そもそもエディター側のキャッシュをどうするのかとか、相当設計を考えないといけないかも
  4. プロジェクトファイルにキャッシュを保存する
    • キャッシュも含めるかどうかを保存関数の引数として渡せるようにする感じ、デフォルトはオフ
    • バイナリファイルを保存できるプロジェクトファイル形式を定義する必要があったり、やっぱり設計が大変

うーーーーーーーーーーーーーーーーーーーーーーーーーーーーーん。
個人的には、そもそもプロジェクトファイルを開き直した時に、完全に同じ音声が得られるべきな気がしてきています。
位相レベルで。と考えると4が妥当なのかもとか思ったり、みたいな感じです。

うーーーん ちょっとどうあるべきかご意見いただけると!!!

(AIリテイクなどのこともあるのでdiscord側にちょっと詳しく書きました。必要とあらばissue作ろうと思います)

Copy link
Member

Choose a reason for hiding this comment

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

更に考えたのですが、人が聞いたときにまあまあ同じに聞こえる音声が返ってくるなら、音声キャッシュは不要な気がしました。
なので4じゃないといけないということはなさそう。

エンジンにキャッシュをもたせる3は避けたほうが良い・・・・・・・かも・・・・?
キャッシュを消す機能とかが将来必要になったりしそうで、考えないといけないことがなんだかんだ増えそう。
まずはエディタに実装して将来エンジンに、とかはあり得るかも。

4のプロジェクトファイル保存は、VST以外で使う人いなさそう!
ということでやるなら2が良さそう・・・・・・・・・?(超自信なし)

Copy link
Contributor

@sigprogramming sigprogramming Mar 1, 2025

Choose a reason for hiding this comment

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

VST版は頻繁にsingingVoiceCacheが吹き飛ぶのでバックエンドにもキャッシュを保存できるようにしよう、がこれですね。

なるほどです!
この実装だとキャッシュの取得経路が2つになるのと、レンダリング処理でVSTの(キャッシュの)ことを意識しないといけなくなってしまうので、エディターが開かれたときにsingingVoiceCacheにキャッシュをセットするのが良いかなと思います。


更に考えたのですが、人が聞いたときにまあまあ同じに聞こえる音声が返ってくるなら、音声キャッシュは不要な気がしました。
なので4じゃないといけないということはなさそう。

discordの方でも書いていますが、位相が変わるとコンプの効きが変わったり位相干渉の発生の仕方が変わったりして、ミックスに結構影響すると思うので、キャッシュ(波形の固定)はあった方が良いと思います。
また、ステレオの場合(パンが振られている場合)はLR(左右)の位相が重要で、LRの位相が少しずれているくらいだと音に広がりが出て良いのですが、LRが逆相だと音が変に聞こえます。(これは聞くだけで結構分かります)

  1. 歌い方含め全てキャッシュを作るようにする
  2. プロジェクトファイルにキャッシュを保存する

私は2と4が良いかなと思っていて(4は2のサブセットになると思います)、今のsinging.tsの実装ではピッチやボリュームもキャッシュするようになっているので、これをVST(Processor側)やプロジェクトファイルに保存し、それを読み込むようにすれば、波形の固定はできるはずです。(少しの変更で実現できるはず)

3は、エディターごと&プロジェクトごとのキャッシュの管理が難しいと思うのと、エンジンのAPIがステートレスではなくなるので、避けた方が良いと思います。

また、レンダリング時間の短縮と波形(テイク)の固定は分けて考えた方が良いと思います。(実現方法は同じかもですが、目的は別なので)

Copy link
Member

@Hiroshiba Hiroshiba Mar 1, 2025

Choose a reason for hiding this comment

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

なるほどです!!
エンジンのキャッシュはとりあえずなしで良さそう感。

(4は2のサブセットになると思います)

あっすみません、2. 歌い方含め全てキャッシュを作るようにするは「全てのキャッシュを作り、PRで提案されている方法のような形でPCにキャッシュを保存する」という意図でした!!
プロジェクトファイルのサブセットではないかもと思ったので、補足です 🙇

キャッシュをプロジェクトファイルに埋め込むの、賛成です。
少なくとも歌い方は保存しないと位相は変わりうる気がします。

この場合、PCにキャッシュを保存するのを実装すべきかどうかちょっと迷いどころかもです。

  • プロジェクトファイルにキャッシュを保存するのは設計が結構大変
    • マイグレーションに配慮が必要
    • 結構容量が増える
      • 秒間100フレームで歌唱区間2分で8桁保存だとすると 2*60*100*8 = 960kB
      • それがf0・volume・複数人歌唱などとなっていくとそこそこな容量になる
      • たぶん圧縮が必要になり、なかなか大変
  • プロジェクトファイルへの保存は不要になる可能性がある
    • シード値を固定する機能が実装されたあと、いろいろ試してみてから必要性判断になる
    • つまり、プロジェクトファイルにキャッシュ保存するかどうかは判断を遅らせたい
  • PCにキャッシュ保存は容量の問題をさほど気にしなくても良い
    • 再レンダリングを減らしたい目的に適してるのはこっち
    • とはいえそのうち容量がすごいことになるので対策は必要
  • PCにキャッシュ保存は破壊的変更が許される
    • 目的が音声の再現ではないため

整理した感じ、今回はPCに保存で、あとあとプロジェクトファイルに保存するか決めるのが良い気がしました!

PCに保存と書いてますが、とりあえずVST(DAW)に保存するコードを書くのでも、まーーーーーー良いかもです!!!
キャッシュを消す機構が要らなくなり、かつ最初に全部読み込めば良いので実装はかなり簡単になるはず。
できれば通常エディタでも使えるようPCに保存だと便利&設計きれいだけど。。という気持ちです!!

Copy link
Member Author

Choose a reason for hiding this comment

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

となると、

  • 歌い方はプロジェクトファイルに保存
  • 音声はbackendに保存

って感じですかね?

Copy link
Member

@Hiroshiba Hiroshiba Mar 2, 2025

Choose a reason for hiding this comment

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

歌い方はプロジェクトファイルに保存

今↑をやると

結構容量が増える
プロジェクトファイルへの保存は不要になる可能性がある

が課題になるなぁと。
なので。。。。この3択・・・・・・・・?

  • エディタ・VSTどちらでもPCに保存・読み込みできるように汎用的に作りつつ、歌い方・音声をキャッシュ
  • DAWファイルに書き込む前提でVST専用に作りつつ、歌い方・音声をキャッシュ
  • いったんキャッシュなし

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.

3 participants