From 06a5250f61c40fc0508f0668f0808ae6a225e3f9 Mon Sep 17 00:00:00 2001 From: wataru Date: Wed, 21 Jun 2023 07:23:13 +0900 Subject: [PATCH] WIP: integrate vcs to new gui 2 --- server/data/ModelSlot.py | 38 +-- server/downloader/SampleDownloader.py | 2 +- server/voice_changer/RVC/RVC.py | 320 +++++++------------- server/voice_changer/RVC/RVCSettings.py | 1 - server/voice_changer/VoiceChanger.py | 71 ++--- server/voice_changer/VoiceChangerManager.py | 63 +++- 6 files changed, 211 insertions(+), 284 deletions(-) diff --git a/server/data/ModelSlot.py b/server/data/ModelSlot.py index 0afe0c5b..5ed0b0c8 100644 --- a/server/data/ModelSlot.py +++ b/server/data/ModelSlot.py @@ -10,6 +10,11 @@ import json @dataclass class ModelSlot: voiceChangerType: VoiceChangerType | None = None + name: str = "" + description: str = "" + credit: str = "" + termsOfUseUrl: str = "" + iconFile: str = "" @dataclass @@ -30,12 +35,7 @@ class RVCModelSlot(ModelSlot): deprecated: bool = False embedder: str = EnumEmbedderTypes.hubert.value - name: str = "" - description: str = "" - credit: str = "" - termsOfUseUrl: str = "" sampleId: str = "" - iconFile: str = "" @dataclass @@ -48,10 +48,6 @@ class MMVCv13ModelSlot(ModelSlot): isONNX: bool = False samplingRate: int = 24000 - name: str = "" - description: str = "" - iconFile: str = "" - @dataclass class MMVCv15ModelSlot(ModelSlot): @@ -60,13 +56,10 @@ class MMVCv15ModelSlot(ModelSlot): configFile: str = "" srcId: int = 0 dstId: int = 101 + f0Factor: float = 1.0 isONNX: bool = False samplingRate: int = 24000 - name: str = "" - description: str = "" - iconFile: str = "" - @dataclass class SoVitsSvc40ModelSlot(ModelSlot): @@ -77,12 +70,11 @@ class SoVitsSvc40ModelSlot(ModelSlot): dstId: int = 0 isONNX: bool = False - name: str = "" - description: str = "" - credit: str = "" - termsOfUseUrl: str = "" sampleId: str = "" - iconFile: str = "" + + defaultTune: int = 0 + defaultClusterInferRatio: float = 0.0 + noiseScale: float = 0.0 @dataclass @@ -95,12 +87,12 @@ class DDSPSVCModelSlot(ModelSlot): dstId: int = 0 isONNX: bool = False - name: str = "" - description: str = "" - credit: str = "" - termsOfUseUrl: str = "" sampleId: str = "" - iconFile: str = "" + defaultTune: int = 0 + enhancer: bool = False + diffusion: bool = True + acc: int = 20 + kstep: int = 100 ModelSlots: TypeAlias = Union[ModelSlot, RVCModelSlot, MMVCv13ModelSlot, MMVCv15ModelSlot, SoVitsSvc40ModelSlot, DDSPSVCModelSlot] diff --git a/server/downloader/SampleDownloader.py b/server/downloader/SampleDownloader.py index ecb5a08e..e862f009 100644 --- a/server/downloader/SampleDownloader.py +++ b/server/downloader/SampleDownloader.py @@ -15,7 +15,7 @@ def downloadInitialSamples(mode: RVCSampleMode, model_dir: str): sampleJsonUrls, sampleModels = getSampleJsonAndModelIds(mode) sampleJsons = _downloadSampleJsons(sampleJsonUrls) if os.path.exists(model_dir): - print("[Voice Changer] model_dir is already exists. skil download samples.") + print("[Voice Changer] model_dir is already exists. skip download samples.") return samples = _generateSampleList(sampleJsons) slotIndex = list(range(len(sampleModels))) diff --git a/server/voice_changer/RVC/RVC.py b/server/voice_changer/RVC/RVC.py index 5f1e86cd..9fe0154e 100644 --- a/server/voice_changer/RVC/RVC.py +++ b/server/voice_changer/RVC/RVC.py @@ -1,12 +1,10 @@ import sys import os from dataclasses import asdict -from typing import cast import numpy as np import torch import torchaudio from data.ModelSlot import RVCModelSlot -from voice_changer.ModelSlotManager import ModelSlotManager # avoiding parse arg error in RVC @@ -22,15 +20,13 @@ if sys.platform.startswith("darwin"): else: sys.path.append("RVC") -from voice_changer.RVC.modelMerger.MergeModel import merge_model -from voice_changer.RVC.modelMerger.MergeModelRequest import MergeModelRequest from voice_changer.RVC.ModelSlotGenerator import ( _setInfoByONNX, _setInfoByPytorch, ) from voice_changer.RVC.RVCSettings import RVCSettings from voice_changer.RVC.embedder.EmbedderManager import EmbedderManager -from voice_changer.utils.LoadModelParams import LoadModelParams, LoadModelParams2 +from voice_changer.utils.LoadModelParams import LoadModelParams2 from voice_changer.utils.VoiceChangerModel import AudioInOut from voice_changer.utils.VoiceChangerParams import VoiceChangerParams from voice_changer.RVC.onnxExporter.export2onnx import export2onnx @@ -40,11 +36,6 @@ from voice_changer.RVC.deviceManager.DeviceManager import DeviceManager from voice_changer.RVC.pipeline.Pipeline import Pipeline from Exceptions import DeviceCannotSupportHalfPrecisionException, NoModeLoadedException -from const import ( - UPLOAD_DIR, -) -import shutil -import json class RVC: @@ -61,34 +52,29 @@ class RVC: currentSlot: int = 0 needSwitch: bool = False - def __init__(self, params: VoiceChangerParams): - self.pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector) - self.params = params + def __init__(self, params: VoiceChangerParams, slotInfo: RVCModelSlot): + print("[Voice Changer][RVC] Creating instance ") EmbedderManager.initialize(params) - print("[Voice Changer] RVC initialization: ", params) - self.modelSlotManager = ModelSlotManager.get_instance(self.params.model_dir) - # 起動時にスロットにモデルがある場合はロードしておく - allSlots = self.modelSlotManager.getAllSlotInfo() - availableIndex = -1 - for i, slot in enumerate(allSlots): - if slot.modelFile is not None and slot.modelFile != "": - availableIndex = i - break - if availableIndex >= 0: - self.prepareModel(availableIndex) - self.settings.modelSlotIndex = availableIndex - self.switchModel(self.settings.modelSlotIndex) - self.initialLoad = False + self.params = params + self.pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector) self.prevVol = 0.0 + self.slotInfo = slotInfo + self.initialize() - def moveToModelDir(self, file: str, dstDir: str): - dst = os.path.join(dstDir, os.path.basename(file)) - if os.path.exists(dst): - os.remove(dst) - shutil.move(file, dst) - return dst + def initialize(self): + print("[Voice Changer][RVC] Initializing... ") + + # pipelineの生成 + self.pipeline = createPipeline(self.slotInfo, self.settings.gpu, self.settings.f0Detector) + + # その他の設定 + self.trans = self.slotInfo.defaultTune + self.index_ratio = self.slotInfo.defaultIndexRatio + self.protect = self.slotInfo.defaultProtect + self.samplingRate = self.slotInfo.samplingRate + print("[Voice Changer][RVC] Initializing... done") @classmethod def loadModel2(cls, props: LoadModelParams2): @@ -111,70 +97,13 @@ class RVC: _setInfoByPytorch(slotInfo) return slotInfo - def loadModel(self, props: LoadModelParams): - target_slot_idx = props.slot - params = props.params - slotInfo: RVCModelSlot = RVCModelSlot() - - print("loadModel", params) - slotInfo.modelFile = params["files"]["rvcModel"] - slotInfo.indexFile = params["files"]["rvcIndex"] if "rvcIndex" in params["files"] else None - - slotInfo.defaultTune = params["defaultTune"] - slotInfo.defaultIndexRatio = params["defaultIndexRatio"] - slotInfo.defaultProtect = params["defaultProtect"] - slotInfo.voiceChangerType = "RVC" - slotInfo.isONNX = slotInfo.modelFile.endswith(".onnx") - - if slotInfo.isONNX: - _setInfoByONNX(slotInfo) - else: - _setInfoByPytorch(slotInfo) - - # メタデータを見て、永続化モデルフォルダに移動させる - # その際に、メタデータのファイル格納場所も書き換える - slotDir = os.path.join(self.params.model_dir, str(target_slot_idx)) - os.makedirs(slotDir, exist_ok=True) - slotInfo.modelFile = self.moveToModelDir(slotInfo.modelFile, slotDir) - if slotInfo.indexFile is not None and len(slotInfo.indexFile) > 0: - slotInfo.indexFile = self.moveToModelDir(slotInfo.indexFile, slotDir) - if slotInfo.iconFile is not None and len(slotInfo.iconFile) > 0: - slotInfo.iconFile = self.moveToModelDir(slotInfo.iconFile, slotDir) - # json.dump(asdict(slotInfo), open(os.path.join(slotDir, "params.json"), "w")) - self.modelSlotManager.save_model_slot(target_slot_idx, slotInfo) - - # 初回のみロード(起動時にスロットにモデルがあった場合はinitialLoadはFalseになっている) - if self.initialLoad: - self.prepareModel(target_slot_idx) - self.settings.modelSlotIndex = target_slot_idx - self.switchModel(self.settings.modelSlotIndex) - self.initialLoad = False - elif target_slot_idx == self.currentSlot: - self.prepareModel(target_slot_idx) - - return self.get_info() - def update_settings(self, key: str, val: int | float | str): + print("[Voice Changer][RVC]: update_settings", key, val) if key in self.settings.intData: - # 設定前処理 - val = cast(int, val) - if key == "modelSlotIndex": - if val < 0: - return True - val = val % 1000 # Quick hack for same slot is selected - allModelSlots = self.modelSlotManager.getAllSlotInfo() - if allModelSlots[val].modelFile is None or allModelSlots[val].modelFile == "": - print("[Voice Changer] slot does not have model.") - return True - self.prepareModel(val) - - # 設定 - setattr(self.settings, key, val) - + setattr(self.settings, key, int(val)) if key == "gpu": self.deviceManager.setForceTensor(False) - self.prepareModel(self.settings.modelSlotIndex) - + self.initialize() elif key in self.settings.floatData: setattr(self.settings, key, float(val)) elif key in self.settings.strData: @@ -186,44 +115,6 @@ class RVC: return False return True - def prepareModel(self, slot: int): - if slot < 0: - print("[Voice Changer] Prepare Model of slot skip:", slot) - return self.get_info() - allModelSlots = self.modelSlotManager.getAllSlotInfo() - modelSlot = allModelSlots[slot] - - print("[Voice Changer] Prepare Model of slot:", slot) - - # pipelineの生成 - self.next_pipeline = createPipeline(modelSlot, self.settings.gpu, self.settings.f0Detector) - - # その他の設定 - self.next_trans = modelSlot.defaultTune - self.next_index_ratio = modelSlot.defaultIndexRatio - self.next_protect = modelSlot.defaultProtect - self.next_samplingRate = modelSlot.samplingRate - self.next_framework = "ONNX" if modelSlot.isONNX else "PyTorch" - # self.needSwitch = True - print("[Voice Changer] Prepare done.") - self.switchModel(slot) - return self.get_info() - - def switchModel(self, slot: int): - print("[Voice Changer] Switching model..") - self.pipeline = self.next_pipeline - self.settings.tran = self.next_trans - self.settings.indexRatio = self.next_index_ratio - self.settings.protect = self.next_protect - self.settings.modelSamplingRate = self.next_samplingRate - self.settings.framework = self.next_framework - - # self.currentSlot = self.settings.modelSlotIndex # prepareModelから呼ばれるということはupdate_settingsの中で呼ばれるということなので、まだmodelSlotIndexは更新されていない - self.currentSlot = slot - print( - "[Voice Changer] Switching model..done", - ) - def get_info(self): data = asdict(self.settings) if self.pipeline is not None: @@ -279,22 +170,13 @@ class RVC: return (audio_buffer, convertSize, vol) def inference(self, data): - if self.settings.modelSlotIndex < 0: - print( - "[Voice Changer] wait for loading model...", - self.settings.modelSlotIndex, - self.currentSlot, - ) - raise NoModeLoadedException("model_common") - # if self.needSwitch: + # if self.settings.modelSlotIndex < 0: # print( - # f"[Voice Changer] Switch model {self.currentSlot} -> {self.settings.modelSlotIndex}" + # "[Voice Changer] wait for loading model...", + # self.settings.modelSlotIndex, + # self.currentSlot, # ) - # self.switchModel() - # self.needSwitch = False - - # half = self.deviceManager.halfPrecisionAvailable(self.settings.gpu) - # half = self.pipeline.isHalf + # raise NoModeLoadedException("model_common") audio = data[0] convertSize = data[1] @@ -314,9 +196,9 @@ class RVC: # embOutputLayer = self.settings.modelSlots[self.currentSlot].embOutputLayer # useFinalProj = self.settings.modelSlots[self.currentSlot].useFinalProj - if_f0 = 1 if self.modelSlotManager.get_slot_info(self.currentSlot).f0 else 0 - embOutputLayer = self.modelSlotManager.get_slot_info(self.currentSlot).embOutputLayer - useFinalProj = self.modelSlotManager.get_slot_info(self.currentSlot).useFinalProj + if_f0 = 1 if self.slotInfo.f0 else 0 + embOutputLayer = self.slotInfo.embOutputLayer + useFinalProj = self.slotInfo.useFinalProj try: audio_out = self.pipeline.exec( @@ -345,7 +227,7 @@ class RVC: def __del__(self): del self.pipeline - # print("---------- REMOVING ---------------") + print("---------- REMOVING ---------------") remove_path = os.path.join("RVC") sys.path = [x for x in sys.path if x.endswith(remove_path) is False] @@ -378,70 +260,86 @@ class RVC: def merge_models(self, request: str): print("[Voice Changer] MergeRequest:", request) - req: MergeModelRequest = MergeModelRequest.from_json(request) - merged = merge_model(req) - targetSlot = 0 - if req.slot < 0: - # 最後尾のスロット番号を格納先とする。 - allModelSlots = self.modelSlotManager.getAllSlotInfo() - targetSlot = len(allModelSlots) - 1 - else: - targetSlot = req.slot + # req: MergeModelRequest = MergeModelRequest.from_json(request) + # merged = merge_model(req) + # targetSlot = 0 + # if req.slot < 0: + # # 最後尾のスロット番号を格納先とする。 + # allModelSlots = self.modelSlotManager.getAllSlotInfo() + # targetSlot = len(allModelSlots) - 1 + # else: + # targetSlot = req.slot - # いったんは、アップロードフォルダに格納する。(歴史的経緯) - # 後続のloadmodelを呼び出すことで永続化モデルフォルダに移動させられる。 - storeDir = os.path.join(UPLOAD_DIR, f"{targetSlot}") - print("[Voice Changer] store merged model to:", storeDir) - os.makedirs(storeDir, exist_ok=True) - storeFile = os.path.join(storeDir, "merged.pth") - torch.save(merged, storeFile) + # # いったんは、アップロードフォルダに格納する。(歴史的経緯) + # # 後続のloadmodelを呼び出すことで永続化モデルフォルダに移動させられる。 + # storeDir = os.path.join(UPLOAD_DIR, f"{targetSlot}") + # print("[Voice Changer] store merged model to:", storeDir) + # os.makedirs(storeDir, exist_ok=True) + # storeFile = os.path.join(storeDir, "merged.pth") + # torch.save(merged, storeFile) - # loadmodelを呼び出して永続化モデルフォルダに移動させる。 - params = { - "defaultTune": req.defaultTune, - "defaultIndexRatio": req.defaultIndexRatio, - "defaultProtect": req.defaultProtect, - "sampleId": "", - "files": {"rvcModel": storeFile}, - } - props: LoadModelParams = LoadModelParams(slot=targetSlot, isHalf=True, params=params) - self.loadModel(props) - self.prepareModel(targetSlot) - self.settings.modelSlotIndex = targetSlot - self.currentSlot = self.settings.modelSlotIndex + # # loadmodelを呼び出して永続化モデルフォルダに移動させる。 + # params = { + # "defaultTune": req.defaultTune, + # "defaultIndexRatio": req.defaultIndexRatio, + # "defaultProtect": req.defaultProtect, + # "sampleId": "", + # "files": {"rvcModel": storeFile}, + # } + # props: LoadModelParams = LoadModelParams(slot=targetSlot, isHalf=True, params=params) + # self.loadModel(props) + # self.prepareModel(targetSlot) + # self.settings.modelSlotIndex = targetSlot + # self.currentSlot = self.settings.modelSlotIndex - def update_model_default(self): - # {"slot":9,"key":"name","val":"dogsdododg"} - self.modelSlotManager.update_model_info( - json.dumps( - { - "slot": self.currentSlot, - "key": "defaultTune", - "val": self.settings.tran, - } - ) - ) - self.modelSlotManager.update_model_info( - json.dumps( - { - "slot": self.currentSlot, - "key": "defaultIndexRatio", - "val": self.settings.indexRatio, - } - ) - ) - self.modelSlotManager.update_model_info( - json.dumps( - { - "slot": self.currentSlot, - "key": "defaultProtect", - "val": self.settings.protect, - } - ) - ) + # def update_model_default(self): + # # {"slot":9,"key":"name","val":"dogsdododg"} + # self.modelSlotManager.update_model_info( + # json.dumps( + # { + # "slot": self.currentSlot, + # "key": "defaultTune", + # "val": self.settings.tran, + # } + # ) + # ) + # self.modelSlotManager.update_model_info( + # json.dumps( + # { + # "slot": self.currentSlot, + # "key": "defaultIndexRatio", + # "val": self.settings.indexRatio, + # } + # ) + # ) + # self.modelSlotManager.update_model_info( + # json.dumps( + # { + # "slot": self.currentSlot, + # "key": "defaultProtect", + # "val": self.settings.protect, + # } + # ) + # ) - def update_model_info(self, newData: str): - self.modelSlotManager.update_model_info(newData) + def get_model_current(self): + return [ + { + "key": "defaultTune", + "val": self.settings.tran, + }, + { + "key": "defaultIndexRatio", + "val": self.settings.indexRatio, + }, + { + "key": "defaultProtect", + "val": self.settings.protect, + }, + ] - def upload_model_assets(self, params: str): - self.modelSlotManager.store_model_assets(params) + # def update_model_info(self, newData: str): + # self.modelSlotManager.update_model_info(newData) + + # def upload_model_assets(self, params: str): + # self.modelSlotManager.store_model_assets(params) diff --git a/server/voice_changer/RVC/RVCSettings.py b/server/voice_changer/RVC/RVCSettings.py index caddc0cf..25f1381e 100644 --- a/server/voice_changer/RVC/RVCSettings.py +++ b/server/voice_changer/RVC/RVCSettings.py @@ -19,7 +19,6 @@ class RVCSettings: rvcQuality: int = 0 silenceFront: int = 1 # 0:off, 1:on modelSamplingRate: int = 48000 - modelSlotIndex: int = -1 speakers: dict[str, int] = field(default_factory=lambda: {}) isHalf: int = 1 # 0:off, 1:on diff --git a/server/voice_changer/VoiceChanger.py b/server/voice_changer/VoiceChanger.py index 5c759b20..0a859230 100755 --- a/server/voice_changer/VoiceChanger.py +++ b/server/voice_changer/VoiceChanger.py @@ -80,48 +80,51 @@ class VoiceChanger: print(f"VoiceChanger Initialized (GPU_NUM:{self.gpu_num}, mps_enabled:{self.mps_enabled})") - def switchModelType(self, modelType: ModelType): - print("Switch Model Type:", modelType) - try: - if self.voiceChanger is not None: - # return {"status": "ERROR", "msg": "vc is already selected. currently re-select is not implemented"} - del self.voiceChanger - self.voiceChanger = None + def setModel(self, model: Any): + self.voiceChanger = model - self.modelType = modelType - if self.modelType == "MMVCv15": - from voice_changer.MMVCv15.MMVCv15 import MMVCv15 + # def switchModelType(self, modelType: ModelType): + # print("Switch Model Type:", modelType) + # try: + # if self.voiceChanger is not None: + # # return {"status": "ERROR", "msg": "vc is already selected. currently re-select is not implemented"} + # del self.voiceChanger + # self.voiceChanger = None - self.voiceChanger = MMVCv15() # type: ignore - elif self.modelType == "MMVCv13": - from voice_changer.MMVCv13.MMVCv13 import MMVCv13 + # self.modelType = modelType + # if self.modelType == "MMVCv15": + # from voice_changer.MMVCv15.MMVCv15 import MMVCv15 - self.voiceChanger = MMVCv13() - elif self.modelType == "so-vits-svc-40v2": - from voice_changer.SoVitsSvc40v2.SoVitsSvc40v2 import SoVitsSvc40v2 + # self.voiceChanger = MMVCv15() # type: ignore + # elif self.modelType == "MMVCv13": + # from voice_changer.MMVCv13.MMVCv13 import MMVCv13 - self.voiceChanger = SoVitsSvc40v2(self.params) - elif self.modelType == "so-vits-svc-40" or self.modelType == "so-vits-svc-40_c": - from voice_changer.SoVitsSvc40.SoVitsSvc40 import SoVitsSvc40 + # self.voiceChanger = MMVCv13() + # elif self.modelType == "so-vits-svc-40v2": + # from voice_changer.SoVitsSvc40v2.SoVitsSvc40v2 import SoVitsSvc40v2 - self.voiceChanger = SoVitsSvc40(self.params) - elif self.modelType == "DDSP-SVC": - from voice_changer.DDSP_SVC.DDSP_SVC import DDSP_SVC + # self.voiceChanger = SoVitsSvc40v2(self.params) + # elif self.modelType == "so-vits-svc-40" or self.modelType == "so-vits-svc-40_c": + # from voice_changer.SoVitsSvc40.SoVitsSvc40 import SoVitsSvc40 - self.voiceChanger = DDSP_SVC(self.params) - elif self.modelType == "RVC": - from voice_changer.RVC.RVC import RVC + # self.voiceChanger = SoVitsSvc40(self.params) + # elif self.modelType == "DDSP-SVC": + # from voice_changer.DDSP_SVC.DDSP_SVC import DDSP_SVC - self.voiceChanger = RVC(self.params) - else: - from voice_changer.MMVCv13.MMVCv13 import MMVCv13 + # self.voiceChanger = DDSP_SVC(self.params) + # elif self.modelType == "RVC": + # from voice_changer.RVC.RVC import RVC - self.voiceChanger = MMVCv13() - except Exception as e: - print(e) - print(traceback.format_exc()) - print("Switch Model Type:", self.voiceChanger) - return {"status": "OK", "msg": "vc is switched."} + # self.voiceChanger = RVC(self.params) + # else: + # from voice_changer.MMVCv13.MMVCv13 import MMVCv13 + + # self.voiceChanger = MMVCv13() + # except Exception as e: + # print(e) + # print(traceback.format_exc()) + # print("Switch Model Type:", self.voiceChanger) + # return {"status": "OK", "msg": "vc is switched."} def getModelType(self): if self.modelType is not None: diff --git a/server/voice_changer/VoiceChangerManager.py b/server/voice_changer/VoiceChangerManager.py index 7698be96..0ecf8a7b 100644 --- a/server/voice_changer/VoiceChangerManager.py +++ b/server/voice_changer/VoiceChangerManager.py @@ -1,3 +1,4 @@ +import json import os import shutil import numpy as np @@ -9,9 +10,10 @@ from const import UPLOAD_DIR, ModelType from voice_changer.utils.LoadModelParams import LoadModelParamFile, LoadModelParams, LoadModelParams2 from voice_changer.utils.VoiceChangerModel import AudioInOut from voice_changer.utils.VoiceChangerParams import VoiceChangerParams -from dataclasses import dataclass, asdict +from dataclasses import dataclass, asdict, field import torch -import threading + +# import threading from typing import Callable from typing import Any @@ -26,8 +28,9 @@ class GPUInfo: @dataclass() class VoiceChangerManagerSettings: dummy: int - - # intData: list[str] = field(default_factory=lambda: ["slotIndex"]) + modelSlotIndex: int = -1 + # ↓mutableな物だけ列挙 + intData: list[str] = field(default_factory=lambda: ["modelSlotIndex"]) class VoiceChangerManager(ServerDeviceCallbacks): @@ -62,8 +65,8 @@ class VoiceChangerManager(ServerDeviceCallbacks): self.serverDevice = ServerDevice(self) - thread = threading.Thread(target=self.serverDevice.start, args=()) - thread.start() + # thread = threading.Thread(target=self.serverDevice.start, args=()) + # thread.start() def _get_gpuInfos(self): devCount = torch.cuda.device_count() @@ -174,12 +177,38 @@ class VoiceChangerManager(ServerDeviceCallbacks): else: return {"status": "ERROR", "msg": "no model loaded"} - def update_settings(self, key: str, val: str | int | float): - self.serverDevice.update_settings(key, val) - if hasattr(self, "voiceChanger"): - self.voiceChanger.update_settings(key, val) + def generateVoiceChanger(self, val: int): + slotInfo = self.modelSlotManager.get_slot_info(val) + if slotInfo is None: + print(f"[Voice Changer] model slot is not found {val}") + return + elif slotInfo.voiceChangerType == "RVC": + print("................RVC") + from voice_changer.RVC.RVC import RVC + + self.voiceChangerModel = RVC(self.params, slotInfo) + self.voiceChanger = VoiceChanger(self.params) + self.voiceChanger.setModel(self.voiceChangerModel) + else: - return {"status": "ERROR", "msg": "no model loaded"} + print(f"[Voice Changer] unknown voice changer model: {slotInfo.voiceChangerType}") + del self.voiceChangerModel + return + + def update_settings(self, key: str, val: str | int | float): + if key in self.settings.intData: + newVal = int(val) + if key == "modelSlotIndex": + newVal = newVal % 1000 + print(f"[Voice Changer] model slot is changed {self.settings.modelSlotIndex} -> {newVal}") + self.generateVoiceChanger(newVal) + setattr(self.settings, key, newVal) + + else: + self.serverDevice.update_settings(key, val) + if hasattr(self, "voiceChanger"): + self.voiceChanger.update_settings(key, val) + return self.get_info() def changeVoice(self, receivedData: AudioInOut): @@ -206,13 +235,19 @@ class VoiceChangerManager(ServerDeviceCallbacks): self.emitToFunc = emitTo def update_model_default(self): - self.voiceChanger.update_model_default() + # self.voiceChanger.update_model_default() + current_settings = self.voiceChangerModel.get_model_current() + for current_setting in current_settings: + current_setting["slot"] = self.settings.modelSlotIndex + self.modelSlotManager.update_model_info(json.dumps(current_setting)) return self.get_info() def update_model_info(self, newData: str): - self.voiceChanger.update_model_info(newData) + # self.voiceChanger.update_model_info(newData) + self.modelSlotManager.update_model_info(newData) return self.get_info() def upload_model_assets(self, params: str): - self.voiceChanger.upload_model_assets(params) + # self.voiceChanger.upload_model_assets(params) + self.modelSlotManager.store_model_assets(params) return self.get_info()