WIP: integrate vcs to new gui 2

This commit is contained in:
wataru 2023-06-21 07:23:13 +09:00
parent c7e72e52db
commit 06a5250f61
6 changed files with 211 additions and 284 deletions

View File

@ -10,6 +10,11 @@ import json
@dataclass @dataclass
class ModelSlot: class ModelSlot:
voiceChangerType: VoiceChangerType | None = None voiceChangerType: VoiceChangerType | None = None
name: str = ""
description: str = ""
credit: str = ""
termsOfUseUrl: str = ""
iconFile: str = ""
@dataclass @dataclass
@ -30,12 +35,7 @@ class RVCModelSlot(ModelSlot):
deprecated: bool = False deprecated: bool = False
embedder: str = EnumEmbedderTypes.hubert.value embedder: str = EnumEmbedderTypes.hubert.value
name: str = ""
description: str = ""
credit: str = ""
termsOfUseUrl: str = ""
sampleId: str = "" sampleId: str = ""
iconFile: str = ""
@dataclass @dataclass
@ -48,10 +48,6 @@ class MMVCv13ModelSlot(ModelSlot):
isONNX: bool = False isONNX: bool = False
samplingRate: int = 24000 samplingRate: int = 24000
name: str = ""
description: str = ""
iconFile: str = ""
@dataclass @dataclass
class MMVCv15ModelSlot(ModelSlot): class MMVCv15ModelSlot(ModelSlot):
@ -60,13 +56,10 @@ class MMVCv15ModelSlot(ModelSlot):
configFile: str = "" configFile: str = ""
srcId: int = 0 srcId: int = 0
dstId: int = 101 dstId: int = 101
f0Factor: float = 1.0
isONNX: bool = False isONNX: bool = False
samplingRate: int = 24000 samplingRate: int = 24000
name: str = ""
description: str = ""
iconFile: str = ""
@dataclass @dataclass
class SoVitsSvc40ModelSlot(ModelSlot): class SoVitsSvc40ModelSlot(ModelSlot):
@ -77,12 +70,11 @@ class SoVitsSvc40ModelSlot(ModelSlot):
dstId: int = 0 dstId: int = 0
isONNX: bool = False isONNX: bool = False
name: str = ""
description: str = ""
credit: str = ""
termsOfUseUrl: str = ""
sampleId: str = "" sampleId: str = ""
iconFile: str = ""
defaultTune: int = 0
defaultClusterInferRatio: float = 0.0
noiseScale: float = 0.0
@dataclass @dataclass
@ -95,12 +87,12 @@ class DDSPSVCModelSlot(ModelSlot):
dstId: int = 0 dstId: int = 0
isONNX: bool = False isONNX: bool = False
name: str = ""
description: str = ""
credit: str = ""
termsOfUseUrl: str = ""
sampleId: 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] ModelSlots: TypeAlias = Union[ModelSlot, RVCModelSlot, MMVCv13ModelSlot, MMVCv15ModelSlot, SoVitsSvc40ModelSlot, DDSPSVCModelSlot]

View File

@ -15,7 +15,7 @@ def downloadInitialSamples(mode: RVCSampleMode, model_dir: str):
sampleJsonUrls, sampleModels = getSampleJsonAndModelIds(mode) sampleJsonUrls, sampleModels = getSampleJsonAndModelIds(mode)
sampleJsons = _downloadSampleJsons(sampleJsonUrls) sampleJsons = _downloadSampleJsons(sampleJsonUrls)
if os.path.exists(model_dir): 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 return
samples = _generateSampleList(sampleJsons) samples = _generateSampleList(sampleJsons)
slotIndex = list(range(len(sampleModels))) slotIndex = list(range(len(sampleModels)))

View File

@ -1,12 +1,10 @@
import sys import sys
import os import os
from dataclasses import asdict from dataclasses import asdict
from typing import cast
import numpy as np import numpy as np
import torch import torch
import torchaudio import torchaudio
from data.ModelSlot import RVCModelSlot from data.ModelSlot import RVCModelSlot
from voice_changer.ModelSlotManager import ModelSlotManager
# avoiding parse arg error in RVC # avoiding parse arg error in RVC
@ -22,15 +20,13 @@ if sys.platform.startswith("darwin"):
else: else:
sys.path.append("RVC") 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 ( from voice_changer.RVC.ModelSlotGenerator import (
_setInfoByONNX, _setInfoByONNX,
_setInfoByPytorch, _setInfoByPytorch,
) )
from voice_changer.RVC.RVCSettings import RVCSettings from voice_changer.RVC.RVCSettings import RVCSettings
from voice_changer.RVC.embedder.EmbedderManager import EmbedderManager 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.VoiceChangerModel import AudioInOut
from voice_changer.utils.VoiceChangerParams import VoiceChangerParams from voice_changer.utils.VoiceChangerParams import VoiceChangerParams
from voice_changer.RVC.onnxExporter.export2onnx import export2onnx 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 voice_changer.RVC.pipeline.Pipeline import Pipeline
from Exceptions import DeviceCannotSupportHalfPrecisionException, NoModeLoadedException from Exceptions import DeviceCannotSupportHalfPrecisionException, NoModeLoadedException
from const import (
UPLOAD_DIR,
)
import shutil
import json
class RVC: class RVC:
@ -61,34 +52,29 @@ class RVC:
currentSlot: int = 0 currentSlot: int = 0
needSwitch: bool = False needSwitch: bool = False
def __init__(self, params: VoiceChangerParams): def __init__(self, params: VoiceChangerParams, slotInfo: RVCModelSlot):
self.pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector) print("[Voice Changer][RVC] Creating instance ")
self.params = params
EmbedderManager.initialize(params) EmbedderManager.initialize(params)
print("[Voice Changer] RVC initialization: ", params)
self.modelSlotManager = ModelSlotManager.get_instance(self.params.model_dir)
# 起動時にスロットにモデルがある場合はロードしておく self.params = params
allSlots = self.modelSlotManager.getAllSlotInfo() self.pitchExtractor = PitchExtractorManager.getPitchExtractor(self.settings.f0Detector)
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.prevVol = 0.0 self.prevVol = 0.0
self.slotInfo = slotInfo
self.initialize()
def moveToModelDir(self, file: str, dstDir: str): def initialize(self):
dst = os.path.join(dstDir, os.path.basename(file)) print("[Voice Changer][RVC] Initializing... ")
if os.path.exists(dst):
os.remove(dst) # pipelineの生成
shutil.move(file, dst) self.pipeline = createPipeline(self.slotInfo, self.settings.gpu, self.settings.f0Detector)
return dst
# その他の設定
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 @classmethod
def loadModel2(cls, props: LoadModelParams2): def loadModel2(cls, props: LoadModelParams2):
@ -111,70 +97,13 @@ class RVC:
_setInfoByPytorch(slotInfo) _setInfoByPytorch(slotInfo)
return 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): def update_settings(self, key: str, val: int | float | str):
print("[Voice Changer][RVC]: update_settings", key, val)
if key in self.settings.intData: if key in self.settings.intData:
# 設定前処理 setattr(self.settings, key, int(val))
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)
if key == "gpu": if key == "gpu":
self.deviceManager.setForceTensor(False) self.deviceManager.setForceTensor(False)
self.prepareModel(self.settings.modelSlotIndex) self.initialize()
elif key in self.settings.floatData: elif key in self.settings.floatData:
setattr(self.settings, key, float(val)) setattr(self.settings, key, float(val))
elif key in self.settings.strData: elif key in self.settings.strData:
@ -186,44 +115,6 @@ class RVC:
return False return False
return True 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): def get_info(self):
data = asdict(self.settings) data = asdict(self.settings)
if self.pipeline is not None: if self.pipeline is not None:
@ -279,22 +170,13 @@ class RVC:
return (audio_buffer, convertSize, vol) return (audio_buffer, convertSize, vol)
def inference(self, data): def inference(self, data):
if self.settings.modelSlotIndex < 0: # if self.settings.modelSlotIndex < 0:
print(
"[Voice Changer] wait for loading model...",
self.settings.modelSlotIndex,
self.currentSlot,
)
raise NoModeLoadedException("model_common")
# if self.needSwitch:
# print( # print(
# f"[Voice Changer] Switch model {self.currentSlot} -> {self.settings.modelSlotIndex}" # "[Voice Changer] wait for loading model...",
# self.settings.modelSlotIndex,
# self.currentSlot,
# ) # )
# self.switchModel() # raise NoModeLoadedException("model_common")
# self.needSwitch = False
# half = self.deviceManager.halfPrecisionAvailable(self.settings.gpu)
# half = self.pipeline.isHalf
audio = data[0] audio = data[0]
convertSize = data[1] convertSize = data[1]
@ -314,9 +196,9 @@ class RVC:
# embOutputLayer = self.settings.modelSlots[self.currentSlot].embOutputLayer # embOutputLayer = self.settings.modelSlots[self.currentSlot].embOutputLayer
# useFinalProj = self.settings.modelSlots[self.currentSlot].useFinalProj # useFinalProj = self.settings.modelSlots[self.currentSlot].useFinalProj
if_f0 = 1 if self.modelSlotManager.get_slot_info(self.currentSlot).f0 else 0 if_f0 = 1 if self.slotInfo.f0 else 0
embOutputLayer = self.modelSlotManager.get_slot_info(self.currentSlot).embOutputLayer embOutputLayer = self.slotInfo.embOutputLayer
useFinalProj = self.modelSlotManager.get_slot_info(self.currentSlot).useFinalProj useFinalProj = self.slotInfo.useFinalProj
try: try:
audio_out = self.pipeline.exec( audio_out = self.pipeline.exec(
@ -345,7 +227,7 @@ class RVC:
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]
@ -378,70 +260,86 @@ class RVC:
def merge_models(self, request: str): def merge_models(self, request: str):
print("[Voice Changer] MergeRequest:", request) print("[Voice Changer] MergeRequest:", request)
req: MergeModelRequest = MergeModelRequest.from_json(request) # req: MergeModelRequest = MergeModelRequest.from_json(request)
merged = merge_model(req) # merged = merge_model(req)
targetSlot = 0 # targetSlot = 0
if req.slot < 0: # if req.slot < 0:
# 最後尾のスロット番号を格納先とする。 # # 最後尾のスロット番号を格納先とする。
allModelSlots = self.modelSlotManager.getAllSlotInfo() # allModelSlots = self.modelSlotManager.getAllSlotInfo()
targetSlot = len(allModelSlots) - 1 # targetSlot = len(allModelSlots) - 1
else: # else:
targetSlot = req.slot # targetSlot = req.slot
# いったんは、アップロードフォルダに格納する。(歴史的経緯) # # いったんは、アップロードフォルダに格納する。(歴史的経緯)
# 後続のloadmodelを呼び出すことで永続化モデルフォルダに移動させられる。 # # 後続のloadmodelを呼び出すことで永続化モデルフォルダに移動させられる。
storeDir = os.path.join(UPLOAD_DIR, f"{targetSlot}") # storeDir = os.path.join(UPLOAD_DIR, f"{targetSlot}")
print("[Voice Changer] store merged model to:", storeDir) # print("[Voice Changer] store merged model to:", storeDir)
os.makedirs(storeDir, exist_ok=True) # os.makedirs(storeDir, exist_ok=True)
storeFile = os.path.join(storeDir, "merged.pth") # storeFile = os.path.join(storeDir, "merged.pth")
torch.save(merged, storeFile) # torch.save(merged, storeFile)
# loadmodelを呼び出して永続化モデルフォルダに移動させる。 # # loadmodelを呼び出して永続化モデルフォルダに移動させる。
params = { # params = {
"defaultTune": req.defaultTune, # "defaultTune": req.defaultTune,
"defaultIndexRatio": req.defaultIndexRatio, # "defaultIndexRatio": req.defaultIndexRatio,
"defaultProtect": req.defaultProtect, # "defaultProtect": req.defaultProtect,
"sampleId": "", # "sampleId": "",
"files": {"rvcModel": storeFile}, # "files": {"rvcModel": storeFile},
} # }
props: LoadModelParams = LoadModelParams(slot=targetSlot, isHalf=True, params=params) # props: LoadModelParams = LoadModelParams(slot=targetSlot, isHalf=True, params=params)
self.loadModel(props) # self.loadModel(props)
self.prepareModel(targetSlot) # self.prepareModel(targetSlot)
self.settings.modelSlotIndex = targetSlot # self.settings.modelSlotIndex = targetSlot
self.currentSlot = self.settings.modelSlotIndex # self.currentSlot = self.settings.modelSlotIndex
def update_model_default(self): # def update_model_default(self):
# {"slot":9,"key":"name","val":"dogsdododg"} # # {"slot":9,"key":"name","val":"dogsdododg"}
self.modelSlotManager.update_model_info( # self.modelSlotManager.update_model_info(
json.dumps( # json.dumps(
{ # {
"slot": self.currentSlot, # "slot": self.currentSlot,
"key": "defaultTune", # "key": "defaultTune",
"val": self.settings.tran, # "val": self.settings.tran,
} # }
) # )
) # )
self.modelSlotManager.update_model_info( # self.modelSlotManager.update_model_info(
json.dumps( # json.dumps(
{ # {
"slot": self.currentSlot, # "slot": self.currentSlot,
"key": "defaultIndexRatio", # "key": "defaultIndexRatio",
"val": self.settings.indexRatio, # "val": self.settings.indexRatio,
} # }
) # )
) # )
self.modelSlotManager.update_model_info( # self.modelSlotManager.update_model_info(
json.dumps( # json.dumps(
{ # {
"slot": self.currentSlot, # "slot": self.currentSlot,
"key": "defaultProtect", # "key": "defaultProtect",
"val": self.settings.protect, # "val": self.settings.protect,
} # }
) # )
) # )
def update_model_info(self, newData: str): def get_model_current(self):
self.modelSlotManager.update_model_info(newData) 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): # def update_model_info(self, newData: str):
self.modelSlotManager.store_model_assets(params) # self.modelSlotManager.update_model_info(newData)
# def upload_model_assets(self, params: str):
# self.modelSlotManager.store_model_assets(params)

View File

@ -19,7 +19,6 @@ class RVCSettings:
rvcQuality: int = 0 rvcQuality: int = 0
silenceFront: int = 1 # 0:off, 1:on silenceFront: int = 1 # 0:off, 1:on
modelSamplingRate: int = 48000 modelSamplingRate: int = 48000
modelSlotIndex: int = -1
speakers: dict[str, int] = field(default_factory=lambda: {}) speakers: dict[str, int] = field(default_factory=lambda: {})
isHalf: int = 1 # 0:off, 1:on isHalf: int = 1 # 0:off, 1:on

View File

@ -80,48 +80,51 @@ class VoiceChanger:
print(f"VoiceChanger Initialized (GPU_NUM:{self.gpu_num}, mps_enabled:{self.mps_enabled})") print(f"VoiceChanger Initialized (GPU_NUM:{self.gpu_num}, mps_enabled:{self.mps_enabled})")
def switchModelType(self, modelType: ModelType): def setModel(self, model: Any):
print("Switch Model Type:", modelType) self.voiceChanger = model
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.modelType = modelType # def switchModelType(self, modelType: ModelType):
if self.modelType == "MMVCv15": # print("Switch Model Type:", modelType)
from voice_changer.MMVCv15.MMVCv15 import MMVCv15 # 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 # self.modelType = modelType
elif self.modelType == "MMVCv13": # if self.modelType == "MMVCv15":
from voice_changer.MMVCv13.MMVCv13 import MMVCv13 # from voice_changer.MMVCv15.MMVCv15 import MMVCv15
self.voiceChanger = MMVCv13() # self.voiceChanger = MMVCv15() # type: ignore
elif self.modelType == "so-vits-svc-40v2": # elif self.modelType == "MMVCv13":
from voice_changer.SoVitsSvc40v2.SoVitsSvc40v2 import SoVitsSvc40v2 # from voice_changer.MMVCv13.MMVCv13 import MMVCv13
self.voiceChanger = SoVitsSvc40v2(self.params) # self.voiceChanger = MMVCv13()
elif self.modelType == "so-vits-svc-40" or self.modelType == "so-vits-svc-40_c": # elif self.modelType == "so-vits-svc-40v2":
from voice_changer.SoVitsSvc40.SoVitsSvc40 import SoVitsSvc40 # from voice_changer.SoVitsSvc40v2.SoVitsSvc40v2 import SoVitsSvc40v2
self.voiceChanger = SoVitsSvc40(self.params) # self.voiceChanger = SoVitsSvc40v2(self.params)
elif self.modelType == "DDSP-SVC": # elif self.modelType == "so-vits-svc-40" or self.modelType == "so-vits-svc-40_c":
from voice_changer.DDSP_SVC.DDSP_SVC import DDSP_SVC # from voice_changer.SoVitsSvc40.SoVitsSvc40 import SoVitsSvc40
self.voiceChanger = DDSP_SVC(self.params) # self.voiceChanger = SoVitsSvc40(self.params)
elif self.modelType == "RVC": # elif self.modelType == "DDSP-SVC":
from voice_changer.RVC.RVC import RVC # from voice_changer.DDSP_SVC.DDSP_SVC import DDSP_SVC
self.voiceChanger = RVC(self.params) # self.voiceChanger = DDSP_SVC(self.params)
else: # elif self.modelType == "RVC":
from voice_changer.MMVCv13.MMVCv13 import MMVCv13 # from voice_changer.RVC.RVC import RVC
self.voiceChanger = MMVCv13() # self.voiceChanger = RVC(self.params)
except Exception as e: # else:
print(e) # from voice_changer.MMVCv13.MMVCv13 import MMVCv13
print(traceback.format_exc())
print("Switch Model Type:", self.voiceChanger) # self.voiceChanger = MMVCv13()
return {"status": "OK", "msg": "vc is switched."} # 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): def getModelType(self):
if self.modelType is not None: if self.modelType is not None:

View File

@ -1,3 +1,4 @@
import json
import os import os
import shutil import shutil
import numpy as np 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.LoadModelParams import LoadModelParamFile, LoadModelParams, LoadModelParams2
from voice_changer.utils.VoiceChangerModel import AudioInOut from voice_changer.utils.VoiceChangerModel import AudioInOut
from voice_changer.utils.VoiceChangerParams import VoiceChangerParams from voice_changer.utils.VoiceChangerParams import VoiceChangerParams
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict, field
import torch import torch
import threading
# import threading
from typing import Callable from typing import Callable
from typing import Any from typing import Any
@ -26,8 +28,9 @@ class GPUInfo:
@dataclass() @dataclass()
class VoiceChangerManagerSettings: class VoiceChangerManagerSettings:
dummy: int dummy: int
modelSlotIndex: int = -1
# intData: list[str] = field(default_factory=lambda: ["slotIndex"]) # ↓mutableな物だけ列挙
intData: list[str] = field(default_factory=lambda: ["modelSlotIndex"])
class VoiceChangerManager(ServerDeviceCallbacks): class VoiceChangerManager(ServerDeviceCallbacks):
@ -62,8 +65,8 @@ class VoiceChangerManager(ServerDeviceCallbacks):
self.serverDevice = ServerDevice(self) self.serverDevice = ServerDevice(self)
thread = threading.Thread(target=self.serverDevice.start, args=()) # thread = threading.Thread(target=self.serverDevice.start, args=())
thread.start() # thread.start()
def _get_gpuInfos(self): def _get_gpuInfos(self):
devCount = torch.cuda.device_count() devCount = torch.cuda.device_count()
@ -174,12 +177,38 @@ class VoiceChangerManager(ServerDeviceCallbacks):
else: else:
return {"status": "ERROR", "msg": "no model loaded"} return {"status": "ERROR", "msg": "no model loaded"}
def update_settings(self, key: str, val: str | int | float): def generateVoiceChanger(self, val: int):
self.serverDevice.update_settings(key, val) slotInfo = self.modelSlotManager.get_slot_info(val)
if hasattr(self, "voiceChanger"): if slotInfo is None:
self.voiceChanger.update_settings(key, val) 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: 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() return self.get_info()
def changeVoice(self, receivedData: AudioInOut): def changeVoice(self, receivedData: AudioInOut):
@ -206,13 +235,19 @@ class VoiceChangerManager(ServerDeviceCallbacks):
self.emitToFunc = emitTo self.emitToFunc = emitTo
def update_model_default(self): 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() return self.get_info()
def update_model_info(self, newData: str): 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() return self.get_info()
def upload_model_assets(self, params: str): 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() return self.get_info()