This commit is contained in:
nadare 2023-07-07 08:57:23 +09:00
commit d4f80eeaa8
61 changed files with 2570 additions and 571 deletions

View File

@ -4,6 +4,11 @@
## What's New! ## What's New!
- v.1.5.3.8a
- Bugfix(test): force client device samplerate
- Bugfix: server device filter
- v.1.5.3.8 - v.1.5.3.8
- RVC: performance improvement ([PR](https://github.com/w-okada/voice-changer/pull/371) from [nadare881](https://github.com/nadare881)) - RVC: performance improvement ([PR](https://github.com/w-okada/voice-changer/pull/371) from [nadare881](https://github.com/nadare881))
@ -15,33 +20,6 @@
- Bugfix: - Bugfix:
- device output recorder button is showed in server device mode. - device output recorder button is showed in server device mode.
- v.1.5.3.6a
- some bugfix
- onnx export
- server device mode sampling rate
- server device io record
- improve gui
- dml gpu switch
- v.1.5.3.6
- Integrate Voice Changer model into new GUI
- mac: onnx framework version changed. 1.15.1 -> 1.13.1
- some bugfix
- v.1.5.3.5a
- some bugfix
- onnxcuda: onnx framework version changed. 1.15.1 -> 1.13.1
- rvc quality processing failed.
- model upload issue.
- and others.
- v.1.5.3.5
- RVC: new GUI released. Other VCs will be migrated to the new GUI in stages.
# VC Client とは # VC Client とは
1. 各種音声変換 AI(VC, Voice Conversion)を用いてリアルタイム音声変換を行うためのクライアントソフトウェアです。サポートしている音声変換 AI は次のものになります。 1. 各種音声変換 AI(VC, Voice Conversion)を用いてリアルタイム音声変換を行うためのクライアントソフトウェアです。サポートしている音声変換 AI は次のものになります。
@ -94,26 +72,17 @@
- ダウンロードはこちらから。 - ダウンロードはこちらから。
| Version | OS | フレームワーク | link | サポート VC | サイズ | | Version | OS | フレームワーク | link | サポート VC | サイズ |
| ---------- | --- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------ | | ---------- | --- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------ |
| v.1.5.3.8 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1ptmjFCRDW7M0l80072JVRII5tJpF13__&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB | | v.1.5.3.8a | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1hg6lynE3wWJTNTParTa2qB2L06OL9KJ9&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=19DfeACmpnzqCVH5bIoFunS2pGPABRuso&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB | | | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1C9PCu8pdafO6jJ2yCaB7x54Ls7LcM0Xc&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1AYP_hMdoeacX0KiF31Vd3oEjxwdreSbM&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB | | | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1bzrGhHPc9GdaRAMxkksTGtbuRLEeBx9i&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB |
| v.1.5.3.7 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1HdJwgo0__vR6pAkOkekejUZJ0lu2NfDs&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB | | v.1.5.3.8 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1ptmjFCRDW7M0l80072JVRII5tJpF13__&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1JIF4PvKg-8HNUv_fMaXSM3AeYa-F_c4z&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB | | | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=19DfeACmpnzqCVH5bIoFunS2pGPABRuso&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1cJzRHmD3vk6av0Dvwj3v9Ef5KUsQYhKv&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB | | | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1AYP_hMdoeacX0KiF31Vd3oEjxwdreSbM&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB |
| v.1.5.3.6a | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=14Q2_CPE3mZFU5PIq8RzYwuIX3XSQRTPD&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB | | v.1.5.3.7 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1HdJwgo0__vR6pAkOkekejUZJ0lu2NfDs&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=18iO2JFyytBMFtcBZV5LENEzMGwEmL9H4&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB | | | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1JIF4PvKg-8HNUv_fMaXSM3AeYa-F_c4z&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) \*2 | [normal](https://drive.google.com/uc?id=1PBrIuKQmhM3n1yOBJGgfojCDUt9P9MGa&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB | | | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1cJzRHmD3vk6av0Dvwj3v9Ef5KUsQYhKv&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB |
| v.1.5.3.6 | mac | ONNX(cpu), PyTorch(cpu,mps) | [google](https://drive.google.com/uc?id=1TNCFxx3FKluz-EYV8kutISnp_gbkE43U&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [google](https://drive.google.com/uc?id=1Q36yYVTi1hVUvim2WZFZAEuY4ItR9L9i&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3235MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda)\*2 | [google](https://drive.google.com/uc?id=1tJA7GQA07weSAQofbNax-Y0Wak_zEFlP&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3120MB |
| v.1.5.3.5a | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1CDngewM_1xo8HgJ5oT6qqhhmgUUhiSdz&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 785MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1Tc1qvJIGF79cXCKDnZP4bGYXVg7OgJHp&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3236MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda)\*2 | [normal](https://drive.google.com/uc?id=1dibo9F09V1n6DyBBw0qmBm5hCRoXoo12&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3121MB |
| v.1.5.3.5 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1X4_zYe72yo3RnVHC1G5SZs8CRzlBiMPf&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 785MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1SeMiX3ZSyewsLKDptpRDlVD6j0htpKaJ&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3243MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) \*2 | [normal](https://drive.google.com/uc?id=1FTWrKybOnOKp3yA8PGfQNV-OdyEAqpvx&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3121MB |
(\*1) Google Drive からダウンロードできない方は[hugging_face](https://huggingface.co/wok000/vcclient000/tree/main)からダウンロードしてみてください (\*1) Google Drive からダウンロードできない方は[hugging_face](https://huggingface.co/wok000/vcclient000/tree/main)からダウンロードしてみてください
(\*2) 開発者が AMD のグラフィックボードを持っていないので動作確認していません。onnxruntime-directml を同梱しただけのものです。 (\*2) 開発者が AMD のグラフィックボードを持っていないので動作確認していません。onnxruntime-directml を同梱しただけのものです。

View File

@ -4,6 +4,11 @@
## What's New! ## What's New!
- v.1.5.3.8a
- Bugfix(test): force client device samplerate
- Bugfix: server device filter
- v.1.5.3.8 - v.1.5.3.8
- RVC: performance improvement ([PR](https://github.com/w-okada/voice-changer/pull/371) from [nadare881](https://github.com/nadare881)) - RVC: performance improvement ([PR](https://github.com/w-okada/voice-changer/pull/371) from [nadare881](https://github.com/nadare881))
@ -15,33 +20,6 @@
- Bugfix: - Bugfix:
- device output recorder button is showed in server device mode. - device output recorder button is showed in server device mode.
- v.1.5.3.6a
- some bugfix
- onnx export
- server device mode sampling rate
- server device io record
- improve gui
- dml gpu switch
- v.1.5.3.6
- Integrate Voice Changer model into new GUI
- mac: onnx framework version changed. 1.15.1 -> 1.13.1
- some bugfix
- v.1.5.3.5a
- some bugfix
- onnxcuda: onnx framework version changed. 1.15.1 -> 1.13.1
- rvc quality processing failed.
- model upload issue.
- and others.
- v.1.5.3.5
- RVC: new GUI released. Other VCs will be migrated to the new GUI in stages.
# What is VC Client # What is VC Client
1. This is a client software for performing real-time voice conversion using various Voice Conversion (VC) AI. The supported AI for voice conversion are as follows. 1. This is a client software for performing real-time voice conversion using various Voice Conversion (VC) AI. The supported AI for voice conversion are as follows.
@ -91,26 +69,17 @@ It can be used in two main ways, in order of difficulty:
- Download (When you cannot download from google drive, try [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main)) - Download (When you cannot download from google drive, try [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main))
| Version | OS | Framework | link | support VC | size | | Version | OS | Framework | link | support VC | size |
| ---------- | --- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------ | | ---------- | --- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------ |
| v.1.5.3.8 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1ptmjFCRDW7M0l80072JVRII5tJpF13__&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB | | v.1.5.3.8a | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1hg6lynE3wWJTNTParTa2qB2L06OL9KJ9&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=19DfeACmpnzqCVH5bIoFunS2pGPABRuso&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB | | | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1C9PCu8pdafO6jJ2yCaB7x54Ls7LcM0Xc&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1AYP_hMdoeacX0KiF31Vd3oEjxwdreSbM&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB | | | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1bzrGhHPc9GdaRAMxkksTGtbuRLEeBx9i&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB |
| v.1.5.3.7 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1HdJwgo0__vR6pAkOkekejUZJ0lu2NfDs&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB | | v.1.5.3.8 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1ptmjFCRDW7M0l80072JVRII5tJpF13__&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1JIF4PvKg-8HNUv_fMaXSM3AeYa-F_c4z&export=download) , [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB | | | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=19DfeACmpnzqCVH5bIoFunS2pGPABRuso&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1cJzRHmD3vk6av0Dvwj3v9Ef5KUsQYhKv&export=download) , [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB | | | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1AYP_hMdoeacX0KiF31Vd3oEjxwdreSbM&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB |
| v.1.5.3.6a | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=14Q2_CPE3mZFU5PIq8RzYwuIX3XSQRTPD&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB | | v.1.5.3.7 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1HdJwgo0__vR6pAkOkekejUZJ0lu2NfDs&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=18iO2JFyytBMFtcBZV5LENEzMGwEmL9H4&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB | | | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1JIF4PvKg-8HNUv_fMaXSM3AeYa-F_c4z&export=download) , [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3237MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) \*2 | [normal](https://drive.google.com/uc?id=1PBrIuKQmhM3n1yOBJGgfojCDUt9P9MGa&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB | | | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1cJzRHmD3vk6av0Dvwj3v9Ef5KUsQYhKv&export=download) , [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3122MB |
| v.1.5.3.6 | mac | ONNX(cpu), PyTorch(cpu,mps) | [google](https://drive.google.com/uc?id=1TNCFxx3FKluz-EYV8kutISnp_gbkE43U&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 794MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [google](https://drive.google.com/uc?id=1Q36yYVTi1hVUvim2WZFZAEuY4ItR9L9i&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3235MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) \*2 | [google](https://drive.google.com/uc?id=1tJA7GQA07weSAQofbNax-Y0Wak_zEFlP&export=download), [hugging face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3120MB |
| v.1.5.3.5a | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1CDngewM_1xo8HgJ5oT6qqhhmgUUhiSdz&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 785MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1Tc1qvJIGF79cXCKDnZP4bGYXVg7OgJHp&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3236MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda)\*2 | [normal](https://drive.google.com/uc?id=1dibo9F09V1n6DyBBw0qmBm5hCRoXoo12&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3121MB |
| v.1.5.3.5 | mac | ONNX(cpu), PyTorch(cpu,mps) | [normal](https://drive.google.com/uc?id=1X4_zYe72yo3RnVHC1G5SZs8CRzlBiMPf&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC | 785MB |
| | win | ONNX(cpu,cuda), PyTorch(cpu,cuda) | [normal](https://drive.google.com/uc?id=1SeMiX3ZSyewsLKDptpRDlVD6j0htpKaJ&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3243MB |
| | win | ONNX(cpu,DirectML), PyTorch(cpu,cuda) \*2 | [normal](https://drive.google.com/uc?id=1FTWrKybOnOKp3yA8PGfQNV-OdyEAqpvx&export=download), [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) | MMVC v.1.5.x, MMVC v.1.3.x, so-vits-svc 4.0, RVC, DDSP-SVC | 3121MB |
(\*1) You can also download from [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main) (\*1) You can also download from [hugging_face](https://huggingface.co/wok000/vcclient000/tree/main)
(\*2) The developer does not have an AMD graphics card, so it has not been tested. This package only includes onnxruntime-directml. (\*2) The developer does not have an AMD graphics card, so it has not been tested. This package only includes onnxruntime-directml.

View File

@ -21,7 +21,7 @@
{ {
"name": "configArea", "name": "configArea",
"options": { "options": {
"detectors": ["dio", "harvest", "crepe"], "detectors": ["dio", "harvest", "crepe", "crepe_full", "crepe_tiny"],
"inputChunkNums": [8, 16, 24, 32, 40, 48, 64, 80, 96, 112, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 2048] "inputChunkNums": [8, 16, 24, 32, 40, 48, 64, 80, 96, 112, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 2048]
} }
} }

View File

@ -1 +1,10 @@
<!doctype html><html style="width:100%;height:100%;overflow:hidden"><head><meta charset="utf-8"/><title>Voice Changer Client Demo</title><script defer="defer" src="index.js"></script></head><body style="width:100%;height:100%;margin:0"><div id="app" style="width:100%;height:100%"></div></body></html> <!DOCTYPE html>
<html style="width: 100%; height: 100%; overflow: hidden">
<head>
<meta charset="utf-8" />
<title>Voice Changer Client Demo</title>
<script defer src="index.js"></script></head>
<body style="width: 100%; height: 100%; margin: 0px">
<div id="app" style="width: 100%; height: 100%"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,31 +0,0 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

View File

@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@dannadori/voice-changer-client-js": "^1.0.157", "@dannadori/voice-changer-client-js": "^1.0.159",
"@fortawesome/fontawesome-svg-core": "^6.4.0", "@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-brands-svg-icons": "^6.4.0", "@fortawesome/free-brands-svg-icons": "^6.4.0",
"@fortawesome/free-regular-svg-icons": "^6.4.0", "@fortawesome/free-regular-svg-icons": "^6.4.0",
@ -19,9 +19,9 @@
"react-dom": "^18.2.0" "react-dom": "^18.2.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.22.5", "@babel/core": "^7.22.6",
"@babel/plugin-transform-runtime": "^7.22.5", "@babel/plugin-transform-runtime": "^7.22.6",
"@babel/preset-env": "^7.22.5", "@babel/preset-env": "^7.22.6",
"@babel/preset-react": "^7.22.5", "@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.5", "@babel/preset-typescript": "^7.22.5",
"@types/node": "^20.3.3", "@types/node": "^20.3.3",
@ -888,35 +888,35 @@
} }
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz",
"integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", "integrity": "sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.6.tgz",
"integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", "integrity": "sha512-HPIyDa6n+HKw5dEuway3vVAhBboYCtREBMp+IWeseZy6TFtzn6MHkCH2KKYUOC/vKKwgSMHQW4htBOrmuRPXfw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.22.5", "@babel/code-frame": "^7.22.5",
"@babel/generator": "^7.22.5", "@babel/generator": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5", "@babel/helper-compilation-targets": "^7.22.6",
"@babel/helper-module-transforms": "^7.22.5", "@babel/helper-module-transforms": "^7.22.5",
"@babel/helpers": "^7.22.5", "@babel/helpers": "^7.22.6",
"@babel/parser": "^7.22.5", "@babel/parser": "^7.22.6",
"@babel/template": "^7.22.5", "@babel/template": "^7.22.5",
"@babel/traverse": "^7.22.5", "@babel/traverse": "^7.22.6",
"@babel/types": "^7.22.5", "@babel/types": "^7.22.5",
"@nicolo-ribaudo/semver-v6": "^6.3.3",
"convert-source-map": "^1.7.0", "convert-source-map": "^1.7.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
"json5": "^2.2.2", "json5": "^2.2.2"
"semver": "^6.3.0"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -966,16 +966,16 @@
} }
}, },
"node_modules/@babel/helper-compilation-targets": { "node_modules/@babel/helper-compilation-targets": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz",
"integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", "integrity": "sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.22.5", "@babel/compat-data": "^7.22.6",
"@babel/helper-validator-option": "^7.22.5", "@babel/helper-validator-option": "^7.22.5",
"browserslist": "^4.21.3", "@nicolo-ribaudo/semver-v6": "^6.3.3",
"lru-cache": "^5.1.1", "browserslist": "^4.21.9",
"semver": "^6.3.0" "lru-cache": "^5.1.1"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -985,9 +985,9 @@
} }
}, },
"node_modules/@babel/helper-create-class-features-plugin": { "node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.6.tgz",
"integrity": "sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==", "integrity": "sha512-iwdzgtSiBxF6ni6mzVnZCF3xt5qE6cEA0J7nFt8QOAWZ0zjCFceEgpn3vtb2V7WFR6QzP2jmIFOHMTRo7eNJjQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-annotate-as-pure": "^7.22.5",
@ -997,8 +997,8 @@
"@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-optimise-call-expression": "^7.22.5",
"@babel/helper-replace-supers": "^7.22.5", "@babel/helper-replace-supers": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6",
"semver": "^6.3.0" "@nicolo-ribaudo/semver-v6": "^6.3.3"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1008,14 +1008,14 @@
} }
}, },
"node_modules/@babel/helper-create-regexp-features-plugin": { "node_modules/@babel/helper-create-regexp-features-plugin": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.6.tgz",
"integrity": "sha512-1VpEFOIbMRaXyDeUwUfmTIxExLwQ+zkW+Bh5zXpApA3oQedBx9v/updixWxnx/bZpKw7u8VxWjb/qWpIcmPq8A==", "integrity": "sha512-nBookhLKxAWo/TUCmhnaEJyLz2dekjQvv5SRpE9epWQBcpedWLKt8aZdsuT9XV5ovzR3fENLjRXVT0GsSlGGhA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-annotate-as-pure": "^7.22.5",
"regexpu-core": "^5.3.1", "@nicolo-ribaudo/semver-v6": "^6.3.3",
"semver": "^6.3.0" "regexpu-core": "^5.3.1"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1199,9 +1199,9 @@
} }
}, },
"node_modules/@babel/helper-split-export-declaration": { "node_modules/@babel/helper-split-export-declaration": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/types": "^7.22.5" "@babel/types": "^7.22.5"
@ -1253,13 +1253,13 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
"integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/template": "^7.22.5", "@babel/template": "^7.22.5",
"@babel/traverse": "^7.22.5", "@babel/traverse": "^7.22.6",
"@babel/types": "^7.22.5" "@babel/types": "^7.22.5"
}, },
"engines": { "engines": {
@ -1281,9 +1281,9 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.6.tgz",
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", "integrity": "sha512-EIQu22vNkceq3LbjAq7knDf/UmtI2qbcNI8GRBlijez6TpQLvSodJPYfydQmNA5buwkxxxa/PVI44jjYZ+/cLw==",
"dev": true, "dev": true,
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@ -1731,19 +1731,19 @@
} }
}, },
"node_modules/@babel/plugin-transform-classes": { "node_modules/@babel/plugin-transform-classes": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz",
"integrity": "sha512-2edQhLfibpWpsVBx2n/GKOz6JdGQvLruZQfGr9l1qes2KQaWswjBzhQF7UDUZMNaMMQeYnQzxwOMPsbYF7wqPQ==", "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5", "@babel/helper-compilation-targets": "^7.22.6",
"@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5", "@babel/helper-function-name": "^7.22.5",
"@babel/helper-optimise-call-expression": "^7.22.5", "@babel/helper-optimise-call-expression": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-replace-supers": "^7.22.5", "@babel/helper-replace-supers": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
"engines": { "engines": {
@ -2139,9 +2139,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-optional-chaining": { "node_modules/@babel/plugin-transform-optional-chaining": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz",
"integrity": "sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==", "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5",
@ -2316,17 +2316,17 @@
} }
}, },
"node_modules/@babel/plugin-transform-runtime": { "node_modules/@babel/plugin-transform-runtime": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.6.tgz",
"integrity": "sha512-bg4Wxd1FWeFx3daHFTWk1pkSWK/AyQuiyAoeZAOkAOUBjnZPH6KT7eMxouV47tQ6hl6ax2zyAWBdWZXbrvXlaw==", "integrity": "sha512-+AGkst7Kqq3QUflKGkhWWMRb9vaKamoreNmYc+sjsIpOp+TsyU0exhp3RlwjQa/HdlKkPt3AMDwfg8Hpt9Vwqg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-module-imports": "^7.22.5", "@babel/helper-module-imports": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5",
"@nicolo-ribaudo/semver-v6": "^6.3.3",
"babel-plugin-polyfill-corejs2": "^0.4.3", "babel-plugin-polyfill-corejs2": "^0.4.3",
"babel-plugin-polyfill-corejs3": "^0.8.1", "babel-plugin-polyfill-corejs3": "^0.8.1",
"babel-plugin-polyfill-regenerator": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.5.0"
"semver": "^6.3.0"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -2493,13 +2493,13 @@
} }
}, },
"node_modules/@babel/preset-env": { "node_modules/@babel/preset-env": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.6.tgz",
"integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", "integrity": "sha512-IHr0AXHGk8oh8HYSs45Mxuv6iySUBwDTIzJSnXN7PURqHdxJVQlCoXmKJgyvSS9bcNf9NVRVE35z+LkCvGmi6w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.22.5", "@babel/compat-data": "^7.22.6",
"@babel/helper-compilation-targets": "^7.22.5", "@babel/helper-compilation-targets": "^7.22.6",
"@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-validator-option": "^7.22.5", "@babel/helper-validator-option": "^7.22.5",
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5",
@ -2530,7 +2530,7 @@
"@babel/plugin-transform-block-scoping": "^7.22.5", "@babel/plugin-transform-block-scoping": "^7.22.5",
"@babel/plugin-transform-class-properties": "^7.22.5", "@babel/plugin-transform-class-properties": "^7.22.5",
"@babel/plugin-transform-class-static-block": "^7.22.5", "@babel/plugin-transform-class-static-block": "^7.22.5",
"@babel/plugin-transform-classes": "^7.22.5", "@babel/plugin-transform-classes": "^7.22.6",
"@babel/plugin-transform-computed-properties": "^7.22.5", "@babel/plugin-transform-computed-properties": "^7.22.5",
"@babel/plugin-transform-destructuring": "^7.22.5", "@babel/plugin-transform-destructuring": "^7.22.5",
"@babel/plugin-transform-dotall-regex": "^7.22.5", "@babel/plugin-transform-dotall-regex": "^7.22.5",
@ -2555,7 +2555,7 @@
"@babel/plugin-transform-object-rest-spread": "^7.22.5", "@babel/plugin-transform-object-rest-spread": "^7.22.5",
"@babel/plugin-transform-object-super": "^7.22.5", "@babel/plugin-transform-object-super": "^7.22.5",
"@babel/plugin-transform-optional-catch-binding": "^7.22.5", "@babel/plugin-transform-optional-catch-binding": "^7.22.5",
"@babel/plugin-transform-optional-chaining": "^7.22.5", "@babel/plugin-transform-optional-chaining": "^7.22.6",
"@babel/plugin-transform-parameters": "^7.22.5", "@babel/plugin-transform-parameters": "^7.22.5",
"@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-methods": "^7.22.5",
"@babel/plugin-transform-private-property-in-object": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.5",
@ -2573,11 +2573,11 @@
"@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/plugin-transform-unicode-sets-regex": "^7.22.5",
"@babel/preset-modules": "^0.1.5", "@babel/preset-modules": "^0.1.5",
"@babel/types": "^7.22.5", "@babel/types": "^7.22.5",
"@nicolo-ribaudo/semver-v6": "^6.3.3",
"babel-plugin-polyfill-corejs2": "^0.4.3", "babel-plugin-polyfill-corejs2": "^0.4.3",
"babel-plugin-polyfill-corejs3": "^0.8.1", "babel-plugin-polyfill-corejs3": "^0.8.1",
"babel-plugin-polyfill-regenerator": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.5.0",
"core-js-compat": "^3.30.2", "core-js-compat": "^3.31.0"
"semver": "^6.3.0"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -2648,9 +2648,9 @@
"dev": true "dev": true
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz",
"integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.13.11" "regenerator-runtime": "^0.13.11"
@ -2674,9 +2674,9 @@
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.22.5", "version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.6.tgz",
"integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", "integrity": "sha512-53CijMvKlLIDlOTrdWiHileRddlIiwUIyCKqYa7lYnnPldXCG5dUSN38uT0cA6i7rHWNKJLH0VU/Kxdr1GzB3w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.22.5", "@babel/code-frame": "^7.22.5",
@ -2684,8 +2684,8 @@
"@babel/helper-environment-visitor": "^7.22.5", "@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5", "@babel/helper-function-name": "^7.22.5",
"@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.22.5", "@babel/parser": "^7.22.6",
"@babel/types": "^7.22.5", "@babel/types": "^7.22.5",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
@ -2709,9 +2709,9 @@
} }
}, },
"node_modules/@dannadori/voice-changer-client-js": { "node_modules/@dannadori/voice-changer-client-js": {
"version": "1.0.157", "version": "1.0.159",
"resolved": "https://registry.npmjs.org/@dannadori/voice-changer-client-js/-/voice-changer-client-js-1.0.157.tgz", "resolved": "https://registry.npmjs.org/@dannadori/voice-changer-client-js/-/voice-changer-client-js-1.0.159.tgz",
"integrity": "sha512-KIqgMM3cvB3ZCTLFJyfqWypMJZqFNTExTxoKO/BxqnG02EPG+AsHIHZE0bdTZEg1ss1tba/QMnWsoZ5FQW5YQQ==", "integrity": "sha512-QQLh/djAm1FPcIUacxBhXGRlbCn6POpxTd8Wmc195I9MbtEqy+9mXmGBG5+du1ohGL7HmoHkvLmgB0nlKGLoZw==",
"dependencies": { "dependencies": {
"@types/readable-stream": "^2.3.15", "@types/readable-stream": "^2.3.15",
"amazon-chime-sdk-js": "^3.15.0", "amazon-chime-sdk-js": "^3.15.0",
@ -2949,24 +2949,24 @@
} }
}, },
"node_modules/@jest/schemas": { "node_modules/@jest/schemas": {
"version": "29.4.3", "version": "29.6.0",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz",
"integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@sinclair/typebox": "^0.25.16" "@sinclair/typebox": "^0.27.8"
}, },
"engines": { "engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0" "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
} }
}, },
"node_modules/@jest/types": { "node_modules/@jest/types": {
"version": "29.5.0", "version": "29.6.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.0.tgz",
"integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "integrity": "sha512-8XCgL9JhqbJTFnMRjEAO+TuW251+MoMd5BSzLiE3vvzpQ8RlBxy8NoyNkDhs3K3OL3HeVinlOl9or5p7GTeOLg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@jest/schemas": "^29.4.3", "@jest/schemas": "^29.6.0",
"@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0", "@types/istanbul-reports": "^3.0.0",
"@types/node": "*", "@types/node": "*",
@ -3080,10 +3080,14 @@
} }
}, },
"node_modules/@jridgewell/source-map": { "node_modules/@jridgewell/source-map": {
"version": "0.3.4", "version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.4.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
"integrity": "sha512-KE/SxsDqNs3rrWwFHcRh15ZLVFrI0YoZtgAdIyIq9k5hUNmiWRXXThPomIxHuL20sLdgzbDFyvkUMna14bvtrw==", "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
"dev": true "dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
}, },
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15", "version": "1.4.15",
@ -3113,6 +3117,15 @@
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
"dev": true "dev": true
}, },
"node_modules/@nicolo-ribaudo/semver-v6": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
"integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -3213,9 +3226,9 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
}, },
"node_modules/@sinclair/typebox": { "node_modules/@sinclair/typebox": {
"version": "0.25.24", "version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
"integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
"dev": true "dev": true
}, },
"node_modules/@smithy/abort-controller": { "node_modules/@smithy/abort-controller": {
@ -4977,9 +4990,9 @@
"dev": true "dev": true
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001509", "version": "1.0.30001512",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz",
"integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==", "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -5670,9 +5683,9 @@
"dev": true "dev": true
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.447", "version": "1.4.450",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.447.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.450.tgz",
"integrity": "sha512-sxX0LXh+uL41hSJsujAN86PjhrV/6c79XmpY0TvjZStV6VxIgarf8SRkUoUTuYmFcZQTemsoqo8qXOGw5npWfw==", "integrity": "sha512-BLG5HxSELlrMx7dJ2s+8SFlsCtJp37Zpk2VAxyC6CZtbc+9AJeZHfYHbrlSgdXp6saQ8StMqOTEDaBKgA7u1sw==",
"dev": true "dev": true
}, },
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
@ -6888,9 +6901,9 @@
} }
}, },
"node_modules/globby": { "node_modules/globby": {
"version": "13.2.0", "version": "13.2.1",
"resolved": "https://registry.npmjs.org/globby/-/globby-13.2.0.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.1.tgz",
"integrity": "sha512-jWsQfayf13NvqKUIL3Ta+CIqMnvlaIDFveWE/dpOZ9+3AMEJozsxDvKA02zync9UuvOM8rOXzsD5GqKP4OnWPQ==", "integrity": "sha512-DPCBxctI7dN4EeIqjW2KGqgdcUMbrhJ9AzON+PlxCtvppWhubTLD4+a0GFxiym14ZvacUydTPjLPc2DlKz7EIg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"dir-glob": "^3.0.1", "dir-glob": "^3.0.1",
@ -7796,12 +7809,12 @@
} }
}, },
"node_modules/jest-util": { "node_modules/jest-util": {
"version": "29.5.0", "version": "29.6.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.0.tgz",
"integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "integrity": "sha512-S0USx9YwcvEm4pQ5suisVm/RVxBmi0GFR7ocJhIeaCuW5AXnAnffXbaVKvIFodyZNOc9ygzVtTxmBf40HsHXaA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@jest/types": "^29.5.0", "@jest/types": "^29.6.0",
"@types/node": "*", "@types/node": "*",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"ci-info": "^3.2.0", "ci-info": "^3.2.0",
@ -7883,13 +7896,13 @@
} }
}, },
"node_modules/jest-worker": { "node_modules/jest-worker": {
"version": "29.5.0", "version": "29.6.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.0.tgz",
"integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "integrity": "sha512-oiQHH1SnKmZIwwPnpOrXTq4kHBk3lKGY/07DpnH0sAu+x7J8rXlbLDROZsU6vy9GwB0hPiZeZpu6YlJ48QoKcA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
"jest-util": "^29.5.0", "jest-util": "^29.6.0",
"merge-stream": "^2.0.0", "merge-stream": "^2.0.0",
"supports-color": "^8.0.0" "supports-color": "^8.0.0"
}, },
@ -7922,9 +7935,9 @@
} }
}, },
"node_modules/jiti": { "node_modules/jiti": {
"version": "1.18.2", "version": "1.19.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
"integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==",
"dev": true, "dev": true,
"bin": { "bin": {
"jiti": "bin/jiti.js" "jiti": "bin/jiti.js"

View File

@ -21,9 +21,9 @@
"author": "wataru.okada@flect.co.jp", "author": "wataru.okada@flect.co.jp",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.22.5", "@babel/core": "^7.22.6",
"@babel/plugin-transform-runtime": "^7.22.5", "@babel/plugin-transform-runtime": "^7.22.6",
"@babel/preset-env": "^7.22.5", "@babel/preset-env": "^7.22.6",
"@babel/preset-react": "^7.22.5", "@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.5", "@babel/preset-typescript": "^7.22.5",
"@types/node": "^20.3.3", "@types/node": "^20.3.3",
@ -54,7 +54,7 @@
"webpack-dev-server": "^4.15.1" "webpack-dev-server": "^4.15.1"
}, },
"dependencies": { "dependencies": {
"@dannadori/voice-changer-client-js": "^1.0.157", "@dannadori/voice-changer-client-js": "^1.0.159",
"@fortawesome/fontawesome-svg-core": "^6.4.0", "@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-brands-svg-icons": "^6.4.0", "@fortawesome/free-brands-svg-icons": "^6.4.0",
"@fortawesome/free-regular-svg-icons": "^6.4.0", "@fortawesome/free-regular-svg-icons": "^6.4.0",

View File

@ -21,7 +21,7 @@
{ {
"name": "configArea", "name": "configArea",
"options": { "options": {
"detectors": ["dio", "harvest", "crepe"], "detectors": ["dio", "harvest", "crepe", "crepe_full", "crepe_tiny"],
"inputChunkNums": [8, 16, 24, 32, 40, 48, 64, 80, 96, 112, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 2048] "inputChunkNums": [8, 16, 24, 32, 40, 48, 64, 80, 96, 112, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 2048]
} }
} }

View File

@ -3,15 +3,34 @@ import { useEffect, useState } from "react"
export type AudioConfigState = { export type AudioConfigState = {
audioContext: AudioContext | null audioContext: AudioContext | null
} }
export const useAudioConfig = (): AudioConfigState => { export const useAudioConfig = (): AudioConfigState => {
const [audioContext, setAudioContext] = useState<AudioContext | null>(null) const [audioContext, setAudioContext] = useState<AudioContext | null>(null)
useEffect(() => { useEffect(() => {
const createAudioContext = () => { const createAudioContext = () => {
const ctx = new AudioContext()
const url = new URL(window.location.href);
const params = url.searchParams;
const sampleRate = params.get('sample_rate') || null
let ctx: AudioContext
if(sampleRate){
if(sampleRate == "default"){
console.log(`Sample rate: default`)
ctx = new AudioContext()
}else{
console.log(`Sample rate: ${sampleRate}`)
ctx = new AudioContext({ sampleRate: Number(sampleRate)})
}
}else{
console.log(`Sample rate: default(48000)`)
ctx = new AudioContext({ sampleRate: 48000})
}
console.log(ctx)
setAudioContext(ctx)
document.removeEventListener('touchstart', createAudioContext); document.removeEventListener('touchstart', createAudioContext);
document.removeEventListener('mousedown', createAudioContext); document.removeEventListener('mousedown', createAudioContext);
setAudioContext(ctx)
} }
document.addEventListener('touchstart', createAudioContext, false); document.addEventListener('touchstart', createAudioContext, false);
document.addEventListener('mousedown', createAudioContext, false); document.addEventListener('mousedown', createAudioContext, false);

View File

@ -12,7 +12,6 @@ export const useVCClient = (props: UseVCClientProps): VCClientState => {
const clientState = useClient({ const clientState = useClient({
audioContext: props.audioContext audioContext: props.audioContext
}) })
console.log("useVCClient", props.audioContext)
const ret: VCClientState = { const ret: VCClientState = {
clientState clientState

View File

@ -3,76 +3,78 @@ import { ReactNode } from "react";
import { useAppRoot } from "../../001_provider/001_AppRootProvider"; import { useAppRoot } from "../../001_provider/001_AppRootProvider";
import { StateControlCheckbox, useStateControlCheckbox } from "../../hooks/useStateControlCheckbox"; import { StateControlCheckbox, useStateControlCheckbox } from "../../hooks/useStateControlCheckbox";
export const OpenServerControlCheckbox = "open-server-control-checkbox" export const OpenServerControlCheckbox = "open-server-control-checkbox";
export const OpenModelSettingCheckbox = "open-model-setting-checkbox" export const OpenModelSettingCheckbox = "open-model-setting-checkbox";
export const OpenDeviceSettingCheckbox = "open-device-setting-checkbox" export const OpenDeviceSettingCheckbox = "open-device-setting-checkbox";
export const OpenQualityControlCheckbox = "open-quality-control-checkbox" export const OpenQualityControlCheckbox = "open-quality-control-checkbox";
export const OpenSpeakerSettingCheckbox = "open-speaker-setting-checkbox" export const OpenSpeakerSettingCheckbox = "open-speaker-setting-checkbox";
export const OpenConverterSettingCheckbox = "open-converter-setting-checkbox" export const OpenConverterSettingCheckbox = "open-converter-setting-checkbox";
export const OpenAdvancedSettingCheckbox = "open-advanced-setting-checkbox" export const OpenAdvancedSettingCheckbox = "open-advanced-setting-checkbox";
export const OpenLabCheckbox = "open-lab-checkbox" export const OpenLabCheckbox = "open-lab-checkbox";
export const OpenLicenseDialogCheckbox = "open-license-dialog-checkbox" export const OpenLicenseDialogCheckbox = "open-license-dialog-checkbox";
export const OpenWaitingDialogCheckbox = "open-waiting-dialog-checkbox" export const OpenWaitingDialogCheckbox = "open-waiting-dialog-checkbox";
export const OpenStartingNoticeDialogCheckbox = "open-starting-notice-dialog-checkbox" export const OpenStartingNoticeDialogCheckbox = "open-starting-notice-dialog-checkbox";
export const OpenModelSlotManagerDialogCheckbox = "open-model-slot-manager-dialog-checkbox" export const OpenModelSlotManagerDialogCheckbox = "open-model-slot-manager-dialog-checkbox";
export const OpenMergeLabDialogCheckbox = "open-merge-lab-dialog-checkbox" export const OpenMergeLabDialogCheckbox = "open-merge-lab-dialog-checkbox";
export const OpenAdvancedSettingDialogCheckbox = "open-advanced-setting-dialog-checkbox" export const OpenAdvancedSettingDialogCheckbox = "open-advanced-setting-dialog-checkbox";
export const OpenGetServerInformationDialogCheckbox = "open-get-server-information-dialog-checkbox" export const OpenGetServerInformationDialogCheckbox = "open-get-server-information-dialog-checkbox";
export const OpenGetClientInformationDialogCheckbox = "open-get-client-information-dialog-checkbox";
export const OpenTextInputDialogCheckbox = "open-text-input-dialog-checkbox" export const OpenTextInputDialogCheckbox = "open-text-input-dialog-checkbox";
type Props = { type Props = {
children: ReactNode; children: ReactNode;
}; };
export type StateControls = { export type StateControls = {
openServerControlCheckbox: StateControlCheckbox openServerControlCheckbox: StateControlCheckbox;
openModelSettingCheckbox: StateControlCheckbox openModelSettingCheckbox: StateControlCheckbox;
openDeviceSettingCheckbox: StateControlCheckbox openDeviceSettingCheckbox: StateControlCheckbox;
openQualityControlCheckbox: StateControlCheckbox openQualityControlCheckbox: StateControlCheckbox;
openSpeakerSettingCheckbox: StateControlCheckbox openSpeakerSettingCheckbox: StateControlCheckbox;
openConverterSettingCheckbox: StateControlCheckbox openConverterSettingCheckbox: StateControlCheckbox;
openAdvancedSettingCheckbox: StateControlCheckbox openAdvancedSettingCheckbox: StateControlCheckbox;
openLabCheckbox: StateControlCheckbox openLabCheckbox: StateControlCheckbox;
showWaitingCheckbox: StateControlCheckbox showWaitingCheckbox: StateControlCheckbox;
showStartingNoticeCheckbox: StateControlCheckbox showStartingNoticeCheckbox: StateControlCheckbox;
showModelSlotManagerCheckbox: StateControlCheckbox showModelSlotManagerCheckbox: StateControlCheckbox;
showMergeLabCheckbox: StateControlCheckbox showMergeLabCheckbox: StateControlCheckbox;
showAdvancedSettingCheckbox: StateControlCheckbox showAdvancedSettingCheckbox: StateControlCheckbox;
showGetServerInformationCheckbox: StateControlCheckbox showGetServerInformationCheckbox: StateControlCheckbox;
showTextInputCheckbox: StateControlCheckbox showGetClientInformationCheckbox: StateControlCheckbox;
} showTextInputCheckbox: StateControlCheckbox;
};
type GuiStateAndMethod = { type GuiStateAndMethod = {
stateControls: StateControls stateControls: StateControls;
isConverting: boolean, isConverting: boolean;
isAnalyzing: boolean, isAnalyzing: boolean;
showPyTorchModelUpload: boolean showPyTorchModelUpload: boolean;
setIsConverting: (val: boolean) => void setIsConverting: (val: boolean) => void;
setIsAnalyzing: (val: boolean) => void setIsAnalyzing: (val: boolean) => void;
setShowPyTorchModelUpload: (val: boolean) => void setShowPyTorchModelUpload: (val: boolean) => void;
inputAudioDeviceInfo: MediaDeviceInfo[] inputAudioDeviceInfo: MediaDeviceInfo[];
outputAudioDeviceInfo: MediaDeviceInfo[] outputAudioDeviceInfo: MediaDeviceInfo[];
audioInputForGUI: string audioInputForGUI: string;
audioOutputForGUI: string audioOutputForGUI: string;
fileInputEchoback: boolean | undefined fileInputEchoback: boolean | undefined;
audioOutputForAnalyzer: string audioOutputForAnalyzer: string;
setInputAudioDeviceInfo: (val: MediaDeviceInfo[]) => void setInputAudioDeviceInfo: (val: MediaDeviceInfo[]) => void;
setOutputAudioDeviceInfo: (val: MediaDeviceInfo[]) => void setOutputAudioDeviceInfo: (val: MediaDeviceInfo[]) => void;
setAudioInputForGUI: (val: string) => void setAudioInputForGUI: (val: string) => void;
setAudioOutputForGUI: (val: string) => void setAudioOutputForGUI: (val: string) => void;
setFileInputEchoback: (val: boolean) => void setFileInputEchoback: (val: boolean) => void;
setAudioOutputForAnalyzer: (val: string) => void setAudioOutputForAnalyzer: (val: string) => void;
modelSlotNum: number modelSlotNum: number;
setModelSlotNum: (val: number) => void setModelSlotNum: (val: number) => void;
textInputResolve: TextInputResolveType | null textInputResolve: TextInputResolveType | null;
setTextInputResolve: (val: TextInputResolveType | null) => void setTextInputResolve: (val: TextInputResolveType | null) => void;
} };
const GuiStateContext = React.createContext<GuiStateAndMethod | null>(null); const GuiStateContext = React.createContext<GuiStateAndMethod | null>(null);
export const useGuiState = (): GuiStateAndMethod => { export const useGuiState = (): GuiStateAndMethod => {
@ -84,59 +86,64 @@ export const useGuiState = (): GuiStateAndMethod => {
}; };
type TextInputResolveType = { type TextInputResolveType = {
resolve: ((value: string | PromiseLike<string>) => void) | null resolve: ((value: string | PromiseLike<string>) => void) | null;
} };
export const GuiStateProvider = ({ children }: Props) => { export const GuiStateProvider = ({ children }: Props) => {
const { appGuiSettingState } = useAppRoot() const { appGuiSettingState } = useAppRoot();
const [isConverting, setIsConverting] = useState<boolean>(false) const [isConverting, setIsConverting] = useState<boolean>(false);
const [isAnalyzing, setIsAnalyzing] = useState<boolean>(false) const [isAnalyzing, setIsAnalyzing] = useState<boolean>(false);
const [modelSlotNum, setModelSlotNum] = useState<number>(0) const [modelSlotNum, setModelSlotNum] = useState<number>(0);
const [showPyTorchModelUpload, setShowPyTorchModelUpload] = useState<boolean>(false) const [showPyTorchModelUpload, setShowPyTorchModelUpload] = useState<boolean>(false);
const [inputAudioDeviceInfo, setInputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([]);
const [outputAudioDeviceInfo, setOutputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([]);
const [audioInputForGUI, setAudioInputForGUI] = useState<string>("none");
const [audioOutputForGUI, setAudioOutputForGUI] = useState<string>("none");
const [fileInputEchoback, setFileInputEchoback] = useState<boolean>(false); //最初のmuteが有効になるように。undefined <-- ??? falseしておけばよさそう。undefinedだとwarningがでる。
const [audioOutputForAnalyzer, setAudioOutputForAnalyzer] = useState<string>("default");
const [inputAudioDeviceInfo, setInputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([]) const [textInputResolve, setTextInputResolve] = useState<TextInputResolveType | null>(null);
const [outputAudioDeviceInfo, setOutputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([])
const [audioInputForGUI, setAudioInputForGUI] = useState<string>("none")
const [audioOutputForGUI, setAudioOutputForGUI] = useState<string>("none")
const [fileInputEchoback, setFileInputEchoback] = useState<boolean>(false)//最初のmuteが有効になるように。undefined <-- ??? falseしておけばよさそう。undefinedだとwarningがでる。
const [audioOutputForAnalyzer, setAudioOutputForAnalyzer] = useState<string>("default")
const [textInputResolve, setTextInputResolve] = useState<TextInputResolveType | null>(null)
const reloadDeviceInfo = async () => { const reloadDeviceInfo = async () => {
try { try {
const ms = await navigator.mediaDevices.getUserMedia({ video: false, audio: true }); const ms = await navigator.mediaDevices.getUserMedia({ video: false, audio: true });
ms.getTracks().forEach(x => { x.stop() }) ms.getTracks().forEach((x) => {
x.stop();
});
} catch (e) { } catch (e) {
console.warn("Enumerate device error::", e) console.warn("Enumerate device error::", e);
} }
const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices(); const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices();
const audioInputs = mediaDeviceInfos.filter(x => { return x.kind == "audioinput" }) const audioInputs = mediaDeviceInfos.filter((x) => {
return x.kind == "audioinput";
});
audioInputs.push({ audioInputs.push({
deviceId: "none", deviceId: "none",
groupId: "none", groupId: "none",
kind: "audioinput", kind: "audioinput",
label: "none", label: "none",
toJSON: () => { } toJSON: () => {},
}) });
audioInputs.push({ audioInputs.push({
deviceId: "file", deviceId: "file",
groupId: "file", groupId: "file",
kind: "audioinput", kind: "audioinput",
label: "file", label: "file",
toJSON: () => { } toJSON: () => {},
}) });
const audioOutputs = mediaDeviceInfos.filter(x => { return x.kind == "audiooutput" }) const audioOutputs = mediaDeviceInfos.filter((x) => {
return x.kind == "audiooutput";
});
audioOutputs.push({ audioOutputs.push({
deviceId: "none", deviceId: "none",
groupId: "none", groupId: "none",
kind: "audiooutput", kind: "audiooutput",
label: "none", label: "none",
toJSON: () => { } toJSON: () => {},
}) });
// audioOutputs.push({ // audioOutputs.push({
// deviceId: "record", // deviceId: "record",
// groupId: "record", // groupId: "record",
@ -144,16 +151,16 @@ export const GuiStateProvider = ({ children }: Props) => {
// label: "record", // label: "record",
// toJSON: () => { } // toJSON: () => { }
// }) // })
return [audioInputs, audioOutputs] return [audioInputs, audioOutputs];
} };
useEffect(() => { useEffect(() => {
const audioInitialize = async () => { const audioInitialize = async () => {
const audioInfo = await reloadDeviceInfo() const audioInfo = await reloadDeviceInfo();
setInputAudioDeviceInfo(audioInfo[0]) setInputAudioDeviceInfo(audioInfo[0]);
setOutputAudioDeviceInfo(audioInfo[1]) setOutputAudioDeviceInfo(audioInfo[1]);
} };
audioInitialize() audioInitialize();
}, []) }, []);
// (1) Controller Switch // (1) Controller Switch
const openServerControlCheckbox = useStateControlCheckbox(OpenServerControlCheckbox); const openServerControlCheckbox = useStateControlCheckbox(OpenServerControlCheckbox);
@ -171,35 +178,31 @@ export const GuiStateProvider = ({ children }: Props) => {
const showMergeLabCheckbox = useStateControlCheckbox(OpenMergeLabDialogCheckbox); const showMergeLabCheckbox = useStateControlCheckbox(OpenMergeLabDialogCheckbox);
const showAdvancedSettingCheckbox = useStateControlCheckbox(OpenAdvancedSettingDialogCheckbox); const showAdvancedSettingCheckbox = useStateControlCheckbox(OpenAdvancedSettingDialogCheckbox);
const showGetServerInformationCheckbox = useStateControlCheckbox(OpenGetServerInformationDialogCheckbox); const showGetServerInformationCheckbox = useStateControlCheckbox(OpenGetServerInformationDialogCheckbox);
const showGetClientInformationCheckbox = useStateControlCheckbox(OpenGetClientInformationDialogCheckbox);
const showTextInputCheckbox = useStateControlCheckbox(OpenTextInputDialogCheckbox); const showTextInputCheckbox = useStateControlCheckbox(OpenTextInputDialogCheckbox);
useEffect(() => { useEffect(() => {
openServerControlCheckbox.updateState(true) openServerControlCheckbox.updateState(true);
openModelSettingCheckbox.updateState(false) openModelSettingCheckbox.updateState(false);
openDeviceSettingCheckbox.updateState(true) openDeviceSettingCheckbox.updateState(true);
openSpeakerSettingCheckbox.updateState(true) openSpeakerSettingCheckbox.updateState(true);
openConverterSettingCheckbox.updateState(true) openConverterSettingCheckbox.updateState(true);
openQualityControlCheckbox.updateState(false) openQualityControlCheckbox.updateState(false);
openLabCheckbox.updateState(false) openLabCheckbox.updateState(false);
openAdvancedSettingCheckbox.updateState(false) openAdvancedSettingCheckbox.updateState(false);
showWaitingCheckbox.updateState(false);
showWaitingCheckbox.updateState(false) showStartingNoticeCheckbox.updateState(false);
showModelSlotManagerCheckbox.updateState(false);
showMergeLabCheckbox.updateState(false);
showAdvancedSettingCheckbox.updateState(false);
showGetServerInformationCheckbox.updateState(false);
showGetClientInformationCheckbox.updateState(false);
showTextInputCheckbox.updateState(false);
showStartingNoticeCheckbox.updateState(false) }, []);
showModelSlotManagerCheckbox.updateState(false)
showMergeLabCheckbox.updateState(false)
showAdvancedSettingCheckbox.updateState(false)
showGetServerInformationCheckbox.updateState(false)
showTextInputCheckbox.updateState(false)
}, [])
useEffect(() => { useEffect(() => {
const show = () => { const show = () => {
@ -210,14 +213,12 @@ export const GuiStateProvider = ({ children }: Props) => {
// return // return
// } // }
document.getElementById("dialog")?.classList.add("dialog-container-show") document.getElementById("dialog")?.classList.add("dialog-container-show");
showStartingNoticeCheckbox.updateState(true) showStartingNoticeCheckbox.updateState(true);
document.getElementById("dialog2")?.classList.add("dialog-container-show") document.getElementById("dialog2")?.classList.add("dialog-container-show");
} };
setTimeout(show) setTimeout(show);
}, [appGuiSettingState.edition]) }, [appGuiSettingState.edition]);
const providerValue = { const providerValue = {
stateControls: { stateControls: {
@ -237,9 +238,9 @@ export const GuiStateProvider = ({ children }: Props) => {
showMergeLabCheckbox, showMergeLabCheckbox,
showAdvancedSettingCheckbox, showAdvancedSettingCheckbox,
showGetServerInformationCheckbox, showGetServerInformationCheckbox,
showGetClientInformationCheckbox,
showTextInputCheckbox showTextInputCheckbox,
}, },
isConverting, isConverting,
setIsConverting, setIsConverting,
@ -248,7 +249,6 @@ export const GuiStateProvider = ({ children }: Props) => {
showPyTorchModelUpload, showPyTorchModelUpload,
setShowPyTorchModelUpload, setShowPyTorchModelUpload,
reloadDeviceInfo, reloadDeviceInfo,
inputAudioDeviceInfo, inputAudioDeviceInfo,
outputAudioDeviceInfo, outputAudioDeviceInfo,
@ -266,13 +266,8 @@ export const GuiStateProvider = ({ children }: Props) => {
modelSlotNum, modelSlotNum,
setModelSlotNum, setModelSlotNum,
textInputResolve, textInputResolve,
setTextInputResolve setTextInputResolve,
}; };
return <GuiStateContext.Provider value={providerValue}>{children}</GuiStateContext.Provider>; return <GuiStateContext.Provider value={providerValue}>{children}</GuiStateContext.Provider>;
}; };

View File

@ -6,9 +6,10 @@ import { ModelSlotManagerDialog } from "./904_ModelSlotManagerDialog";
import { MergeLabDialog } from "./905_MergeLabDialog"; import { MergeLabDialog } from "./905_MergeLabDialog";
import { AdvancedSettingDialog } from "./906_AdvancedSettingDialog"; import { AdvancedSettingDialog } from "./906_AdvancedSettingDialog";
import { GetServerInfomationDialog } from "./907_GetServerInfomationDialog"; import { GetServerInfomationDialog } from "./907_GetServerInfomationDialog";
import { GetClientInfomationDialog } from "./908_GetClientInfomationDialog";
export const Dialogs = () => { export const Dialogs = () => {
const guiState = useGuiState() const guiState = useGuiState();
const dialogs = ( const dialogs = (
<div> <div>
{guiState.stateControls.showWaitingCheckbox.trigger} {guiState.stateControls.showWaitingCheckbox.trigger}
@ -17,6 +18,7 @@ export const Dialogs = () => {
{guiState.stateControls.showMergeLabCheckbox.trigger} {guiState.stateControls.showMergeLabCheckbox.trigger}
{guiState.stateControls.showAdvancedSettingCheckbox.trigger} {guiState.stateControls.showAdvancedSettingCheckbox.trigger}
{guiState.stateControls.showGetServerInformationCheckbox.trigger} {guiState.stateControls.showGetServerInformationCheckbox.trigger}
{guiState.stateControls.showGetClientInformationCheckbox.trigger}
<div className="dialog-container" id="dialog"> <div className="dialog-container" id="dialog">
{guiState.stateControls.showWaitingCheckbox.trigger} {guiState.stateControls.showWaitingCheckbox.trigger}
<WaitingDialog></WaitingDialog> <WaitingDialog></WaitingDialog>
@ -30,10 +32,11 @@ export const Dialogs = () => {
<AdvancedSettingDialog></AdvancedSettingDialog> <AdvancedSettingDialog></AdvancedSettingDialog>
{guiState.stateControls.showGetServerInformationCheckbox.trigger} {guiState.stateControls.showGetServerInformationCheckbox.trigger}
<GetServerInfomationDialog></GetServerInfomationDialog> <GetServerInfomationDialog></GetServerInfomationDialog>
{guiState.stateControls.showGetClientInformationCheckbox.trigger}
<GetClientInfomationDialog></GetClientInfomationDialog>
</div> </div>
</div> </div>
); );
return dialogs return dialogs;
} };

View File

@ -0,0 +1,61 @@
import React, { useMemo } from "react";
import { useGuiState } from "./001_GuiStateProvider";
import { useAppState } from "../../001_provider/001_AppStateProvider";
import { useAppRoot } from "../../001_provider/001_AppRootProvider";
export const GetClientInfomationDialog = () => {
const guiState = useGuiState();
const { audioContextState } = useAppRoot();
const { setting } = useAppState();
const dialog = useMemo(() => {
const closeButtonRow = (
<div className="body-row split-3-4-3 left-padding-1">
<div className="body-item-text"></div>
<div className="body-button-container body-button-container-space-around">
<div
className="body-button"
onClick={() => {
guiState.stateControls.showGetClientInformationCheckbox.updateState(false);
}}
>
close
</div>
</div>
<div className="body-item-text"></div>
</div>
);
const settingJson = JSON.stringify(setting, null, 4);
const rootAudioContextJson = JSON.stringify(
{
sampleRate: audioContextState.audioContext?.sampleRate,
baseLatency: audioContextState.audioContext?.baseLatency,
currentTime: audioContextState.audioContext?.currentTime,
outputLatency: audioContextState.audioContext?.outputLatency,
// @ts-ignore
sinkId: audioContextState.audioContext?.sinkId,
state: audioContextState.audioContext?.state,
},
null,
4
);
const concatJson = settingJson + "\n" + rootAudioContextJson;
console.log("AUDIO_CONTEXT", audioContextState.audioContext);
const content = (
<div className="get-server-information-container">
<textarea className="get-server-information-text-area" id="get-server-information-text-area" value={concatJson} onChange={() => {}} />
</div>
);
return (
<div className="dialog-frame">
<div className="dialog-title">Client Information</div>
<div className="dialog-content">
{content}
{closeButtonRow}
</div>
</div>
);
}, [setting, audioContextState]);
return dialog;
};

View File

@ -154,6 +154,11 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
); );
}) })
.filter((x) => x != null); .filter((x) => x != null);
const currentValue = devices.find((x) => {
return (x.hostAPI == inputHostApi || inputHostApi == "ALL") && x.index == serverSetting.serverSetting.serverInputDeviceId;
})
? serverSetting.serverSetting.serverInputDeviceId
: -1;
return ( return (
<div className="config-sub-area-control"> <div className="config-sub-area-control">
@ -176,12 +181,15 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
</select> </select>
<select <select
className="config-sub-area-control-field-auido-io-select" className="config-sub-area-control-field-auido-io-select"
value={serverSetting.serverSetting.serverInputDeviceId} value={currentValue}
onChange={(e) => { onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverInputDeviceId: Number(e.target.value) }); serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverInputDeviceId: Number(e.target.value) });
}} }}
> >
{filteredDevice} {filteredDevice}
<option value="-1" key="none">
none
</option>
</select> </select>
</div> </div>
</div> </div>
@ -390,6 +398,12 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
}) })
.filter((x) => x != null); .filter((x) => x != null);
const currentValue = devices.find((x) => {
return (x.hostAPI == outputHostApi || outputHostApi == "ALL") && x.index == serverSetting.serverSetting.serverOutputDeviceId;
})
? serverSetting.serverSetting.serverOutputDeviceId
: -1;
return ( return (
<div className="config-sub-area-control"> <div className="config-sub-area-control">
<div className="config-sub-area-control-title left-padding-1">output</div> <div className="config-sub-area-control-title left-padding-1">output</div>
@ -411,12 +425,15 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
</select> </select>
<select <select
className="config-sub-area-control-field-auido-io-select" className="config-sub-area-control-field-auido-io-select"
value={serverSetting.serverSetting.serverOutputDeviceId} value={currentValue}
onChange={(e) => { onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverOutputDeviceId: Number(e.target.value) }); serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverOutputDeviceId: Number(e.target.value) });
}} }}
> >
{filteredDevice} {filteredDevice}
<option value="-1" key="none">
none
</option>
</select> </select>
</div> </div>
</div> </div>
@ -523,10 +540,16 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
.filter((x) => x != null); .filter((x) => x != null);
filteredDevice.unshift( filteredDevice.unshift(
<option value={-1} key={-1}> <option value={-1} key={-1}>
None none
</option> </option>
); );
const currentValue = devices.find((x) => {
return (x.hostAPI == monitorHostApi || monitorHostApi == "ALL") && x.index == serverSetting.serverSetting.serverMonitorDeviceId;
})
? serverSetting.serverSetting.serverMonitorDeviceId
: -1;
return ( return (
<div className="config-sub-area-control"> <div className="config-sub-area-control">
<div className="config-sub-area-control-title left-padding-1">monitor</div> <div className="config-sub-area-control-title left-padding-1">monitor</div>
@ -548,7 +571,7 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
</select> </select>
<select <select
className="config-sub-area-control-field-auido-io-select" className="config-sub-area-control-field-auido-io-select"
value={serverSetting.serverSetting.serverMonitorDeviceId} value={currentValue}
onChange={(e) => { onChange={(e) => {
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverMonitorDeviceId: Number(e.target.value) }); serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverMonitorDeviceId: Number(e.target.value) });
}} }}

View File

@ -1,44 +1,48 @@
import React, { useMemo, } from "react" import React, { useMemo } from "react";
import { useGuiState } from "../001_GuiStateProvider" import { useGuiState } from "../001_GuiStateProvider";
export type MoreActionAreaProps = { export type MoreActionAreaProps = {};
}
export const MoreActionArea = (_props: MoreActionAreaProps) => { export const MoreActionArea = (_props: MoreActionAreaProps) => {
const { stateControls } = useGuiState() const { stateControls } = useGuiState();
const serverIORecorderRow = useMemo(() => { const serverIORecorderRow = useMemo(() => {
const onOpenMergeLabClicked = () => { const onOpenMergeLabClicked = () => {
stateControls.showMergeLabCheckbox.updateState(true) stateControls.showMergeLabCheckbox.updateState(true);
} };
const onOpenAdvancedSettingClicked = () => { const onOpenAdvancedSettingClicked = () => {
stateControls.showAdvancedSettingCheckbox.updateState(true) stateControls.showAdvancedSettingCheckbox.updateState(true);
} };
const onOpenGetServerInformationClicked = () => { const onOpenGetServerInformationClicked = () => {
stateControls.showGetServerInformationCheckbox.updateState(true) stateControls.showGetServerInformationCheckbox.updateState(true);
} };
const onOpenGetClientInformationClicked = () => {
stateControls.showGetClientInformationCheckbox.updateState(true);
};
return ( return (
<> <>
<div className="config-sub-area-control left-padding-1"> <div className="config-sub-area-control left-padding-1">
<div className="config-sub-area-control-title">more...</div> <div className="config-sub-area-control-title">more...</div>
<div className="config-sub-area-control-field config-sub-area-control-field-long"> <div className="config-sub-area-control-field config-sub-area-control-field-long">
<div className="config-sub-area-buttons"> <div className="config-sub-area-buttons">
<div onClick={onOpenMergeLabClicked} className="config-sub-area-button">Merge Lab</div> <div onClick={onOpenMergeLabClicked} className="config-sub-area-button">
<div onClick={onOpenAdvancedSettingClicked} className="config-sub-area-button">Advanced Setting</div> Merge Lab
<div onClick={onOpenGetServerInformationClicked} className="config-sub-area-button">Server Info</div> </div>
<div onClick={onOpenAdvancedSettingClicked} className="config-sub-area-button">
Advanced Setting
</div>
<div onClick={onOpenGetServerInformationClicked} className="config-sub-area-button">
Server Info
</div>
<div onClick={onOpenGetClientInformationClicked} className="config-sub-area-button">
Client Info
</div>
</div> </div>
</div> </div>
</div> </div>
</> </>
) );
}, [stateControls]);
}, [stateControls])
return (
<div className="config-sub-area">
{serverIORecorderRow}
</div>
)
}
return <div className="config-sub-area">{serverIORecorderRow}</div>;
};

View File

@ -1,12 +1,12 @@
{ {
"name": "@dannadori/voice-changer-client-js", "name": "@dannadori/voice-changer-client-js",
"version": "1.0.157", "version": "1.0.159",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@dannadori/voice-changer-client-js", "name": "@dannadori/voice-changer-client-js",
"version": "1.0.157", "version": "1.0.159",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@types/readable-stream": "^2.3.15", "@types/readable-stream": "^2.3.15",

View File

@ -1,6 +1,6 @@
{ {
"name": "@dannadori/voice-changer-client-js", "name": "@dannadori/voice-changer-client-js",
"version": "1.0.157", "version": "1.0.159",
"description": "", "description": "",
"main": "dist/index.js", "main": "dist/index.js",
"directories": { "directories": {

View File

@ -42,8 +42,9 @@ export type CrossFadeOverlapSize = typeof CrossFadeOverlapSize[keyof typeof Cros
export const F0Detector = { export const F0Detector = {
"dio": "dio", "dio": "dio",
"harvest": "harvest", "harvest": "harvest",
// "parselmouth": "parselmouth",
"crepe": "crepe", "crepe": "crepe",
"crepe_full": "crepe_full",
"crepe_tiny": "crepe_tiny",
} as const } as const
export type F0Detector = typeof F0Detector[keyof typeof F0Detector] export type F0Detector = typeof F0Detector[keyof typeof F0Detector]

View File

@ -81,7 +81,7 @@ export const useClient = (props: UseClientProps): ClientState => {
}, []) }, [])
// (1-2) 各種設定I/F // (1-2) 各種設定I/F
const voiceChangerClientSetting = useClientSetting({ voiceChangerClient, audioContext: props.audioContext, voiceChangerClientSetting: setting.voiceChangerClientSetting }) const voiceChangerClientSetting = useClientSetting({ voiceChangerClient, voiceChangerClientSetting: setting.voiceChangerClientSetting })
const workletNodeSetting = useWorkletNodeSetting({ voiceChangerClient: voiceChangerClient, workletNodeSetting: setting.workletNodeSetting }) const workletNodeSetting = useWorkletNodeSetting({ voiceChangerClient: voiceChangerClient, workletNodeSetting: setting.workletNodeSetting })
useWorkletSetting({ voiceChangerClient, workletSetting: setting.workletSetting }) useWorkletSetting({ voiceChangerClient, workletSetting: setting.workletSetting })
const serverSetting = useServerSetting({ voiceChangerClient }) const serverSetting = useServerSetting({ voiceChangerClient })

View File

@ -5,7 +5,6 @@ import { VoiceChangerClient } from "../VoiceChangerClient"
export type UseClientSettingProps = { export type UseClientSettingProps = {
voiceChangerClient: VoiceChangerClient | null voiceChangerClient: VoiceChangerClient | null
audioContext: AudioContext | null
voiceChangerClientSetting: VoiceChangerClientSetting voiceChangerClientSetting: VoiceChangerClientSetting
} }

View File

@ -113,8 +113,6 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
const _uploadFile2 = useMemo(() => { const _uploadFile2 = useMemo(() => {
return async (file: File, onprogress: (progress: number, end: boolean) => void, dir: string = "") => { return async (file: File, onprogress: (progress: number, end: boolean) => void, dir: string = "") => {
if (!props.voiceChangerClient) return if (!props.voiceChangerClient) return
console.log("uploading..1.", file)
console.log("uploading..2.", file.name)
const num = await props.voiceChangerClient.uploadFile2(dir, file, onprogress) const num = await props.voiceChangerClient.uploadFile2(dir, file, onprogress)
const res = await props.voiceChangerClient.concatUploadedFile(dir + file.name, num) const res = await props.voiceChangerClient.concatUploadedFile(dir + file.name, num)
console.log("uploaded", num, res) console.log("uploaded", num, res)

View File

@ -34,6 +34,7 @@ def setupArgParser():
parser.add_argument("--logLevel", type=str, default="error", help="Log level info|critical|error. (default: error)") parser.add_argument("--logLevel", type=str, default="error", help="Log level info|critical|error. (default: error)")
parser.add_argument("-p", type=int, default=18888, help="port") parser.add_argument("-p", type=int, default=18888, help="port")
parser.add_argument("--https", type=strtobool, default=False, help="use https") parser.add_argument("--https", type=strtobool, default=False, help="use https")
parser.add_argument("--test_connect", type=str, default="8.8.8.8", help="test connect to detect ip in https mode. default 8.8.8.8")
parser.add_argument("--httpsKey", type=str, default="ssl.key", help="path for the key of https") parser.add_argument("--httpsKey", type=str, default="ssl.key", help="path for the key of https")
parser.add_argument("--httpsCert", type=str, default="ssl.cert", help="path for the cert of https") parser.add_argument("--httpsCert", type=str, default="ssl.cert", help="path for the cert of https")
parser.add_argument("--httpsSelfSigned", type=strtobool, default=True, help="generate self-signed certificate") parser.add_argument("--httpsSelfSigned", type=strtobool, default=True, help="generate self-signed certificate")
@ -48,6 +49,8 @@ def setupArgParser():
parser.add_argument("--hubert_base_jp", type=str, help="path to hubert_base_jp model(pytorch)") parser.add_argument("--hubert_base_jp", type=str, help="path to hubert_base_jp model(pytorch)")
parser.add_argument("--hubert_soft", type=str, help="path to hubert_soft model(pytorch)") parser.add_argument("--hubert_soft", type=str, help="path to hubert_soft model(pytorch)")
parser.add_argument("--nsf_hifigan", type=str, help="path to nsf_hifigan model(pytorch)") parser.add_argument("--nsf_hifigan", type=str, help="path to nsf_hifigan model(pytorch)")
parser.add_argument("--crepe_onnx_full", type=str, help="path to crepe_onnx_full")
parser.add_argument("--crepe_onnx_tiny", type=str, help="path to crepe_onnx_tiny")
return parser return parser
@ -85,6 +88,8 @@ voiceChangerParams = VoiceChangerParams(
hubert_base_jp=args.hubert_base_jp, hubert_base_jp=args.hubert_base_jp,
hubert_soft=args.hubert_soft, hubert_soft=args.hubert_soft,
nsf_hifigan=args.nsf_hifigan, nsf_hifigan=args.nsf_hifigan,
crepe_onnx_full=args.crepe_onnx_full,
crepe_onnx_tiny=args.crepe_onnx_tiny,
sample_mode=args.sample_mode, sample_mode=args.sample_mode,
) )
@ -120,6 +125,7 @@ if __name__ == "__mp_main__":
if __name__ == "__main__": if __name__ == "__main__":
mp.freeze_support() mp.freeze_support()
printMessage(f"PYTHON:{sys.version}", level=2)
printMessage("Voice Changerを起動しています。", level=2) printMessage("Voice Changerを起動しています。", level=2)
# ダウンロード(Weight) # ダウンロード(Weight)
try: try:
@ -195,10 +201,10 @@ if __name__ == "__main__":
else: else:
printMessage(f"http://localhost:{EX_PORT}/", level=1) printMessage(f"http://localhost:{EX_PORT}/", level=1)
else: # 直接python起動 else: # 直接python起動
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
hostname = s.getsockname()[0]
if args.https == 1: if args.https == 1:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((args.test_connect, 80))
hostname = s.getsockname()[0]
printMessage(f"https://localhost:{PORT}/", level=1) printMessage(f"https://localhost:{PORT}/", level=1)
printMessage(f"https://{hostname}:{PORT}/", level=1) printMessage(f"https://{hostname}:{PORT}/", level=1)
else: else:

View File

@ -54,11 +54,11 @@ def getFrontendPath():
return frontend_path return frontend_path
# "hubert_base", "contentvec", "distilhubert" EmbedderType: TypeAlias = Literal[
class EnumEmbedderTypes(Enum): "hubert_base",
hubert = "hubert_base" "contentvec",
contentvec = "contentvec" "hubert-base-japanese"
hubert_jp = "hubert-base-japanese" ]
class EnumInferenceTypes(Enum): class EnumInferenceTypes(Enum):
@ -73,21 +73,18 @@ class EnumInferenceTypes(Enum):
onnxRVCNono = "onnxRVCNono" onnxRVCNono = "onnxRVCNono"
class EnumPitchExtractorTypes(Enum): PitchExtractorType: TypeAlias = Literal[
harvest = "harvest" "harvest",
dio = "dio" "dio",
crepe = "crepe" "crepe",
"crepe_full",
"crepe_tiny",
class EnumFrameworkTypes(Enum): ]
pyTorch = "pyTorch"
onnx = "onnx"
class ServerAudioDeviceTypes(Enum):
audioinput = "audioinput"
audiooutput = "audiooutput"
ServerAudioDeviceType: TypeAlias = Literal[
"audioinput",
"audiooutput"
]
RVCSampleMode: TypeAlias = Literal[ RVCSampleMode: TypeAlias = Literal[
"production", "production",

View File

@ -1,5 +1,5 @@
from typing import TypeAlias, Union from typing import TypeAlias, Union
from const import MAX_SLOT_NUM, EnumInferenceTypes, EnumEmbedderTypes, VoiceChangerType from const import MAX_SLOT_NUM, EnumInferenceTypes, EmbedderType, VoiceChangerType
from dataclasses import dataclass, asdict, field from dataclasses import dataclass, asdict, field
@ -34,7 +34,7 @@ class RVCModelSlot(ModelSlot):
embOutputLayer: int = 9 embOutputLayer: int = 9
useFinalProj: bool = True useFinalProj: bool = True
deprecated: bool = False deprecated: bool = False
embedder: str = EnumEmbedderTypes.hubert.value embedder: EmbedderType = "hubert_base"
sampleId: str = "" sampleId: str = ""
speakers: dict = field(default_factory=lambda: {0: "target"}) speakers: dict = field(default_factory=lambda: {0: "target"})

View File

@ -166,7 +166,8 @@ def _downloadSamples(samples: list[ModelSamples], sampleModelIds: list[Tuple[str
slotInfo = modelSlotManager.get_slot_info(targetSlotIndex) slotInfo = modelSlotManager.get_slot_info(targetSlotIndex)
if slotInfo.voiceChangerType == "RVC": if slotInfo.voiceChangerType == "RVC":
if slotInfo.isONNX: if slotInfo.isONNX:
RVCModelSlotGenerator._setInfoByONNX(slotInfo) slotInfo = RVCModelSlotGenerator._setInfoByONNX(slotInfo)
else: else:
RVCModelSlotGenerator._setInfoByPytorch(slotInfo) slotInfo = RVCModelSlotGenerator._setInfoByPytorch(slotInfo)
modelSlotManager.save_model_slot(targetSlotIndex, slotInfo) modelSlotManager.save_model_slot(targetSlotIndex, slotInfo)

View File

@ -11,6 +11,8 @@ def downloadWeight(voiceChangerParams: VoiceChangerParams):
hubert_base_jp = voiceChangerParams.hubert_base_jp hubert_base_jp = voiceChangerParams.hubert_base_jp
hubert_soft = voiceChangerParams.hubert_soft hubert_soft = voiceChangerParams.hubert_soft
nsf_hifigan = voiceChangerParams.nsf_hifigan nsf_hifigan = voiceChangerParams.nsf_hifigan
crepe_onnx_full = voiceChangerParams.crepe_onnx_full
crepe_onnx_tiny = voiceChangerParams.crepe_onnx_tiny
# file exists check (currently only for rvc) # file exists check (currently only for rvc)
downloadParams = [] downloadParams = []
@ -57,6 +59,24 @@ def downloadWeight(voiceChangerParams: VoiceChangerParams):
} }
) )
if os.path.exists(crepe_onnx_full) is False:
downloadParams.append(
{
"url": "https://huggingface.co/wok000/weights/resolve/main/crepe/onnx/full.onnx",
"saveTo": crepe_onnx_full,
"position": 5,
}
)
if os.path.exists(crepe_onnx_tiny) is False:
downloadParams.append(
{
"url": "https://huggingface.co/wok000/weights/resolve/main/crepe/onnx/tiny.onnx",
"saveTo": crepe_onnx_tiny,
"position": 6,
}
)
with ThreadPoolExecutor() as pool: with ThreadPoolExecutor() as pool:
pool.map(download, downloadParams) pool.map(download, downloadParams)

View File

@ -1,14 +1,15 @@
import sounddevice as sd import sounddevice as sd
from dataclasses import dataclass, field from dataclasses import dataclass, field
from const import ServerAudioDeviceTypes
import numpy as np import numpy as np
from const import ServerAudioDeviceType
# from const import SERVER_DEVICE_SAMPLE_RATES # from const import SERVER_DEVICE_SAMPLE_RATES
@dataclass @dataclass
class ServerAudioDevice: class ServerAudioDevice:
kind: ServerAudioDeviceTypes = ServerAudioDeviceTypes.audioinput kind: ServerAudioDeviceType = "audioinput"
index: int = 0 index: int = 0
name: str = "" name: str = ""
hostAPI: str = "" hostAPI: str = ""
@ -22,7 +23,7 @@ def dummy_callback(data: np.ndarray, frames, times, status):
pass pass
def checkSamplingRate(deviceId: int, desiredSamplingRate: int, type: ServerAudioDeviceTypes): def checkSamplingRate(deviceId: int, desiredSamplingRate: int, type: ServerAudioDeviceType):
if type == "input": if type == "input":
try: try:
with sd.InputStream( with sd.InputStream(
@ -71,7 +72,7 @@ def list_audio_device():
serverAudioOutputDevices: list[ServerAudioDevice] = [] serverAudioOutputDevices: list[ServerAudioDevice] = []
for d in inputAudioDeviceList: for d in inputAudioDeviceList:
serverInputAudioDevice: ServerAudioDevice = ServerAudioDevice( serverInputAudioDevice: ServerAudioDevice = ServerAudioDevice(
kind=ServerAudioDeviceTypes.audioinput, kind="audioinput",
index=d["index"], index=d["index"],
name=d["name"], name=d["name"],
hostAPI=hostapis[d["hostapi"]]["name"], hostAPI=hostapis[d["hostapi"]]["name"],
@ -82,7 +83,7 @@ def list_audio_device():
serverAudioInputDevices.append(serverInputAudioDevice) serverAudioInputDevices.append(serverInputAudioDevice)
for d in outputAudioDeviceList: for d in outputAudioDeviceList:
serverOutputAudioDevice: ServerAudioDevice = ServerAudioDevice( serverOutputAudioDevice: ServerAudioDevice = ServerAudioDevice(
kind=ServerAudioDeviceTypes.audiooutput, kind="audiooutput",
index=d["index"], index=d["index"],
name=d["name"], name=d["name"],
hostAPI=hostapis[d["hostapi"]]["name"], hostAPI=hostapis[d["hostapi"]]["name"],

View File

@ -300,5 +300,5 @@ class MMVCv15:
if file_path.find(remove_path + os.path.sep) >= 0: if file_path.find(remove_path + os.path.sep) >= 0:
# print("remove", key, file_path) # print("remove", key, file_path)
sys.modules.pop(key) sys.modules.pop(key)
except: # type:ignore except: # NOQA
pass pass

View File

@ -1,5 +1,5 @@
import sys # import sys
import os # import os
from dataclasses import asdict from dataclasses import asdict
import numpy as np import numpy as np
import torch import torch
@ -7,18 +7,18 @@ import torchaudio
from data.ModelSlot import RVCModelSlot from data.ModelSlot import RVCModelSlot
# avoiding parse arg error in RVC # # avoiding parse arg error in RVC
sys.argv = ["MMVCServerSIO.py"] # sys.argv = ["MMVCServerSIO.py"]
if sys.platform.startswith("darwin"): # if sys.platform.startswith("darwin"):
baseDir = [x for x in sys.path if x.endswith("Contents/MacOS")] # baseDir = [x for x in sys.path if x.endswith("Contents/MacOS")]
if len(baseDir) != 1: # if len(baseDir) != 1:
print("baseDir should be only one ", baseDir) # print("baseDir should be only one ", baseDir)
sys.exit() # sys.exit()
modulePath = os.path.join(baseDir[0], "RVC") # modulePath = os.path.join(baseDir[0], "RVC")
sys.path.append(modulePath) # sys.path.append(modulePath)
else: # else:
sys.path.append("RVC") # sys.path.append("RVC")
from voice_changer.RVC.RVCSettings import RVCSettings from voice_changer.RVC.RVCSettings import RVCSettings
@ -39,9 +39,10 @@ class RVC(VoiceChangerModel):
print("[Voice Changer] [RVC] Creating instance ") print("[Voice Changer] [RVC] Creating instance ")
self.deviceManager = DeviceManager.get_instance() self.deviceManager = DeviceManager.get_instance()
EmbedderManager.initialize(params) EmbedderManager.initialize(params)
PitchExtractorManager.initialize(params)
self.settings = RVCSettings() self.settings = RVCSettings()
self.params = params self.params = params
self.pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector) self.pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector, self.settings.gpu)
self.pipeline: Pipeline | None = None self.pipeline: Pipeline | None = None
@ -76,7 +77,7 @@ class RVC(VoiceChangerModel):
elif key in self.settings.strData: elif key in self.settings.strData:
setattr(self.settings, key, str(val)) setattr(self.settings, key, str(val))
if key == "f0Detector" and self.pipeline is not None: if key == "f0Detector" and self.pipeline is not None:
pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector) pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector, self.settings.gpu)
self.pipeline.setPitchExtractor(pitchExtractor) self.pipeline.setPitchExtractor(pitchExtractor)
else: else:
return False return False
@ -112,7 +113,7 @@ class RVC(VoiceChangerModel):
self.audio_buffer = newData self.audio_buffer = newData
if self.slotInfo.f0: if self.slotInfo.f0:
self.pitchf_buffer = np.zeros(new_feature_length) self.pitchf_buffer = np.zeros(new_feature_length)
self.feature_buffer = np.zeros([new_feature_length, self.slotInfo.embChannels]) self.feature_buffer = np.zeros([new_feature_length, self.slotInfo.embChannels])
convertSize = inputSize + crossfadeSize + solaSearchFrame + self.settings.extraConvertSize convertSize = inputSize + crossfadeSize + solaSearchFrame + self.settings.extraConvertSize
@ -201,21 +202,21 @@ class RVC(VoiceChangerModel):
def __del__(self): def __del__(self):
del self.pipeline del self.pipeline
print("---------- REMOVING ---------------") # print("---------- REMOVING ---------------")
remove_path = os.path.join("RVC") # remove_path = os.path.join("RVC")
sys.path = [x for x in sys.path if x.endswith(remove_path) is False] # sys.path = [x for x in sys.path if x.endswith(remove_path) is False]
for key in list(sys.modules): # for key in list(sys.modules):
val = sys.modules.get(key) # val = sys.modules.get(key)
try: # try:
file_path = val.__file__ # file_path = val.__file__
if file_path.find("RVC" + os.path.sep) >= 0: # if file_path.find("RVC" + os.path.sep) >= 0:
# print("remove", key, file_path) # # print("remove", key, file_path)
sys.modules.pop(key) # sys.modules.pop(key)
except Exception: # type:ignore # except Exception: # type:ignore
# print(e) # # print(e)
pass # pass
def export2onnx(self): def export2onnx(self):
modelSlot = self.slotInfo modelSlot = self.slotInfo

View File

@ -1,6 +1,6 @@
import os import os
from const import EnumEmbedderTypes, EnumInferenceTypes from const import EnumInferenceTypes
from dataclasses import asdict
import torch import torch
import onnxruntime import onnxruntime
import json import json
@ -38,6 +38,8 @@ class RVCModelSlotGenerator(ModelSlotGenerator):
config_len = len(cpt["config"]) config_len = len(cpt["config"])
version = cpt.get("version", "v1") version = cpt.get("version", "v1")
slot = RVCModelSlot(**asdict(slot))
if version == "voras_beta": if version == "voras_beta":
slot.f0 = True if cpt["f0"] == 1 else False slot.f0 = True if cpt["f0"] == 1 else False
slot.modelType = EnumInferenceTypes.pyTorchVoRASbeta.value slot.modelType = EnumInferenceTypes.pyTorchVoRASbeta.value
@ -49,12 +51,12 @@ class RVCModelSlotGenerator(ModelSlotGenerator):
if slot.embedder.endswith("768"): if slot.embedder.endswith("768"):
slot.embedder = slot.embedder[:-3] slot.embedder = slot.embedder[:-3]
if slot.embedder == EnumEmbedderTypes.hubert.value: # if slot.embedder == "hubert":
slot.embedder = EnumEmbedderTypes.hubert.value # slot.embedder = "hubert"
elif slot.embedder == EnumEmbedderTypes.contentvec.value: # elif slot.embedder == "contentvec":
slot.embedder = EnumEmbedderTypes.contentvec.value # slot.embedder = "contentvec"
elif slot.embedder == EnumEmbedderTypes.hubert_jp.value: # elif slot.embedder == "hubert_jp":
slot.embedder = EnumEmbedderTypes.hubert_jp.value # slot.embedder = "hubert_jp"
else: else:
raise RuntimeError("[Voice Changer][setInfoByONNX] unknown embedder") raise RuntimeError("[Voice Changer][setInfoByONNX] unknown embedder")
@ -67,14 +69,14 @@ class RVCModelSlotGenerator(ModelSlotGenerator):
slot.embChannels = 256 slot.embChannels = 256
slot.embOutputLayer = 9 slot.embOutputLayer = 9
slot.useFinalProj = True slot.useFinalProj = True
slot.embedder = EnumEmbedderTypes.hubert.value slot.embedder = "hubert_base"
print("[Voice Changer] Official Model(pyTorch) : v1") print("[Voice Changer] Official Model(pyTorch) : v1")
else: else:
slot.modelType = EnumInferenceTypes.pyTorchRVCv2.value if slot.f0 else EnumInferenceTypes.pyTorchRVCv2Nono.value slot.modelType = EnumInferenceTypes.pyTorchRVCv2.value if slot.f0 else EnumInferenceTypes.pyTorchRVCv2Nono.value
slot.embChannels = 768 slot.embChannels = 768
slot.embOutputLayer = 12 slot.embOutputLayer = 12
slot.useFinalProj = False slot.useFinalProj = False
slot.embedder = EnumEmbedderTypes.hubert.value slot.embedder = "hubert_base"
print("[Voice Changer] Official Model(pyTorch) : v2") print("[Voice Changer] Official Model(pyTorch) : v2")
else: else:
@ -104,24 +106,18 @@ class RVCModelSlotGenerator(ModelSlotGenerator):
for k, v in cpt["speaker_info"].items(): for k, v in cpt["speaker_info"].items():
slot.speakers[int(k)] = str(v) slot.speakers[int(k)] = str(v)
# if slot.embedder == EnumEmbedderTypes.hubert.value:
# slot.embedder = EnumEmbedderTypes.hubert
# elif slot.embedder == EnumEmbedderTypes.contentvec.value:
# slot.embedder = EnumEmbedderTypes.contentvec
# elif slot.embedder == EnumEmbedderTypes.hubert_jp.value:
# slot.embedder = EnumEmbedderTypes.hubert_jp
# else:
# raise RuntimeError("[Voice Changer][setInfoByONNX] unknown embedder")
slot.samplingRate = cpt["config"][-1] slot.samplingRate = cpt["config"][-1]
del cpt del cpt
return slot
@classmethod @classmethod
def _setInfoByONNX(cls, slot: ModelSlot): def _setInfoByONNX(cls, slot: ModelSlot):
tmp_onnx_session = onnxruntime.InferenceSession(slot.modelFile, providers=["CPUExecutionProvider"]) tmp_onnx_session = onnxruntime.InferenceSession(slot.modelFile, providers=["CPUExecutionProvider"])
modelmeta = tmp_onnx_session.get_modelmeta() modelmeta = tmp_onnx_session.get_modelmeta()
try: try:
slot = RVCModelSlot(**asdict(slot))
metadata = json.loads(modelmeta.custom_metadata_map["metadata"]) metadata = json.loads(modelmeta.custom_metadata_map["metadata"])
# slot.modelType = metadata["modelType"] # slot.modelType = metadata["modelType"]
@ -144,17 +140,9 @@ class RVCModelSlotGenerator(ModelSlotGenerator):
print(f"[Voice Changer] ONNX Model: ch:{slot.embChannels}, L:{slot.embOutputLayer}, FP:{slot.useFinalProj}") print(f"[Voice Changer] ONNX Model: ch:{slot.embChannels}, L:{slot.embOutputLayer}, FP:{slot.useFinalProj}")
if "embedder" not in metadata: if "embedder" not in metadata:
slot.embedder = EnumEmbedderTypes.hubert.value slot.embedder = "hubert_base"
else: else:
slot.embedder = metadata["embedder"] slot.embedder = metadata["embedder"]
# elif metadata["embedder"] == EnumEmbedderTypes.hubert.value:
# slot.embedder = EnumEmbedderTypes.hubert
# elif metadata["embedder"] == EnumEmbedderTypes.contentvec.value:
# slot.embedder = EnumEmbedderTypes.contentvec
# elif metadata["embedder"] == EnumEmbedderTypes.hubert_jp.value:
# slot.embedder = EnumEmbedderTypes.hubert_jp
# else:
# raise RuntimeError("[Voice Changer][setInfoByONNX] unknown embedder")
slot.f0 = metadata["f0"] slot.f0 = metadata["f0"]
slot.modelType = EnumInferenceTypes.onnxRVC.value if slot.f0 else EnumInferenceTypes.onnxRVCNono.value slot.modelType = EnumInferenceTypes.onnxRVC.value if slot.f0 else EnumInferenceTypes.onnxRVCNono.value
@ -164,7 +152,7 @@ class RVCModelSlotGenerator(ModelSlotGenerator):
except Exception as e: except Exception as e:
slot.modelType = EnumInferenceTypes.onnxRVC.value slot.modelType = EnumInferenceTypes.onnxRVC.value
slot.embChannels = 256 slot.embChannels = 256
slot.embedder = EnumEmbedderTypes.hubert.value slot.embedder = "hubert_base"
slot.f0 = True slot.f0 = True
slot.samplingRate = 48000 slot.samplingRate = 48000
slot.deprecated = True slot.deprecated = True
@ -175,3 +163,4 @@ class RVCModelSlotGenerator(ModelSlotGenerator):
print("[Voice Changer] ############## !!!! CAUTION !!!! ####################") print("[Voice Changer] ############## !!!! CAUTION !!!! ####################")
del tmp_onnx_session del tmp_onnx_session
return slot

View File

@ -3,11 +3,11 @@ from typing import Any, Protocol
import torch import torch
from torch import device from torch import device
from const import EnumEmbedderTypes from const import EmbedderType
class Embedder(Protocol): class Embedder(Protocol):
embedderType: EnumEmbedderTypes = EnumEmbedderTypes.hubert embedderType: EmbedderType = "hubert_base"
file: str file: str
isHalf: bool = True isHalf: bool = True
dev: device dev: device
@ -24,7 +24,7 @@ class Embedder(Protocol):
def getEmbedderInfo(self): def getEmbedderInfo(self):
return { return {
"embedderType": self.embedderType.value, "embedderType": self.embedderType,
"file": self.file, "file": self.file,
"isHalf": self.isHalf, "isHalf": self.isHalf,
"devType": self.dev.type, "devType": self.dev.type,
@ -33,7 +33,7 @@ class Embedder(Protocol):
def setProps( def setProps(
self, self,
embedderType: EnumEmbedderTypes, embedderType: EmbedderType,
file: str, file: str,
dev: device, dev: device,
isHalf: bool = True, isHalf: bool = True,
@ -56,7 +56,7 @@ class Embedder(Protocol):
self.model = self.model.to(self.dev) self.model = self.model.to(self.dev)
return self return self
def matchCondition(self, embedderType: EnumEmbedderTypes) -> bool: def matchCondition(self, embedderType: EmbedderType) -> bool:
# Check Type # Check Type
if self.embedderType != embedderType: if self.embedderType != embedderType:
print( print(

View File

@ -1,6 +1,6 @@
from torch import device from torch import device
from const import EnumEmbedderTypes from const import EmbedderType
from voice_changer.RVC.embedder.Embedder import Embedder from voice_changer.RVC.embedder.Embedder import Embedder
from voice_changer.RVC.embedder.FairseqContentvec import FairseqContentvec from voice_changer.RVC.embedder.FairseqContentvec import FairseqContentvec
from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert
@ -18,7 +18,7 @@ class EmbedderManager:
@classmethod @classmethod
def getEmbedder( def getEmbedder(
cls, embederType: EnumEmbedderTypes, isHalf: bool, dev: device cls, embederType: EmbedderType, isHalf: bool, dev: device
) -> Embedder: ) -> Embedder:
if cls.currentEmbedder is None: if cls.currentEmbedder is None:
print("[Voice Changer] generate new embedder. (no embedder)") print("[Voice Changer] generate new embedder. (no embedder)")
@ -35,24 +35,15 @@ class EmbedderManager:
@classmethod @classmethod
def loadEmbedder( def loadEmbedder(
cls, embederType: EnumEmbedderTypes, isHalf: bool, dev: device cls, embederType: EmbedderType, isHalf: bool, dev: device
) -> Embedder: ) -> Embedder:
if ( if embederType == "hubert_base":
embederType == EnumEmbedderTypes.hubert
or embederType == EnumEmbedderTypes.hubert.value
):
file = cls.params.hubert_base file = cls.params.hubert_base
return FairseqHubert().loadModel(file, dev, isHalf) return FairseqHubert().loadModel(file, dev, isHalf)
elif ( elif embederType == "hubert-base-japanese":
embederType == EnumEmbedderTypes.hubert_jp
or embederType == EnumEmbedderTypes.hubert_jp.value
):
file = cls.params.hubert_base_jp file = cls.params.hubert_base_jp
return FairseqHubertJp().loadModel(file, dev, isHalf) return FairseqHubertJp().loadModel(file, dev, isHalf)
elif ( elif embederType == "contentvec":
embederType == EnumEmbedderTypes.contentvec
or embederType == EnumEmbedderTypes.contentvec.value
):
file = cls.params.hubert_base file = cls.params.hubert_base
return FairseqContentvec().loadModel(file, dev, isHalf) return FairseqContentvec().loadModel(file, dev, isHalf)
else: else:

View File

@ -1,5 +1,4 @@
from torch import device from torch import device
from const import EnumEmbedderTypes
from voice_changer.RVC.embedder.Embedder import Embedder from voice_changer.RVC.embedder.Embedder import Embedder
from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert
@ -7,5 +6,5 @@ from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert
class FairseqContentvec(FairseqHubert): class FairseqContentvec(FairseqHubert):
def loadModel(self, file: str, dev: device, isHalf: bool = True) -> Embedder: def loadModel(self, file: str, dev: device, isHalf: bool = True) -> Embedder:
super().loadModel(file, dev, isHalf) super().loadModel(file, dev, isHalf)
super().setProps(EnumEmbedderTypes.contentvec, file, dev, isHalf) super().setProps("contentvec", file, dev, isHalf)
return self return self

View File

@ -1,13 +1,12 @@
import torch import torch
from torch import device from torch import device
from const import EnumEmbedderTypes
from voice_changer.RVC.embedder.Embedder import Embedder from voice_changer.RVC.embedder.Embedder import Embedder
from fairseq import checkpoint_utils from fairseq import checkpoint_utils
class FairseqHubert(Embedder): class FairseqHubert(Embedder):
def loadModel(self, file: str, dev: device, isHalf: bool = True) -> Embedder: def loadModel(self, file: str, dev: device, isHalf: bool = True) -> Embedder:
super().setProps(EnumEmbedderTypes.hubert, file, dev, isHalf) super().setProps("hubert_base", file, dev, isHalf)
models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task(
[file], [file],

View File

@ -1,5 +1,4 @@
from torch import device from torch import device
from const import EnumEmbedderTypes
from voice_changer.RVC.embedder.Embedder import Embedder from voice_changer.RVC.embedder.Embedder import Embedder
from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert
@ -7,5 +6,5 @@ from voice_changer.RVC.embedder.FairseqHubert import FairseqHubert
class FairseqHubertJp(FairseqHubert): class FairseqHubertJp(FairseqHubert):
def loadModel(self, file: str, dev: device, isHalf: bool = True) -> Embedder: def loadModel(self, file: str, dev: device, isHalf: bool = True) -> Embedder:
super().loadModel(file, dev, isHalf) super().loadModel(file, dev, isHalf)
super().setProps(EnumEmbedderTypes.hubert_jp, file, dev, isHalf) super().setProps("hubert-base-japanese", file, dev, isHalf)
return self return self

View File

@ -31,7 +31,6 @@ class InferencerManager:
file: str, file: str,
gpu: int, gpu: int,
) -> Inferencer: ) -> Inferencer:
print("inferencerTypeinferencerTypeinferencerTypeinferencerType", inferencerType)
if inferencerType == EnumInferenceTypes.pyTorchRVC or inferencerType == EnumInferenceTypes.pyTorchRVC.value: if inferencerType == EnumInferenceTypes.pyTorchRVC or inferencerType == EnumInferenceTypes.pyTorchRVC.value:
return RVCInferencer().loadModel(file, gpu) return RVCInferencer().loadModel(file, gpu)
elif inferencerType == EnumInferenceTypes.pyTorchRVCNono or inferencerType == EnumInferenceTypes.pyTorchRVCNono.value: elif inferencerType == EnumInferenceTypes.pyTorchRVCNono or inferencerType == EnumInferenceTypes.pyTorchRVCNono.value:

View File

@ -51,7 +51,7 @@ class OnnxRVCInferencer(Inferencer):
"p_len": pitch_length.cpu().numpy().astype(np.int64), "p_len": pitch_length.cpu().numpy().astype(np.int64),
"pitch": pitch.cpu().numpy().astype(np.int64), "pitch": pitch.cpu().numpy().astype(np.int64),
"pitchf": pitchf.cpu().numpy().astype(np.float32), "pitchf": pitchf.cpu().numpy().astype(np.float32),
"sid": sid.cpu().numpy().astype(np.int64) "sid": sid.cpu().numpy().astype(np.int64)
}, },
) )
else: else:
@ -62,7 +62,7 @@ class OnnxRVCInferencer(Inferencer):
"p_len": pitch_length.cpu().numpy().astype(np.int64), "p_len": pitch_length.cpu().numpy().astype(np.int64),
"pitch": pitch.cpu().numpy().astype(np.int64), "pitch": pitch.cpu().numpy().astype(np.int64),
"pitchf": pitchf.cpu().numpy().astype(np.float32), "pitchf": pitchf.cpu().numpy().astype(np.float32),
"sid": sid.cpu().numpy().astype(np.int64) "sid": sid.cpu().numpy().astype(np.int64)
}, },
) )

View File

@ -4,6 +4,7 @@ from const import EnumInferenceTypes
from voice_changer.RVC.inferencer.OnnxRVCInferencer import OnnxRVCInferencer from voice_changer.RVC.inferencer.OnnxRVCInferencer import OnnxRVCInferencer
class OnnxRVCInferencerNono(OnnxRVCInferencer): class OnnxRVCInferencerNono(OnnxRVCInferencer):
def loadModel(self, file: str, gpu: int): def loadModel(self, file: str, gpu: int):
super().loadModel(file, gpu) super().loadModel(file, gpu)

View File

@ -73,9 +73,9 @@ class Pipeline(object):
def exec( def exec(
self, self,
sid, sid,
audio, # torch.tensor [n] audio, # torch.tensor [n]
pitchf, # np.array [m] pitchf, # np.array [m]
feature, # np.array [m, feat] feature, # np.array [m, feat]
f0_up_key, f0_up_key,
index_rate, index_rate,
if_f0, if_f0,

View File

@ -34,7 +34,7 @@ def createPipeline(modelSlot: RVCModelSlot, gpu: int, f0Detector: str):
traceback.print_exc() traceback.print_exc()
# pitchExtractor # pitchExtractor
pitchExtractor = PitchExtractorManager.getPitchExtractor(f0Detector) pitchExtractor = PitchExtractorManager.getPitchExtractor(f0Detector, gpu)
# index, feature # index, feature
index = _loadIndex(modelSlot) index = _loadIndex(modelSlot)
@ -67,7 +67,7 @@ def _loadIndex(modelSlot: RVCModelSlot):
try: try:
print("Try loading...", modelSlot.indexFile) print("Try loading...", modelSlot.indexFile)
index = faiss.read_index(modelSlot.indexFile) index = faiss.read_index(modelSlot.indexFile)
except: except: # NOQA
print("[Voice Changer] load index failed. Use no index.") print("[Voice Changer] load index failed. Use no index.")
traceback.print_exc() traceback.print_exc()
return None return None

View File

@ -0,0 +1,68 @@
import numpy as np
from const import PitchExtractorType
from voice_changer.RVC.deviceManager.DeviceManager import DeviceManager
from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor
import onnxruntime
from voice_changer.RVC.pitchExtractor import onnxcrepe
class CrepeOnnxPitchExtractor(PitchExtractor):
def __init__(self, pitchExtractorType: PitchExtractorType, file: str, gpu: int):
self.pitchExtractorType = pitchExtractorType
super().__init__()
(
onnxProviders,
onnxProviderOptions,
) = DeviceManager.get_instance().getOnnxExecutionProvider(gpu)
self.onnx_session = onnxruntime.InferenceSession(
file, providers=onnxProviders, provider_options=onnxProviderOptions
)
def extract(self, audio, pitchf, f0_up_key, sr, window, silence_front=0):
n_frames = int(len(audio) // window) + 1
start_frame = int(silence_front * sr / window)
real_silence_front = start_frame * window / sr
silence_front_offset = int(np.round(real_silence_front * sr))
audio = audio[silence_front_offset:]
f0_min = 50
f0_max = 1100
f0_mel_min = 1127 * np.log(1 + f0_min / 700)
f0_mel_max = 1127 * np.log(1 + f0_max / 700)
precision = 10.0
audio_num = audio.cpu()
onnx_f0, onnx_pd = onnxcrepe.predict(
self.onnx_session,
audio_num,
sr,
precision=precision,
fmin=f0_min,
fmax=f0_max,
batch_size=256,
return_periodicity=True,
decoder=onnxcrepe.decode.weighted_argmax,
)
f0 = onnxcrepe.filter.median(onnx_f0, 3)
pd = onnxcrepe.filter.median(onnx_pd, 3)
f0[pd < 0.1] = 0
f0 = f0.squeeze()
f0 = np.pad(f0, (start_frame, n_frames - f0.shape[0] - start_frame), 'constant', constant_values=(0, 0))
f0 *= pow(2, f0_up_key / 12)
pitchf[-f0.shape[0]:] = f0[:pitchf.shape[0]]
f0bak = pitchf.copy()
f0_mel = 1127.0 * np.log(1.0 + f0bak / 700.0)
f0_mel = np.clip(
(f0_mel - f0_mel_min) * 254.0 / (f0_mel_max - f0_mel_min) + 1.0, 1.0, 255.0
)
pitch_coarse = f0_mel.astype(int)
return pitch_coarse, pitchf

View File

@ -1,16 +1,16 @@
import torchcrepe import torchcrepe
import torch import torch
import numpy as np import numpy as np
from const import EnumPitchExtractorTypes from const import PitchExtractorType
from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor
class CrepePitchExtractor(PitchExtractor): class CrepePitchExtractor(PitchExtractor):
pitchExtractorType: EnumPitchExtractorTypes = EnumPitchExtractorTypes.crepe
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.pitchExtractorType: PitchExtractorType = "crepe"
if torch.cuda.is_available(): if torch.cuda.is_available():
self.device = torch.device("cuda:" + str(torch.cuda.current_device())) self.device = torch.device("cuda:" + str(torch.cuda.current_device()))
else: else:

View File

@ -1,16 +1,19 @@
import pyworld import pyworld
import numpy as np import numpy as np
from const import EnumPitchExtractorTypes from const import PitchExtractorType
from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor
class DioPitchExtractor(PitchExtractor): class DioPitchExtractor(PitchExtractor):
pitchExtractorType: EnumPitchExtractorTypes = EnumPitchExtractorTypes.dio
def __init__(self):
super().__init__()
self.pitchExtractorType: PitchExtractorType = "dio"
def extract(self, audio, pitchf, f0_up_key, sr, window, silence_front=0): def extract(self, audio, pitchf, f0_up_key, sr, window, silence_front=0):
audio = audio.detach().cpu().numpy() audio = audio.detach().cpu().numpy()
n_frames = int(len(audio) // window) + 1 n_frames = int(len(audio) // window) + 1 # NOQA
start_frame = int(silence_front * sr / window) start_frame = int(silence_front * sr / window)
real_silence_front = start_frame * window / sr real_silence_front = start_frame * window / sr
@ -31,7 +34,7 @@ class DioPitchExtractor(PitchExtractor):
frame_period=10, frame_period=10,
) )
f0 = pyworld.stonemask(audio.astype(np.double), _f0, t, sr) f0 = pyworld.stonemask(audio.astype(np.double), _f0, t, sr)
# f0 = np.pad(f0.astype("float"), (start_frame, n_frames - len(f0) - start_frame)) # f0 = np.pad(f0.astype("float"), (start_frame, n_frames - len(f0) - start_frame))
f0 *= pow(2, f0_up_key / 12) f0 *= pow(2, f0_up_key / 12)
pitchf[-f0.shape[0]:] = f0[:pitchf.shape[0]] pitchf[-f0.shape[0]:] = f0[:pitchf.shape[0]]
@ -45,4 +48,3 @@ class DioPitchExtractor(PitchExtractor):
pitch_coarse = np.rint(f0_mel).astype(int) pitch_coarse = np.rint(f0_mel).astype(int)
return pitch_coarse, pitchf return pitch_coarse, pitchf

View File

@ -1,17 +1,20 @@
import pyworld import pyworld
import numpy as np import numpy as np
import scipy.signal as signal import scipy.signal as signal
from const import EnumPitchExtractorTypes from const import PitchExtractorType
from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor
class HarvestPitchExtractor(PitchExtractor): class HarvestPitchExtractor(PitchExtractor):
pitchExtractorType: EnumPitchExtractorTypes = EnumPitchExtractorTypes.harvest
def __init__(self):
super().__init__()
self.pitchExtractorType: PitchExtractorType = "harvest"
def extract(self, audio, pitchf, f0_up_key, sr, window, silence_front=0): def extract(self, audio, pitchf, f0_up_key, sr, window, silence_front=0):
audio = audio.detach().cpu().numpy() audio = audio.detach().cpu().numpy()
n_frames = int(len(audio) // window) + 1 n_frames = int(len(audio) // window) + 1 # NOQA
start_frame = int(silence_front * sr / window) start_frame = int(silence_front * sr / window)
real_silence_front = start_frame * window / sr real_silence_front = start_frame * window / sr

View File

@ -1,14 +1,12 @@
from typing import Protocol from typing import Protocol
from const import EnumPitchExtractorTypes
class PitchExtractor(Protocol): class PitchExtractor(Protocol):
pitchExtractorType: EnumPitchExtractorTypes = EnumPitchExtractorTypes.harvest
def extract(self, audio, f0_up_key, sr, window, silence_front=0): def extract(self, audio, f0_up_key, sr, window, silence_front=0):
... ...
def getPitchExtractorInfo(self): def getPitchExtractorInfo(self):
return { return {
"pitchExtractorType": self.pitchExtractorType.value, "pitchExtractorType": self.pitchExtractorType,
} }

View File

@ -1,40 +1,42 @@
from typing import Protocol from typing import Protocol
from const import EnumPitchExtractorTypes from const import PitchExtractorType
from voice_changer.RVC.pitchExtractor.CrepeOnnxPitchExtractor import CrepeOnnxPitchExtractor
from voice_changer.RVC.pitchExtractor.DioPitchExtractor import DioPitchExtractor from voice_changer.RVC.pitchExtractor.DioPitchExtractor import DioPitchExtractor
from voice_changer.RVC.pitchExtractor.HarvestPitchExtractor import HarvestPitchExtractor from voice_changer.RVC.pitchExtractor.HarvestPitchExtractor import HarvestPitchExtractor
from voice_changer.RVC.pitchExtractor.CrepePitchExtractor import CrepePitchExtractor from voice_changer.RVC.pitchExtractor.CrepePitchExtractor import CrepePitchExtractor
from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor from voice_changer.RVC.pitchExtractor.PitchExtractor import PitchExtractor
from voice_changer.utils.VoiceChangerParams import VoiceChangerParams
class PitchExtractorManager(Protocol): class PitchExtractorManager(Protocol):
currentPitchExtractor: PitchExtractor | None = None currentPitchExtractor: PitchExtractor | None = None
params: VoiceChangerParams
@classmethod
def initialize(cls, params: VoiceChangerParams):
cls.params = params
@classmethod @classmethod
def getPitchExtractor( def getPitchExtractor(
cls, pitchExtractorType: EnumPitchExtractorTypes cls, pitchExtractorType: PitchExtractorType, gpu: int
) -> PitchExtractor: ) -> PitchExtractor:
cls.currentPitchExtractor = cls.loadPitchExtractor(pitchExtractorType) cls.currentPitchExtractor = cls.loadPitchExtractor(pitchExtractorType, gpu)
return cls.currentPitchExtractor return cls.currentPitchExtractor
@classmethod @classmethod
def loadPitchExtractor( def loadPitchExtractor(
cls, pitchExtractorType: EnumPitchExtractorTypes cls, pitchExtractorType: PitchExtractorType, gpu: int
) -> PitchExtractor: ) -> PitchExtractor:
if ( if pitchExtractorType == "harvest":
pitchExtractorType == EnumPitchExtractorTypes.harvest
or pitchExtractorType == EnumPitchExtractorTypes.harvest.value
):
return HarvestPitchExtractor() return HarvestPitchExtractor()
elif ( elif pitchExtractorType == "dio":
pitchExtractorType == EnumPitchExtractorTypes.dio
or pitchExtractorType == EnumPitchExtractorTypes.dio.value
):
return DioPitchExtractor() return DioPitchExtractor()
elif ( elif pitchExtractorType == "crepe":
pitchExtractorType == EnumPitchExtractorTypes.crepe
or pitchExtractorType == EnumPitchExtractorTypes.crepe.value
):
return CrepePitchExtractor() return CrepePitchExtractor()
elif pitchExtractorType == "crepe_tiny":
return CrepeOnnxPitchExtractor(pitchExtractorType, cls.params.crepe_onnx_tiny, gpu)
elif pitchExtractorType == "crepe_full":
return CrepeOnnxPitchExtractor(pitchExtractorType, cls.params.crepe_onnx_full, gpu)
else: else:
# return hubert as default # return hubert as default
raise RuntimeError( raise RuntimeError(

View File

@ -0,0 +1,8 @@
from . import decode # NOQA
from .core import * # NOQA
from . import convert # NOQA
from . import filter # NOQA
from . import load # NOQA
from . import loudness # NOQA
from .session import CrepeInferenceSession # NOQA
from . import threshold # NOQA

View File

@ -0,0 +1,57 @@
import numpy as np
import scipy
from voice_changer.RVC.pitchExtractor import onnxcrepe
###############################################################################
# Pitch unit conversions
###############################################################################
def bins_to_cents(bins, apply_dither=False):
"""Converts pitch bins to cents"""
cents = onnxcrepe.CENTS_PER_BIN * bins + 1997.3794084376191
# Trade quantization error for noise (disabled by default)
return dither(cents) if apply_dither else cents
def bins_to_frequency(bins, apply_dither=False):
"""Converts pitch bins to frequency in Hz"""
return cents_to_frequency(bins_to_cents(bins, apply_dither=apply_dither))
def cents_to_bins(cents, quantize_fn=np.floor):
"""Converts cents to pitch bins"""
bins = (cents - 1997.3794084376191) / onnxcrepe.CENTS_PER_BIN
return quantize_fn(bins).astype(np.int64)
def cents_to_frequency(cents):
"""Converts cents to frequency in Hz"""
return 10 * 2 ** (cents / 1200)
def frequency_to_bins(frequency, quantize_fn=np.floor):
"""Convert frequency in Hz to pitch bins"""
return cents_to_bins(frequency_to_cents(frequency), quantize_fn)
def frequency_to_cents(frequency):
"""Convert frequency in Hz to cents"""
return 1200 * np.log2(frequency / 10.)
###############################################################################
# Utilities
###############################################################################
def dither(cents):
"""Dither the predicted pitch in cents to remove quantization error"""
noise = scipy.stats.triang.rvs(c=0.5,
loc=-onnxcrepe.CENTS_PER_BIN,
scale=2 * onnxcrepe.CENTS_PER_BIN,
size=cents.shape)
return cents + noise.astype(cents.dtype)

View File

@ -0,0 +1,256 @@
import librosa
import numpy as np
from voice_changer.RVC.pitchExtractor import onnxcrepe
__all__ = ['CENTS_PER_BIN',
'MAX_FMAX',
'PITCH_BINS',
'SAMPLE_RATE',
'WINDOW_SIZE',
'UNVOICED',
'predict',
'preprocess',
'infer',
'postprocess',
'resample']
###############################################################################
# Constants
###############################################################################
CENTS_PER_BIN = 20 # cents
MAX_FMAX = 2006. # hz
PITCH_BINS = 360
SAMPLE_RATE = 16000 # hz
WINDOW_SIZE = 1024 # samples
UNVOICED = np.nan
###############################################################################
# Crepe pitch prediction
###############################################################################
def predict(session,
audio,
sample_rate,
precision=None,
fmin=50.,
fmax=MAX_FMAX,
decoder=onnxcrepe.decode.weighted_viterbi,
return_periodicity=False,
batch_size=None,
pad=True):
"""Performs pitch estimation
Arguments
session (onnxcrepe.CrepeInferenceSession)
An onnxruntime.InferenceSession holding the CREPE model
audio (numpy.ndarray [shape=(n_samples,)])
The audio signal
sample_rate (int)
The sampling rate in Hz
precision (float)
The precision in milliseconds, i.e. the length of each frame
fmin (float)
The minimum allowable frequency in Hz
fmax (float)
The maximum allowable frequency in Hz
decoder (function)
The decoder to use. See decode.py for decoders.
return_periodicity (bool)
Whether to also return the network confidence
batch_size (int)
The number of frames per batch
pad (bool)
Whether to zero-pad the audio
Returns
pitch (numpy.ndarray [shape=(1, 1 + int(time // precision))])
(Optional) periodicity (numpy.ndarray
[shape=(1, 1 + int(time // precision))])
"""
results = []
# Preprocess audio
generator = preprocess(audio,
sample_rate,
precision,
batch_size,
pad)
for frames in generator:
# Infer independent probabilities for each pitch bin
probabilities = infer(session, frames) # shape=(batch, 360)
probabilities = probabilities.transpose(1, 0)[None] # shape=(1, 360, batch)
# Convert probabilities to F0 and periodicity
result = postprocess(probabilities,
fmin,
fmax,
decoder,
return_periodicity)
# Place on same device as audio to allow very long inputs
if isinstance(result, tuple):
result = (result[0], result[1])
results.append(result)
# Split pitch and periodicity
if return_periodicity:
pitch, periodicity = zip(*results)
return np.concatenate(pitch, axis=1), np.concatenate(periodicity, axis=1)
# Concatenate
return np.concatenate(results, axis=1)
def preprocess(audio,
sample_rate,
precision=None,
batch_size=None,
pad=True):
"""Convert audio to model input
Arguments
audio (numpy.ndarray [shape=(time,)])
The audio signals
sample_rate (int)
The sampling rate in Hz
precision (float)
The precision in milliseconds, i.e. the length of each frame
batch_size (int)
The number of frames per batch
pad (bool)
Whether to zero-pad the audio
Returns
frames (numpy.ndarray [shape=(1 + int(time // precision), 1024)])
"""
# Resample
if sample_rate != SAMPLE_RATE:
audio = librosa.resample(audio, orig_sr=sample_rate, target_sr=SAMPLE_RATE)
# Default hop length of 10 ms
hop_length = SAMPLE_RATE / 100 if precision is None else SAMPLE_RATE * precision / 1000
# Get total number of frames
# Maybe pad
if pad:
total_frames = 1 + int(audio.shape[0] / hop_length)
audio = np.pad(
audio,
(WINDOW_SIZE // 2, WINDOW_SIZE // 2))
else:
total_frames = 1 + int((audio.shape[0] - WINDOW_SIZE) / hop_length)
# Default to running all frames in a single batch
batch_size = total_frames if batch_size is None else batch_size
# Generate batches
for i in range(0, total_frames, batch_size):
# Batch indices
start = max(0, int(i * hop_length))
end = min(audio.shape[0],
int((i + batch_size - 1) * hop_length) + WINDOW_SIZE)
# Chunk
n_bytes = audio.strides[-1]
frames = np.lib.stride_tricks.as_strided(
audio[start:end],
shape=((end - start - WINDOW_SIZE) // int(hop_length) + 1, WINDOW_SIZE),
strides=(int(hop_length) * n_bytes, n_bytes)) # shape=(batch, 1024)
# Note:
# Z-score standardization operations originally located here
# (https://github.com/maxrmorrison/torchcrepe/blob/master/torchcrepe/core.py#L692)
# are wrapped into the ONNX models for hardware acceleration.
yield frames
def infer(session, frames):
"""Forward pass through the model
Arguments
session (onnxcrepe.CrepeInferenceSession)
An onnxruntime.InferenceSession holding the CREPE model
frames (numpy.ndarray [shape=(time / precision, 1024)])
The network input
Returns
logits (numpy.ndarray [shape=(1 + int(time // precision), 360)])
"""
# Apply model
return session.run(None, {'frames': frames})[0]
def postprocess(probabilities,
fmin=0.,
fmax=MAX_FMAX,
decoder=onnxcrepe.decode.weighted_viterbi,
return_periodicity=False):
"""Convert model output to F0 and periodicity
Arguments
probabilities (numpy.ndarray [shape=(1, 360, time / precision)])
The probabilities for each pitch bin inferred by the network
fmin (float)
The minimum allowable frequency in Hz
fmax (float)
The maximum allowable frequency in Hz
decoder (function)
The decoder to use. See decode.py for decoders.
return_periodicity (bool)
Whether to also return the network confidence
Returns
pitch (numpy.ndarray [shape=(1, 1 + int(time // precision))])
periodicity (numpy.ndarray [shape=(1, 1 + int(time // precision))])
"""
# Convert frequency range to pitch bin range
minidx = onnxcrepe.convert.frequency_to_bins(fmin)
maxidx = onnxcrepe.convert.frequency_to_bins(fmax, np.ceil)
# Remove frequencies outside allowable range
probabilities[:, :minidx] = float('-inf')
probabilities[:, maxidx:] = float('-inf')
# Perform argmax or viterbi sampling
bins, pitch = decoder(probabilities)
if not return_periodicity:
return pitch
# Compute periodicity from probabilities and decoded pitch bins
return pitch, periodicity(probabilities, bins)
###############################################################################
# Utilities
###############################################################################
def periodicity(probabilities, bins):
"""Computes the periodicity from the network output and pitch bins"""
# shape=(time / precision, 360)
probs_stacked = probabilities.transpose(0, 2, 1).reshape(-1, PITCH_BINS)
# shape=(time / precision, 1)
bins_stacked = bins.reshape(-1, 1).astype(np.int64)
# Use maximum logit over pitch bins as periodicity
periodicity = np.take_along_axis(probs_stacked, bins_stacked, axis=1)
# shape=(batch, time / precision)
return periodicity.reshape(probabilities.shape[0], probabilities.shape[2])
def resample(audio, sample_rate):
"""Resample audio"""
return librosa.resample(audio, orig_sr=sample_rate, target_sr=onnxcrepe.SAMPLE_RATE)

View File

@ -0,0 +1,80 @@
import librosa
import numpy as np
from voice_changer.RVC.pitchExtractor import onnxcrepe
###############################################################################
# Probability sequence decoding methods
###############################################################################
def argmax(logits):
"""Sample observations by taking the argmax"""
bins = logits.argmax(axis=1)
# Convert to frequency in Hz
return bins, onnxcrepe.convert.bins_to_frequency(bins)
def weighted_argmax(logits: np.ndarray):
"""Sample observations using weighted sum near the argmax"""
# Find center of analysis window
bins = logits.argmax(axis=1)
return bins, _apply_weights(logits, bins)
def viterbi(logits):
"""Sample observations using viterbi decoding"""
# Create viterbi transition matrix
if not hasattr(viterbi, 'transition'):
xx, yy = np.meshgrid(range(360), range(360))
transition = np.maximum(12 - abs(xx - yy), 0)
transition = transition / transition.sum(axis=1, keepdims=True)
viterbi.transition = transition
# Normalize logits (softmax)
logits -= logits.max(axis=1)
exp = np.exp(logits)
probs = exp / np.sum(exp, axis=1)
# Perform viterbi decoding
bins = np.array([
librosa.sequence.viterbi(sequence, viterbi.transition).astype(np.int64)
for sequence in probs])
# Convert to frequency in Hz
return bins, onnxcrepe.convert.bins_to_frequency(bins)
def weighted_viterbi(logits):
"""Sample observations combining viterbi decoding and weighted argmax"""
bins, _ = viterbi(logits)
return bins, _apply_weights(logits, bins)
def _apply_weights(logits, bins):
# Find bounds of analysis window
start = np.maximum(0, bins - 4)
end = np.minimum(logits.shape[1], bins + 5)
# Mask out everything outside of window
for batch in range(logits.shape[0]):
for time in range(logits.shape[2]):
logits[batch, :start[batch, time], time] = float('-inf')
logits[batch, end[batch, time]:, time] = float('-inf')
# Construct weights
if not hasattr(_apply_weights, 'weights'):
weights = onnxcrepe.convert.bins_to_cents(np.arange(360))
_apply_weights.weights = weights[None, :, None]
# Convert to probabilities (ReLU)
probs = np.maximum(0, logits)
# Apply weights
cents = (_apply_weights.weights * probs).sum(axis=1) / probs.sum(axis=1)
# Convert to frequency in Hz
return onnxcrepe.convert.cents_to_frequency(cents)

View File

@ -0,0 +1,125 @@
import numpy as np
###############################################################################
# Sequence filters
###############################################################################
def mean(signals, win_length=9):
"""Averave filtering for signals containing nan values
Arguments
signals (numpy.ndarray (shape=(batch, time)))
The signals to filter
win_length
The size of the analysis window
Returns
filtered (numpy.ndarray (shape=(batch, time)))
"""
return nanfilter(signals, win_length, nanmean)
def median(signals, win_length):
"""Median filtering for signals containing nan values
Arguments
signals (numpy.ndarray (shape=(batch, time)))
The signals to filter
win_length
The size of the analysis window
Returns
filtered (numpy.ndarray (shape=(batch, time)))
"""
return nanfilter(signals, win_length, nanmedian)
###############################################################################
# Utilities
###############################################################################
def nanfilter(signals, win_length, filter_fn):
"""Filters a sequence, ignoring nan values
Arguments
signals (numpy.ndarray (shape=(batch, time)))
The signals to filter
win_length
The size of the analysis window
filter_fn (function)
The function to use for filtering
Returns
filtered (numpy.ndarray (shape=(batch, time)))
"""
# Output buffer
filtered = np.empty_like(signals)
# Loop over frames
for i in range(signals.shape[1]):
# Get analysis window bounds
start = max(0, i - win_length // 2)
end = min(signals.shape[1], i + win_length // 2 + 1)
# Apply filter to window
filtered[:, i] = filter_fn(signals[:, start:end])
return filtered
def nanmean(signals):
"""Computes the mean, ignoring nans
Arguments
signals (numpy.ndarray [shape=(batch, time)])
The signals to filter
Returns
filtered (numpy.ndarray [shape=(batch, time)])
"""
signals = signals.clone()
# Find nans
nans = np.isnan(signals)
# Set nans to 0.
signals[nans] = 0.
# Compute average
return signals.sum(axis=1) / (~nans).astype(np.float32).sum(axis=1)
def nanmedian(signals):
"""Computes the median, ignoring nans
Arguments
signals (numpy.ndarray [shape=(batch, time)])
The signals to filter
Returns
filtered (numpy.ndarray [shape=(batch, time)])
"""
# Find nans
nans = np.isnan(signals)
# Compute median for each slice
medians = [nanmedian1d(signal[~nan]) for signal, nan in zip(signals, nans)]
# Stack results
return np.array(medians, dtype=signals.dtype)
def nanmedian1d(signal):
"""Computes the median. If signal is empty, returns torch.nan
Arguments
signal (numpy.ndarray [shape=(time,)])
Returns
median (numpy.ndarray [shape=(1,)])
"""
return np.median(signal) if signal.size else np.nan

View File

@ -0,0 +1,12 @@
import librosa
import numpy as np
def audio(filename):
"""Load audio from disk"""
samples, sr = librosa.load(filename, sr=None)
if len(samples.shape) > 1:
# To mono
samples = np.mean(samples, axis=1)
return samples, sr

View File

@ -0,0 +1,73 @@
import warnings
import librosa
import numpy as np
from voice_changer.RVC.pitchExtractor import onnxcrepe
###############################################################################
# Constants
###############################################################################
# Minimum decibel level
MIN_DB = -100.
# Reference decibel level
REF_DB = 20.
###############################################################################
# A-weighted loudness
###############################################################################
def a_weighted(audio, sample_rate, hop_length=None, pad=True):
"""Retrieve the per-frame loudness"""
# Default hop length of 10 ms
hop_length = sample_rate // 100 if hop_length is None else hop_length
# Convert to numpy
audio = audio.squeeze(0)
# Resample
if sample_rate != onnxcrepe.SAMPLE_RATE:
audio = librosa.resample(audio, orig_sr=sample_rate, target_sr=onnxcrepe.SAMPLE_RATE)
hop_length = int(hop_length * onnxcrepe.SAMPLE_RATE / sample_rate)
# Cache weights
if not hasattr(a_weighted, 'weights'):
a_weighted.weights = perceptual_weights()
# Take stft
stft = librosa.stft(audio,
n_fft=onnxcrepe.WINDOW_SIZE,
hop_length=hop_length,
win_length=onnxcrepe.WINDOW_SIZE,
center=pad,
pad_mode='constant')
# Compute magnitude on db scale
db = librosa.amplitude_to_db(np.abs(stft))
# Apply A-weighting
weighted = db + a_weighted.weights
# Threshold
weighted[weighted < MIN_DB] = MIN_DB
# Average over weighted frequencies
return weighted.mean(axis=0).astype(np.float32)[None]
def perceptual_weights():
"""A-weighted frequency-dependent perceptual loudness weights"""
frequencies = librosa.fft_frequencies(sr=onnxcrepe.SAMPLE_RATE,
n_fft=onnxcrepe.WINDOW_SIZE)
# A warning is raised for nearly inaudible frequencies, but it ends up
# defaulting to -100 db. That default is fine for our purposes.
with warnings.catch_warnings():
warnings.simplefilter('ignore', RuntimeWarning)
return librosa.A_weighting(frequencies)[:, None] - REF_DB

View File

@ -0,0 +1 @@
modules in this folder from https://github.com/yqzhishen/onnxcrepe at ca7e5d7f2dfca5cc4d99e8d546b00793ca4e7157

View File

@ -0,0 +1,9 @@
import os
import onnxruntime as ort
class CrepeInferenceSession(ort.InferenceSession):
def __init__(self, model='full', sess_options=None, providers=None, provider_options=None, **kwargs):
model_path = os.path.join(os.path.dirname(__file__), 'assets', f'{model}.onnx')
super().__init__(model_path, sess_options, providers, provider_options, **kwargs)

View File

@ -0,0 +1,129 @@
import numpy as np
from voice_changer.RVC.pitchExtractor import onnxcrepe
###############################################################################
# Pitch thresholding methods
###############################################################################
class At:
"""Simple thresholding at a specified probability value"""
def __init__(self, value):
self.value = value
def __call__(self, pitch, periodicity):
# Make a copy to prevent in-place modification
pitch = pitch.copy()
# Threshold
pitch[periodicity < self.value] = onnxcrepe.UNVOICED
return pitch
class Hysteresis:
"""Hysteresis thresholding"""
def __init__(self,
lower_bound=.19,
upper_bound=.31,
width=.2,
stds=1.7,
return_threshold=False):
self.lower_bound = lower_bound
self.upper_bound = upper_bound
self.width = width
self.stds = stds
self.return_threshold = return_threshold
def __call__(self, pitch, periodicity):
# Perform hysteresis in log-2 space
pitch = np.log2(pitch).flatten()
# Flatten periodicity
periodicity = periodicity.flatten()
# Ignore confidently unvoiced pitch
pitch[periodicity < self.lower_bound] = onnxcrepe.UNVOICED
# Whiten pitch
mean, std = np.nanmean(pitch), np.nanstd(pitch)
pitch = (pitch - mean) / std
# Require high confidence to make predictions far from the mean
parabola = self.width * pitch ** 2 - self.width * self.stds ** 2
threshold = self.lower_bound + np.clip(parabola, 0, 1 - self.lower_bound)
threshold[np.isnan(threshold)] = self.lower_bound
# Apply hysteresis to prevent short, unconfident voiced regions
i = 0
while i < len(periodicity) - 1:
# Detect unvoiced to voiced transition
if periodicity[i] < threshold[i] and periodicity[i + 1] > threshold[i + 1]:
# Grow region until next unvoiced or end of array
start, end, keep = i + 1, i + 1, False
while end < len(periodicity) and periodicity[end] > threshold[end]:
if periodicity[end] > self.upper_bound:
keep = True
end += 1
# Force unvoiced if we didn't pass the confidence required by
# the hysteresis
if not keep:
threshold[start:end] = 1
i = end
else:
i += 1
# Remove pitch with low periodicity
pitch[periodicity < threshold] = onnxcrepe.UNVOICED
# Unwhiten
pitch = pitch * std + mean
# Convert to Hz
pitch = np.array(2 ** pitch)[None, :]
# Optionally return threshold
if self.return_threshold:
return pitch, np.array(threshold)
return pitch
###############################################################################
# Periodicity thresholding methods
###############################################################################
class Silence:
"""Set periodicity to zero in silent regions"""
def __init__(self, value=-60):
self.value = value
def __call__(self,
periodicity,
audio,
sample_rate=onnxcrepe.SAMPLE_RATE,
precision=None,
pad=True):
# Don't modify in-place
periodicity = periodicity.copy()
# Compute loudness
hop_length = sample_rate * precision // 1000
loudness = onnxcrepe.loudness.a_weighted(
audio, sample_rate, hop_length, pad)
# Threshold silence
periodicity[loudness < self.value] = 0.
return periodicity

View File

@ -1,5 +1,6 @@
import json import json
import os import os
import sys
import shutil import shutil
import threading import threading
import numpy as np import numpy as np
@ -169,6 +170,7 @@ class VoiceChangerManager(ServerDeviceCallbacks):
data["gpus"] = self.gpus data["gpus"] = self.gpus
data["modelSlots"] = self.modelSlotManager.getAllSlotInfo(reload=True) data["modelSlots"] = self.modelSlotManager.getAllSlotInfo(reload=True)
data["sampleModels"] = getSampleInfos(self.params.sample_mode) data["sampleModels"] = getSampleInfos(self.params.sample_mode)
data["python"] = sys.version
data["status"] = "OK" data["status"] = "OK"

View File

@ -12,3 +12,5 @@ class VoiceChangerParams:
hubert_soft: str hubert_soft: str
nsf_hifigan: str nsf_hifigan: str
sample_mode: str sample_mode: str
crepe_onnx_full: str
crepe_onnx_tiny: str

View File

@ -80,6 +80,14 @@ Q3. The pitch is off.
A3. Although it wasn't explained in the Quick Start, if the model is pitch-changeable, you can change it with TUNE. Please refer to the more detailed explanation below. A3. Although it wasn't explained in the Quick Start, if the model is pitch-changeable, you can change it with TUNE. Please refer to the more detailed explanation below.
Q4. The window doesn't show up or the window shows up but the contents are not displayed. A console error such as `electron: Failed to load URL: http://localhost:18888/ with error: ERR_CONNECTION_REFUSED` is displayed.
A4. There is a possibility that the virus checker is running. Please wait or designate the folder to be excluded at your own risk.
Q5. `[4716:0429/213736.103:ERROR:gpu_init.cc(523)] Passthrough is not supported, GL is disabled, ANGLE is` is displayed
A5. This is an error produced by the library used by this application, but it does not have any effect, so please ignore it.
## Configurable items ## Configurable items
## Title ## Title

View File

@ -36,6 +36,7 @@
`.bat`ファイル(win)や`.command`ファイル(mac)を実行すると、次のような画面が表示され、初回起動時には各種データをインターネットからダウンロードします。 `.bat`ファイル(win)や`.command`ファイル(mac)を実行すると、次のような画面が表示され、初回起動時には各種データをインターネットからダウンロードします。
お使いの環境によりますが、多くの場合1~2分かかります。 お使いの環境によりますが、多くの場合1~2分かかります。
![image](https://github.com/w-okada/voice-changer/assets/48346627/88a30097-2fb3-4c50-8bf1-19c41f27c481) ![image](https://github.com/w-okada/voice-changer/assets/48346627/88a30097-2fb3-4c50-8bf1-19c41f27c481)
### GUI 表示 ### GUI 表示
@ -80,6 +81,14 @@ Q3. 音程がおかしい
A3. クイックスタートでは説明しませんでしたが、Pitch 変更可能なモデルであれば TUNE で変更できます。後述の詳細説明をご確認ください。 A3. クイックスタートでは説明しませんでしたが、Pitch 変更可能なモデルであれば TUNE で変更できます。後述の詳細説明をご確認ください。
Q4. ウィンドウが表示されない。あるいはウィンドウは表示されるが中身が表示されない。コンソールに`electron: Failed to load URL: http://localhost:18888/ with error: ERR_CONNECTION_REFUSED`のようなエラーが表示される。
A4. ウィルスチェッカーが走っている可能性があります。しばらく待つか、自己責任でフォルダを除外指定してください。
Q5. `[4716:0429/213736.103:ERROR:gpu_init.cc(523)] Passthrough is not supported, GL is disabled, ANGLE is`という表示が出る
A5. 使用しているライブラリが出しているエラーです。影響はありませんので無視してください。
# GUI の詳細 # GUI の詳細
## タイトルエリア ## タイトルエリア