WIP:VC select

This commit is contained in:
wataru 2023-04-11 00:21:17 +09:00
parent bd6080c52e
commit 4cc02540ea
34 changed files with 389 additions and 118 deletions

View File

@ -105,10 +105,6 @@
"name": "indexRatio", "name": "indexRatio",
"options": {} "options": {}
}, },
{
"name": "noiseScale",
"options": {}
},
{ {
"name": "silentThreshold", "name": "silentThreshold",
"options": {} "options": {}

File diff suppressed because one or more lines are too long

View File

@ -10,9 +10,10 @@ import { far } from "@fortawesome/free-regular-svg-icons";
import { fab } from "@fortawesome/free-brands-svg-icons"; import { fab } from "@fortawesome/free-brands-svg-icons";
import { AppRootProvider, useAppRoot } from "./001_provider/001_AppRootProvider"; import { AppRootProvider, useAppRoot } from "./001_provider/001_AppRootProvider";
import ErrorBoundary from "./001_provider/900_ErrorBoundary"; import ErrorBoundary from "./001_provider/900_ErrorBoundary";
import { INDEXEDDB_KEY_CLIENT, INDEXEDDB_KEY_MODEL_DATA, INDEXEDDB_KEY_SERVER, INDEXEDDB_KEY_WORKLET, INDEXEDDB_KEY_WORKLETNODE, useIndexedDB } from "@dannadori/voice-changer-client-js"; import { ClientType, INDEXEDDB_KEY_CLIENT, INDEXEDDB_KEY_MODEL_DATA, INDEXEDDB_KEY_SERVER, INDEXEDDB_KEY_WORKLET, INDEXEDDB_KEY_WORKLETNODE, useIndexedDB } from "@dannadori/voice-changer-client-js";
import { CLIENT_TYPE, INDEXEDDB_KEY_AUDIO_OUTPUT } from "./const"; import { CLIENT_TYPE, INDEXEDDB_KEY_AUDIO_OUTPUT } from "./const";
import { Demo } from "./components/demo/010_Demo"; import { Demo } from "./components/demo/010_Demo";
import { ClientSelector } from "./001_ClientSelector";
library.add(fas, far, fab); library.add(fas, far, fab);
@ -21,7 +22,7 @@ const container = document.getElementById("app")!;
const root = createRoot(container); const root = createRoot(container);
const App = () => { const App = () => {
const { appGuiSettingState } = useAppRoot() const { appGuiSettingState, clientType } = useAppRoot()
const front = useMemo(() => { const front = useMemo(() => {
if (appGuiSettingState.appGuiSetting.type == "demo") { if (appGuiSettingState.appGuiSetting.type == "demo") {
return <Demo></Demo> return <Demo></Demo>
@ -38,7 +39,7 @@ const App = () => {
} }
const AppStateWrapper = () => { const AppStateWrapper = () => {
const { appGuiSettingState } = useAppRoot() const { appGuiSettingState, clientType } = useAppRoot()
// エラーバウンダリー設定 // エラーバウンダリー設定
const [error, setError] = useState<{ error: Error, errorInfo: ErrorInfo }>() const [error, setError] = useState<{ error: Error, errorInfo: ErrorInfo }>()
const { removeItem } = useIndexedDB({ clientType: CLIENT_TYPE }) const { removeItem } = useIndexedDB({ clientType: CLIENT_TYPE })
@ -96,7 +97,11 @@ const AppStateWrapper = () => {
setError({ error, errorInfo }) setError({ error, errorInfo })
} }
if (!appGuiSettingState.guiSettingLoaded) {
if (!clientType) {
return <ClientSelector></ClientSelector>
} else if (!appGuiSettingState.guiSettingLoaded) {
return <></> return <></>
} else { } else {
return ( return (

View File

@ -0,0 +1,16 @@
import React from "react"
import { useAppRoot } from "./001_provider/001_AppRootProvider"
export const ClientSelector = () => {
const { setClientType } = useAppRoot()
return (
<div>
<div onClick={() => { setClientType("MMVCv13") }}>MMVCv13</div>
<div onClick={() => { setClientType("MMVCv15") }}>MMVCv15</div>
<div onClick={() => { setClientType("so-vits-svc-40") }}>so-vits-svc-40</div>
<div onClick={() => { setClientType("so-vits-svc-40v2") }}>so-vits-svc-40v2</div>
<div onClick={() => { setClientType("RVC") }}>RVC</div>
</div>
)
}

View File

@ -51,13 +51,14 @@ export type AppGuiSettingState = {
} }
export type AppGuiSettingStateAndMethod = AppGuiSettingState & { export type AppGuiSettingStateAndMethod = AppGuiSettingState & {
getAppSetting: (url: string) => Promise<void> getAppGuiSetting: (url: string) => Promise<void>
clearAppGuiSetting: () => void
} }
export const userAppGuiSetting = (): AppGuiSettingStateAndMethod => { export const userAppGuiSetting = (): AppGuiSettingStateAndMethod => {
const [guiSettingLoaded, setGuiSettingLoaded] = useState<boolean>(false) const [guiSettingLoaded, setGuiSettingLoaded] = useState<boolean>(false)
const [appGuiSetting, setAppGuiSetting] = useState<AppGuiSetting>(InitialAppGuiDemoSetting) const [appGuiSetting, setAppGuiSetting] = useState<AppGuiSetting>(InitialAppGuiDemoSetting)
const getAppSetting = async (url: string) => { const getAppGuiSetting = async (url: string) => {
const res = await fetch(`${url}`, { const res = await fetch(`${url}`, {
method: "GET", method: "GET",
}) })
@ -65,9 +66,15 @@ export const userAppGuiSetting = (): AppGuiSettingStateAndMethod => {
setAppGuiSetting(appSetting) setAppGuiSetting(appSetting)
setGuiSettingLoaded(true) setGuiSettingLoaded(true)
} }
const clearAppGuiSetting = () => {
setAppGuiSetting(InitialAppGuiDemoSetting)
setGuiSettingLoaded(false)
}
return { return {
appGuiSetting, appGuiSetting,
guiSettingLoaded, guiSettingLoaded,
getAppSetting, getAppGuiSetting,
clearAppGuiSetting,
} }
} }

View File

@ -2,23 +2,30 @@ import { ClientState, useClient, ClientType } from "@dannadori/voice-changer-cli
export type UseVCClientProps = { export type UseVCClientProps = {
audioContext: AudioContext | null audioContext: AudioContext | null
clientType: ClientType clientType: ClientType | null
} }
export type VCClientState = { export type VCClientState = {
clientState: ClientState clientState: ClientState
} }
export const useVCClient = (props: UseVCClientProps) => { export const useVCClient = (props: UseVCClientProps): VCClientState => {
const clientState = useClient({ const clientState = useClient({
clientType: props.clientType,
audioContext: props.audioContext, audioContext: props.audioContext,
clientType: props.clientType,
}) })
// const setClientType = (clientType: ClientType) => {
// console.log("SET CLIENT TYPE", clientType)
// clientState.setClientType(clientType)
// }
const ret: VCClientState = { const ret: VCClientState = {
clientState clientState
} }
return ret return ret
} }

View File

@ -1,4 +1,5 @@
import React, { useContext, useEffect } from "react"; import { ClientType } from "@dannadori/voice-changer-client-js";
import React, { useContext, useEffect, useState } from "react";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { AppGuiSettingStateAndMethod, userAppGuiSetting } from "../001_globalHooks/001_useAppGuiSetting"; import { AppGuiSettingStateAndMethod, userAppGuiSetting } from "../001_globalHooks/001_useAppGuiSetting";
import { AudioConfigState, useAudioConfig } from "../001_globalHooks/001_useAudioConfig"; import { AudioConfigState, useAudioConfig } from "../001_globalHooks/001_useAudioConfig";
@ -10,6 +11,8 @@ type Props = {
type AppRootValue = { type AppRootValue = {
audioContextState: AudioConfigState audioContextState: AudioConfigState
appGuiSettingState: AppGuiSettingStateAndMethod appGuiSettingState: AppGuiSettingStateAndMethod
clientType: ClientType | null
setClientType: (val: ClientType | null) => void
} }
const AppRootContext = React.createContext<AppRootValue | null>(null); const AppRootContext = React.createContext<AppRootValue | null>(null);
@ -24,16 +27,20 @@ export const useAppRoot = (): AppRootValue => {
export const AppRootProvider = ({ children }: Props) => { export const AppRootProvider = ({ children }: Props) => {
const audioContextState = useAudioConfig() const audioContextState = useAudioConfig()
const appGuiSettingState = userAppGuiSetting() const appGuiSettingState = userAppGuiSetting()
const [clientType, setClientType] = useState<ClientType | null>(null)
useEffect(() => { useEffect(() => {
const params = new URLSearchParams(window.location.search); if (!clientType) {
const modelType = params.get("modelType") || "" return
appGuiSettingState.getAppSetting(`/assets/gui_settings/${modelType}.json`) }
}, []) appGuiSettingState.getAppGuiSetting(`/assets/gui_settings/${clientType}.json`)
}, [clientType])
const providerValue: AppRootValue = { const providerValue: AppRootValue = {
audioContextState, audioContextState,
appGuiSettingState appGuiSettingState,
clientType,
setClientType
}; };
return <AppRootContext.Provider value={providerValue}>{children}</AppRootContext.Provider>; return <AppRootContext.Provider value={providerValue}>{children}</AppRootContext.Provider>;
}; };

View File

@ -24,7 +24,7 @@ export const useAppState = (): AppStateValue => {
export const AppStateProvider = ({ children }: Props) => { export const AppStateProvider = ({ children }: Props) => {
const appRoot = useAppRoot() const appRoot = useAppRoot()
const clientState = useVCClient({ audioContext: appRoot.audioContextState.audioContext, clientType: appRoot.appGuiSettingState.appGuiSetting.id }) const clientState = useVCClient({ audioContext: appRoot.audioContextState.audioContext, clientType: appRoot.clientType })
const initializedRef = useRef<boolean>(false) const initializedRef = useRef<boolean>(false)

View File

@ -3,14 +3,15 @@ import { useAppState } from "../../../001_provider/001_AppStateProvider";
import { useIndexedDB } from "@dannadori/voice-changer-client-js"; import { useIndexedDB } from "@dannadori/voice-changer-client-js";
import { INDEXEDDB_KEY_AUDIO_OUTPUT } from "../../../const"; import { INDEXEDDB_KEY_AUDIO_OUTPUT } from "../../../const";
import { useAppRoot } from "../../../001_provider/001_AppRootProvider"; import { useAppRoot } from "../../../001_provider/001_AppRootProvider";
import { useGuiState } from "../001_GuiStateProvider"
export type ClearSettingRowProps = { export type ClearSettingRowProps = {
} }
export const ClearSettingRow = (_props: ClearSettingRowProps) => { export const ClearSettingRow = (_props: ClearSettingRowProps) => {
const appState = useAppState() const appState = useAppState()
const { appGuiSettingState } = useAppRoot() const { appGuiSettingState, setClientType } = useAppRoot()
const guiState = useGuiState()
const clientType = appGuiSettingState.appGuiSetting.id const clientType = appGuiSettingState.appGuiSetting.id
const { removeItem } = useIndexedDB({ clientType: clientType }) const { removeItem } = useIndexedDB({ clientType: clientType })
@ -21,12 +22,21 @@ export const ClearSettingRow = (_props: ClearSettingRowProps) => {
await removeItem(INDEXEDDB_KEY_AUDIO_OUTPUT) await removeItem(INDEXEDDB_KEY_AUDIO_OUTPUT)
location.reload() location.reload()
} }
const onReselectVCClicked = async () => {
guiState.setIsConverting(false)
await appState.clientSetting.stop()
setClientType(null)
appGuiSettingState.clearAppGuiSetting()
}
return ( return (
<div className="body-row split-3-3-4 left-padding-1"> <div className="body-row split-3-3-4 left-padding-1">
<div className="body-button-container"> <div className="body-button-container">
<div className="body-button" onClick={onClearSettingClicked}>clear setting</div> <div className="body-button" onClick={onClearSettingClicked}>clear setting</div>
</div> </div>
<div className="body-item-text"></div> <div className="body-button-container">
<div className="body-button" onClick={onReselectVCClicked}>re-select vc</div>
</div>
<div className="body-item-text"></div> <div className="body-item-text"></div>
</div> </div>
) )

View File

@ -11,7 +11,7 @@ export const TuneRow = (_props: TuneRowProps) => {
<div className="body-row split-3-2-2-3 left-padding-1 guided"> <div className="body-row split-3-2-2-3 left-padding-1 guided">
<div className="body-item-title left-padding-1 ">Tuning</div> <div className="body-item-title left-padding-1 ">Tuning</div>
<div> <div>
<input type="range" className="body-item-input-slider" min="-50" max="50" step="1" value={appState.serverSetting.serverSetting.tran} onChange={(e) => { <input type="range" className="body-item-input-slider" min="-50" max="50" step="1" value={appState.serverSetting.serverSetting.tran || 0} onChange={(e) => {
appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, tran: Number(e.target.value) }) appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, tran: Number(e.target.value) })
}}></input> }}></input>
<span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.tran}</span> <span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.tran}</span>

View File

@ -12,7 +12,7 @@ export const ClusterInferRatioRow = (_props: ClusterInferRatioRowProps) => {
<div className="body-row split-3-3-4 left-padding-1 guided"> <div className="body-row split-3-3-4 left-padding-1 guided">
<div className="body-item-title left-padding-1 ">Cluster infer ratio</div> <div className="body-item-title left-padding-1 ">Cluster infer ratio</div>
<div> <div>
<input type="range" className="body-item-input-slider" min="0" max="1" step="0.1" value={appState.serverSetting.serverSetting.clusterInferRatio} onChange={(e) => { <input type="range" className="body-item-input-slider" min="0" max="1" step="0.1" value={appState.serverSetting.serverSetting.clusterInferRatio || 0} onChange={(e) => {
appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, clusterInferRatio: Number(e.target.value) }) appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, clusterInferRatio: Number(e.target.value) })
}}></input> }}></input>
<span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.clusterInferRatio}</span> <span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.clusterInferRatio}</span>

View File

@ -12,7 +12,7 @@ export const NoiseScaleRow = (_props: NoiseScaleRowProps) => {
<div className="body-row split-3-3-4 left-padding-1 guided"> <div className="body-row split-3-3-4 left-padding-1 guided">
<div className="body-item-title left-padding-1 ">Noise Scale</div> <div className="body-item-title left-padding-1 ">Noise Scale</div>
<div> <div>
<input type="range" className="body-item-input-slider" min="0" max="1" step="0.1" value={appState.serverSetting.serverSetting.noiceScale} onChange={(e) => { <input type="range" className="body-item-input-slider" min="0" max="1" step="0.1" value={appState.serverSetting.serverSetting.noiceScale || 0} onChange={(e) => {
appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, noiceScale: Number(e.target.value) }) appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, noiceScale: Number(e.target.value) })
}}></input> }}></input>
<span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.noiceScale}</span> <span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.noiceScale}</span>

View File

@ -12,7 +12,7 @@ export const SilentThresholdRow = (_props: SilentThresholdRowProps) => {
<div className="body-row split-3-3-4 left-padding-1 guided"> <div className="body-row split-3-3-4 left-padding-1 guided">
<div className="body-item-title left-padding-1 ">Silent Threshold</div> <div className="body-item-title left-padding-1 ">Silent Threshold</div>
<div> <div>
<input type="range" className="body-item-input-slider" min="0.00000" max="0.001" step="0.00001" value={appState.serverSetting.serverSetting.silentThreshold} onChange={(e) => { <input type="range" className="body-item-input-slider" min="0.00000" max="0.001" step="0.00001" value={appState.serverSetting.serverSetting.silentThreshold || 0} onChange={(e) => {
appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, silentThreshold: Number(e.target.value) }) appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, silentThreshold: Number(e.target.value) })
}}></input> }}></input>
<span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.silentThreshold}</span> <span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.silentThreshold}</span>

View File

@ -12,7 +12,7 @@ export const IndexRatioRow = (_props: IndexRatioRowProps) => {
<div className="body-row split-3-3-4 left-padding-1 guided"> <div className="body-row split-3-3-4 left-padding-1 guided">
<div className="body-item-title left-padding-1 ">index ratio</div> <div className="body-item-title left-padding-1 ">index ratio</div>
<div> <div>
<input type="range" className="body-item-input-slider" min="0" max="1" step="0.1" value={appState.serverSetting.serverSetting.indexRatio} onChange={(e) => { <input type="range" className="body-item-input-slider" min="0" max="1" step="0.1" value={appState.serverSetting.serverSetting.indexRatio || 0} onChange={(e) => {
appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, indexRatio: Number(e.target.value) }) appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, indexRatio: Number(e.target.value) })
}}></input> }}></input>
<span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.indexRatio}</span> <span className="body-item-input-slider-val">{appState.serverSetting.serverSetting.indexRatio}</span>

View File

@ -10,7 +10,7 @@ export const GPURow = (_props: GPURowProps) => {
<div className="body-row split-3-7 left-padding-1 guided"> <div className="body-row split-3-7 left-padding-1 guided">
<div className="body-item-title left-padding-1">GPU</div> <div className="body-item-title left-padding-1">GPU</div>
<div className="body-input-container"> <div className="body-input-container">
<input type="number" min={-2} max={5} step={1} value={appState.serverSetting.serverSetting.gpu} onChange={(e) => { <input type="number" min={-2} max={5} step={1} value={appState.serverSetting.serverSetting.gpu || 0} onChange={(e) => {
appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, gpu: Number(e.target.value) }) appState.serverSetting.updateServerSettings({ ...appState.serverSetting.serverSetting, gpu: Number(e.target.value) })
}} /> }} />
</div> </div>

View File

@ -21,7 +21,7 @@ export const TrancateNumTresholdRow = (_props: TrancateNumTresholdRowProps) => {
</div> </div>
</div> </div>
) )
}, [appState.workletNodeSetting.workletNodeSetting, appState.workletNodeSetting.updateWorkletNodeSetting]) }, [appState.workletSetting.setting, appState.workletSetting.setSetting])
return trancateNumTresholdRow return trancateNumTresholdRow
} }

View File

@ -1,4 +1,4 @@
import { ServerInfo, ServerSettingKey } from "./const"; import { ClientType, ServerInfo, ServerSettingKey } from "./const";
type FileChunk = { type FileChunk = {
@ -132,4 +132,32 @@ export class ServerConfigurator {
return await info return await info
} }
switchModelType = async (clinetType: ClientType) => {
const url = this.serverUrl + "/model_type"
const info = new Promise<ServerInfo>(async (resolve) => {
const formData = new FormData();
formData.append("modelType", clinetType);
const request = new Request(url, {
method: 'POST',
body: formData,
});
const res = await (await fetch(request)).json() as ServerInfo
resolve(res)
})
return await info
}
getModelType = async () => {
const url = this.serverUrl + "/model_type"
const info = new Promise<ServerInfo>(async (resolve) => {
const request = new Request(url, {
method: 'GET',
});
const res = await (await fetch(request)).json() as ServerInfo
resolve(res)
})
return await info
}
} }

View File

@ -3,7 +3,7 @@ import { VoiceChangerWorkletNode, VoiceChangerWorkletListener } from "./VoiceCha
import workerjs from "raw-loader!../worklet/dist/index.js"; import workerjs from "raw-loader!../worklet/dist/index.js";
import { VoiceFocusDeviceTransformer, VoiceFocusTransformDevice } from "amazon-chime-sdk-js"; import { VoiceFocusDeviceTransformer, VoiceFocusTransformDevice } from "amazon-chime-sdk-js";
import { createDummyMediaStream, validateUrl } from "./util"; import { createDummyMediaStream, validateUrl } from "./util";
import { DefaultVoiceChangerClientSetting, ServerSettingKey, VoiceChangerClientSetting, WorkletNodeSetting, WorkletSetting } from "./const"; import { ClientType, DefaultVoiceChangerClientSetting, ServerSettingKey, VoiceChangerClientSetting, WorkletNodeSetting, WorkletSetting } from "./const";
import { ServerConfigurator } from "./ServerConfigurator"; import { ServerConfigurator } from "./ServerConfigurator";
// オーディオデータの流れ // オーディオデータの流れ
@ -44,15 +44,28 @@ export class VoiceChangerClient {
this.vfEnable = vfEnable this.vfEnable = vfEnable
this.promiseForInitialize = new Promise<void>(async (resolve) => { this.promiseForInitialize = new Promise<void>(async (resolve) => {
const scriptUrl = URL.createObjectURL(new Blob([workerjs], { type: "text/javascript" })); const scriptUrl = URL.createObjectURL(new Blob([workerjs], { type: "text/javascript" }));
await this.ctx.audioWorklet.addModule(scriptUrl)
this.vcInNode = new VoiceChangerWorkletNode(this.ctx, voiceChangerWorkletListener); // vc node // await this.ctx.audioWorklet.addModule(scriptUrl)
// this.vcInNode = new VoiceChangerWorkletNode(this.ctx, voiceChangerWorkletListener); // vc node
try {
this.vcInNode = new VoiceChangerWorkletNode(this.ctx, voiceChangerWorkletListener); // vc node
} catch (err) {
await this.ctx.audioWorklet.addModule(scriptUrl)
this.vcInNode = new VoiceChangerWorkletNode(this.ctx, voiceChangerWorkletListener); // vc node
}
// const ctx44k = new AudioContext({ sampleRate: 44100 }) // これでもプチプチが残る // const ctx44k = new AudioContext({ sampleRate: 44100 }) // これでもプチプチが残る
const ctx44k = new AudioContext({ sampleRate: 48000 }) // 結局これが一番まし。 const ctx44k = new AudioContext({ sampleRate: 48000 }) // 結局これが一番まし。
console.log("audio out:", ctx44k) console.log("audio out:", ctx44k)
await ctx44k.audioWorklet.addModule(scriptUrl) try {
this.vcOutNode = new VoiceChangerWorkletNode(ctx44k, voiceChangerWorkletListener); // vc node this.vcOutNode = new VoiceChangerWorkletNode(ctx44k, voiceChangerWorkletListener); // vc node
} catch (err) {
await ctx44k.audioWorklet.addModule(scriptUrl)
this.vcOutNode = new VoiceChangerWorkletNode(ctx44k, voiceChangerWorkletListener); // vc node
}
this.currentMediaStreamAudioDestinationNode = ctx44k.createMediaStreamDestination() // output node this.currentMediaStreamAudioDestinationNode = ctx44k.createMediaStreamDestination() // output node
this.outputGainNode = ctx44k.createGain() this.outputGainNode = ctx44k.createGain()
this.outputGainNode.gain.value = this.setting.outputGain this.outputGainNode.gain.value = this.setting.outputGain
@ -248,6 +261,14 @@ export class VoiceChangerClient {
// コンポーネント設定、操作 // コンポーネント設定、操作
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
//## Server ##// //## Server ##//
switchModelType = (clientType: ClientType) => {
return this.configurator.switchModelType(clientType)
}
getModelType = () => {
return this.configurator.getModelType()
}
updateServerSettings = (key: ServerSettingKey, val: string) => { updateServerSettings = (key: ServerSettingKey, val: string) => {
return this.configurator.updateSettings(key, val) return this.configurator.updateSettings(key, val)
} }

View File

@ -9,7 +9,7 @@ import { useWorkletSetting, WorkletSettingState } from "./useWorkletSetting"
export type UseClientProps = { export type UseClientProps = {
audioContext: AudioContext | null audioContext: AudioContext | null
clientType: ClientType clientType: ClientType | null
} }
export type ClientState = { export type ClientState = {
@ -26,6 +26,8 @@ export type ClientState = {
volume: number; volume: number;
performance: PerformanceData performance: PerformanceData
// setClientType: (val: ClientType) => void
// 情報取得 // 情報取得
getInfo: () => Promise<void> getInfo: () => Promise<void>
// 設定クリア // 設定クリア
@ -50,6 +52,7 @@ const InitialPerformanceData: PerformanceData = {
export const useClient = (props: UseClientProps): ClientState => { export const useClient = (props: UseClientProps): ClientState => {
const [initialized, setInitialized] = useState<boolean>(false) const [initialized, setInitialized] = useState<boolean>(false)
// const [clientType, setClientType] = useState<ClientType | null>(null)
// (1-1) クライアント // (1-1) クライアント
const voiceChangerClientRef = useRef<VoiceChangerClient | null>(null) const voiceChangerClientRef = useRef<VoiceChangerClient | null>(null)
const [voiceChangerClient, setVoiceChangerClient] = useState<VoiceChangerClient | null>(voiceChangerClientRef.current) const [voiceChangerClient, setVoiceChangerClient] = useState<VoiceChangerClient | null>(voiceChangerClientRef.current)
@ -165,6 +168,8 @@ export const useClient = (props: UseClientProps): ClientState => {
volume, volume,
performance, performance,
// setClientType,
// 情報取得 // 情報取得
getInfo, getInfo,

View File

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

View File

@ -3,7 +3,7 @@ import { useMemo } from "react";
import { ClientType, INDEXEDDB_DB_APP_NAME, INDEXEDDB_DB_NAME } from "../const"; import { ClientType, INDEXEDDB_DB_APP_NAME, INDEXEDDB_DB_NAME } from "../const";
export type UseIndexedDBProps = { export type UseIndexedDBProps = {
clientType: ClientType clientType: ClientType | null
} }
export type IndexedDBState = { export type IndexedDBState = {
dummy: string dummy: string
@ -16,31 +16,36 @@ export type IndexedDBStateAndMethod = IndexedDBState & {
} }
export const useIndexedDB = (props: UseIndexedDBProps): IndexedDBStateAndMethod => { export const useIndexedDB = (props: UseIndexedDBProps): IndexedDBStateAndMethod => {
const clientType = props.clientType || "default"
localForage.config({ localForage.config({
driver: localForage.INDEXEDDB, driver: localForage.INDEXEDDB,
name: INDEXEDDB_DB_APP_NAME, name: INDEXEDDB_DB_APP_NAME,
version: 1.0, version: 1.0,
storeName: `${INDEXEDDB_DB_NAME}_${props.clientType}`, storeName: `${INDEXEDDB_DB_NAME}`,
description: 'appStorage' description: 'appStorage'
}) })
const setItem = useMemo(() => { const setItem = useMemo(() => {
return async (key: string, value: unknown) => { return async (key: string, value: unknown) => {
await localForage.setItem(key, value) const clientKey = `${clientType}_${key}`
await localForage.setItem(clientKey, value)
} }
}, []) }, [props.clientType])
const getItem = useMemo(() => { const getItem = useMemo(() => {
return async (key: string) => { return async (key: string) => {
return await localForage.getItem(key) const clientKey = `${clientType}_${key}`
return await localForage.getItem(clientKey)
} }
}, []) }, [props.clientType])
const removeItem = useMemo(() => { const removeItem = useMemo(() => {
return async (key: string) => { return async (key: string) => {
return await localForage.removeItem(key) const clientKey = `${clientType}_${key}`
return await localForage.removeItem(clientKey)
} }
}, []) }, [props.clientType])
return { return {

View File

@ -38,7 +38,7 @@ const InitialFileUploadSetting: FileUploadSetting = {
} }
export type UseServerSettingProps = { export type UseServerSettingProps = {
clientType: ClientType clientType: ClientType | null
voiceChangerClient: VoiceChangerClient | null voiceChangerClient: VoiceChangerClient | null
} }
@ -58,7 +58,7 @@ export type ServerSettingState = {
export const useServerSetting = (props: UseServerSettingProps): ServerSettingState => { export const useServerSetting = (props: UseServerSettingProps): ServerSettingState => {
// const settingRef = useRef<VoiceChangerServerSetting>(DefaultVoiceChangerServerSetting) // const settingRef = useRef<VoiceChangerServerSetting>(DefaultVoiceChangerServerSetting)
const defaultServerSetting = useMemo(() => { const getDefaultServerSetting = () => {
if (props.clientType == "MMVCv13") { if (props.clientType == "MMVCv13") {
return DefaultServerSetting_MMVCv13 return DefaultServerSetting_MMVCv13
} else if (props.clientType == "MMVCv15") { } else if (props.clientType == "MMVCv15") {
@ -75,43 +75,57 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
} else { } else {
return DefaultServerSetting_MMVCv15 return DefaultServerSetting_MMVCv15
} }
}, []) }
const [serverSetting, setServerSetting] = useState<ServerInfo>(defaultServerSetting)
const [serverSetting, setServerSetting] = useState<ServerInfo>(getDefaultServerSetting())
const [fileUploadSetting, setFileUploadSetting] = useState<FileUploadSetting>(InitialFileUploadSetting) const [fileUploadSetting, setFileUploadSetting] = useState<FileUploadSetting>(InitialFileUploadSetting)
const { setItem, getItem, removeItem } = useIndexedDB({ clientType: props.clientType }) const { setItem, getItem, removeItem } = useIndexedDB({ clientType: props.clientType })
// DBから設定取得キャッシュによる初期化 // clientTypeが新しく設定されたときに、serverのmodelType動作を変更設定反映
useEffect(() => { useEffect(() => {
const loadCache = async () => { if (!props.voiceChangerClient) return
const setting = await getItem(INDEXEDDB_KEY_SERVER) if (!props.clientType) return
if (!setting) {
const setInitialSetting = async () => {
// Set Model Type
await props.voiceChangerClient!.switchModelType(props.clientType!)
// Load Default (and Cache) and set
const defaultServerSetting = getDefaultServerSetting()
const cachedServerSetting = await getItem(INDEXEDDB_KEY_SERVER)
let initialSetting: ServerInfo
if (cachedServerSetting) {
initialSetting = { ...defaultServerSetting, ...cachedServerSetting as ServerInfo }
console.log("Initial Setting1:", initialSetting)
} else { } else {
setServerSetting(setting as ServerInfo) initialSetting = { ...defaultServerSetting }
console.log("Initial Setting2:", initialSetting)
}
setServerSetting(initialSetting)
// upload setting
for (let i = 0; i < Object.values(ServerSettingKey).length; i++) {
const k = Object.values(ServerSettingKey)[i] as keyof VoiceChangerServerSetting
const v = initialSetting[k]
if (v) {
props.voiceChangerClient!.updateServerSettings(k, "" + v)
}
} }
// Load file upload cache
const fileuploadSetting = await getItem(INDEXEDDB_KEY_MODEL_DATA) const fileuploadSetting = await getItem(INDEXEDDB_KEY_MODEL_DATA)
if (!fileuploadSetting) { if (!fileuploadSetting) {
} else { } else {
setFileUploadSetting(fileuploadSetting as FileUploadSetting) setFileUploadSetting(fileuploadSetting as FileUploadSetting)
} }
reloadServerInfo()
} }
loadCache() setInitialSetting()
}, [])
// サーバへキャッシュの内容を反映 (クライアント初期化した時の一回) }, [props.voiceChangerClient, props.clientType])
useEffect(() => {
if (!props.voiceChangerClient) return
for (let i = 0; i < Object.values(ServerSettingKey).length; i++) {
const k = Object.values(ServerSettingKey)[i] as keyof VoiceChangerServerSetting
const v = serverSetting[k]
if (v) {
props.voiceChangerClient.updateServerSettings(k, "" + v)
}
}
reloadServerInfo()
}, [props.voiceChangerClient])
////////////// //////////////
// 設定 // 設定
@ -125,7 +139,7 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
const new_v = setting[k] const new_v = setting[k]
if (cur_v != new_v) { if (cur_v != new_v) {
const res = await props.voiceChangerClient.updateServerSettings(k, "" + new_v) const res = await props.voiceChangerClient.updateServerSettings(k, "" + new_v)
if (res.onnxExecutionProviders.length > 0) { if (res.onnxExecutionProviders && res.onnxExecutionProviders.length > 0) {
res.onnxExecutionProvider = res.onnxExecutionProviders[0] res.onnxExecutionProvider = res.onnxExecutionProviders[0]
} else { } else {
res.onnxExecutionProvider = "CPUExecutionProvider" res.onnxExecutionProvider = "CPUExecutionProvider"

View File

@ -5,7 +5,7 @@ import { VoiceChangerClient } from "../VoiceChangerClient"
import { useIndexedDB } from "./useIndexedDB" import { useIndexedDB } from "./useIndexedDB"
export type UseWorkletNodeSettingProps = { export type UseWorkletNodeSettingProps = {
clientType: ClientType clientType: ClientType | null
voiceChangerClient: VoiceChangerClient | null voiceChangerClient: VoiceChangerClient | null
} }

View File

@ -4,7 +4,7 @@ import { VoiceChangerClient } from "../VoiceChangerClient";
import { useIndexedDB } from "./useIndexedDB"; import { useIndexedDB } from "./useIndexedDB";
export type UseWorkletSettingProps = { export type UseWorkletSettingProps = {
clientType: ClientType clientType: ClientType | null
voiceChangerClient: VoiceChangerClient | null voiceChangerClient: VoiceChangerClient | null
} }

View File

@ -8,8 +8,8 @@ class UvicornSuppressFilter(logging.Filter):
return False return False
# logger = logging.getLogger("uvicorn.error") logger = logging.getLogger("uvicorn.error")
# logger.addFilter(UvicornSuppressFilter()) logger.addFilter(UvicornSuppressFilter())
logger = logging.getLogger("fairseq.tasks.hubert_pretraining") logger = logging.getLogger("fairseq.tasks.hubert_pretraining")
logger.addFilter(UvicornSuppressFilter()) logger.addFilter(UvicornSuppressFilter())

View File

@ -9,7 +9,7 @@ from fastapi import HTTPException, FastAPI, UploadFile, File, Form
from restapi.mods.FileUploader import upload_file, concat_file_chunks from restapi.mods.FileUploader import upload_file, concat_file_chunks
from voice_changer.VoiceChangerManager import VoiceChangerManager from voice_changer.VoiceChangerManager import VoiceChangerManager
from const import MODEL_DIR, UPLOAD_DIR from const import MODEL_DIR, UPLOAD_DIR, ModelType
os.makedirs(UPLOAD_DIR, exist_ok=True) os.makedirs(UPLOAD_DIR, exist_ok=True)
os.makedirs(MODEL_DIR, exist_ok=True) os.makedirs(MODEL_DIR, exist_ok=True)
@ -25,8 +25,8 @@ class MMVC_Rest_Fileuploader:
self.router.add_api_route("/load_model", self.post_load_model, methods=["POST"]) self.router.add_api_route("/load_model", self.post_load_model, methods=["POST"])
self.router.add_api_route("/load_model_for_train", self.post_load_model_for_train, methods=["POST"]) self.router.add_api_route("/load_model_for_train", self.post_load_model_for_train, methods=["POST"])
self.router.add_api_route("/extract_voices", self.post_extract_voices, methods=["POST"]) self.router.add_api_route("/extract_voices", self.post_extract_voices, methods=["POST"])
self.router.add_api_route("/model_type", self.post_model_type, methods=["POST"])
self.onnx_provider = "" self.router.add_api_route("/model_type", self.get_model_type, methods=["GET"])
def post_upload_file(self, file: UploadFile = File(...), filename: str = Form(...)): def post_upload_file(self, file: UploadFile = File(...), filename: str = Form(...)):
res = upload_file(UPLOAD_DIR, file, filename) res = upload_file(UPLOAD_DIR, file, filename)
@ -95,3 +95,18 @@ class MMVC_Rest_Fileuploader:
UPLOAD_DIR, zipFilename, zipFileChunkNum, UPLOAD_DIR) UPLOAD_DIR, zipFilename, zipFileChunkNum, UPLOAD_DIR)
shutil.unpack_archive(zipFilePath, "MMVC_Trainer/dataset/textful/") shutil.unpack_archive(zipFilePath, "MMVC_Trainer/dataset/textful/")
return {"Zip file unpacked": f"{zipFilePath}"} return {"Zip file unpacked": f"{zipFilePath}"}
def post_model_type(
self,
modelType: ModelType = Form(...),
):
info = self.voiceChangerManager.switchModelType(modelType)
json_compatible_item_data = jsonable_encoder(info)
return JSONResponse(content=json_compatible_item_data)
def get_model_type(
self,
):
info = self.voiceChangerManager.getModelType(modelType)
json_compatible_item_data = jsonable_encoder(info)
return JSONResponse(content=json_compatible_item_data)

View File

@ -273,6 +273,10 @@ class DDSP_SVC:
del self.net_g del self.net_g
del self.onnx_session del self.onnx_session
def __del__(self):
del self.net_g
del self.onnx_session
def cross_fade(a: np.ndarray, b: np.ndarray, idx: int): def cross_fade(a: np.ndarray, b: np.ndarray, idx: int):
result = np.zeros(idx + b.shape[0]) result = np.zeros(idx + b.shape[0])

View File

@ -10,6 +10,7 @@ if sys.platform.startswith('darwin'):
else: else:
sys.path.append("MMVC_Client_v13/python") sys.path.append("MMVC_Client_v13/python")
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict
import numpy as np import numpy as np
import torch import torch
@ -199,6 +200,18 @@ class MMVCv13:
audio = self._pyTorch_inference(data) audio = self._pyTorch_inference(data)
return audio return audio
def destroy(self): def __del__(self):
del self.net_g del self.net_g
del self.onnx_session del self.onnx_session
remove_path = os.path.join("MMVC_Client_v13", "python")
sys.path = [x for x in sys.path if x.endswith(remove_path) == False]
for key in list(sys.modules):
val = sys.modules.get(key)
try:
file_path = val.__file__
if file_path.find("MMVC_Client_v13/python") >= 0:
print("remove", key, file_path)
sys.modules.pop(key)
except Exception as e:
pass

View File

@ -247,6 +247,19 @@ class MMVCv15:
audio = self._pyTorch_inference(data) audio = self._pyTorch_inference(data)
return audio return audio
def destroy(self): def __del__(self):
del self.net_g del self.net_g
del self.onnx_session del self.onnx_session
remove_path = os.path.join("MMVC_Client_v15", "python")
sys.path = [x for x in sys.path if x.endswith(remove_path) == False]
for key in list(sys.modules):
val = sys.modules.get(key)
try:
file_path = val.__file__
if file_path.find("MMVC_Client_v15/python") >= 0:
print("remove", key, file_path)
sys.modules.pop(key)
except Exception as e:
pass

View File

@ -277,6 +277,19 @@ class RVC:
audio = self._pyTorch_inference(data) audio = self._pyTorch_inference(data)
return audio return audio
def destroy(self): def __del__(self):
del self.net_g del self.net_g
del self.onnx_session del self.onnx_session
remove_path = os.path.join("RVC")
sys.path = [x for x in sys.path if x.endswith(remove_path) == False]
for key in list(sys.modules):
val = sys.modules.get(key)
try:
file_path = val.__file__
if file_path.find("RVC/") >= 0:
print("remove", key, file_path)
sys.modules.pop(key)
except Exception as e:
pass

View File

@ -351,9 +351,21 @@ class SoVitsSvc40:
audio = self._pyTorch_inference(data) audio = self._pyTorch_inference(data)
return audio return audio
def destroy(self): def __del__(self):
del self.net_g del self.net_g
del self.onnx_session del self.onnx_session
remove_path = os.path.join("so-vits-svc-40")
sys.path = [x for x in sys.path if x.endswith(remove_path) == False]
for key in list(sys.modules):
val = sys.modules.get(key)
try:
file_path = val.__file__
if file_path.find("so-vits-svc-40/") >= 0:
print("remove", key, file_path)
sys.modules.pop(key)
except Exception as e:
pass
def resize_f0(x, target_len): def resize_f0(x, target_len):

View File

@ -314,10 +314,23 @@ class SoVitsSvc40v2:
audio = self._pyTorch_inference(data) audio = self._pyTorch_inference(data)
return audio return audio
def destroy(self): def __del__(self):
del self.net_g del self.net_g
del self.onnx_session del self.onnx_session
remove_path = os.path.join("so-vits-svc-40v2")
sys.path = [x for x in sys.path if x.endswith(remove_path) == False]
for key in list(sys.modules):
val = sys.modules.get(key)
try:
file_path = val.__file__
if file_path.find("so-vits-svc-40v2/") >= 0:
print("remove", key, file_path)
sys.modules.pop(key)
except Exception as e:
pass
def resize_f0(x, target_len): def resize_f0(x, target_len):
source = np.array(x) source = np.array(x)

View File

@ -1,10 +1,10 @@
from typing import Any, Callable, Optional, Protocol, TypeAlias, Union, cast from typing import Any, Callable, Optional, Protocol, TypeAlias, Union, cast
from const import TMP_DIR, getModelType from const import TMP_DIR, ModelType
import torch import torch
import os import os
import traceback import traceback
import numpy as np import numpy as np
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict, field
import resampy import resampy
@ -46,9 +46,15 @@ class VoiceChangerSettings():
recordIO: int = 0 # 0:off, 1:on recordIO: int = 0 # 0:off, 1:on
# ↓mutableな物だけ列挙 # ↓mutableな物だけ列挙
intData: list[str] = ["inputSampleRate", "crossFadeOverlapSize", "recordIO"] intData: list[str] = field(
floatData: list[str] = ["crossFadeOffsetRate", "crossFadeEndRate"] default_factory=lambda: ["inputSampleRate", "crossFadeOverlapSize", "recordIO"]
strData: list[str] = [] )
floatData: list[str] = field(
default_factory=lambda: ["crossFadeOffsetRate", "crossFadeEndRate"]
)
strData: list[str] = field(
default_factory=lambda: []
)
class VoiceChanger(): class VoiceChanger():
@ -64,8 +70,46 @@ class VoiceChanger():
self.currentCrossFadeOverlapSize = 0 # setting self.currentCrossFadeOverlapSize = 0 # setting
self.crossfadeSize = 0 # calculated self.crossfadeSize = 0 # calculated
self.modelType = getModelType() # self.modelType = getModelType()
print("[VoiceChanger] activate model type:", self.modelType) # print("[VoiceChanger] activate model type:", self.modelType)
# if self.modelType == "MMVCv15":
# from voice_changer.MMVCv15.MMVCv15 import MMVCv15
# self.voiceChanger = MMVCv15() # type: ignore
# elif self.modelType == "MMVCv13":
# from voice_changer.MMVCv13.MMVCv13 import MMVCv13
# self.voiceChanger = MMVCv13()
# elif self.modelType == "so-vits-svc-40v2":
# from voice_changer.SoVitsSvc40v2.SoVitsSvc40v2 import SoVitsSvc40v2
# self.voiceChanger = SoVitsSvc40v2(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 = SoVitsSvc40(params)
# elif self.modelType == "DDSP-SVC":
# from voice_changer.DDSP_SVC.DDSP_SVC import DDSP_SVC
# self.voiceChanger = DDSP_SVC(params)
# elif self.modelType == "RVC":
# from voice_changer.RVC.RVC import RVC
# self.voiceChanger = RVC(params)
# else:
# from voice_changer.MMVCv13.MMVCv13 import MMVCv13
# self.voiceChanger = MMVCv13()
self.voiceChanger = None
self.modelType = None
self.params = params
self.gpu_num = torch.cuda.device_count()
self.prev_audio = np.zeros(4096)
self.mps_enabled: bool = getattr(torch.backends, "mps", None) is not None and torch.backends.mps.is_available()
print(f"VoiceChanger Initialized (GPU_NUM:{self.gpu_num}, mps_enabled:{self.mps_enabled})")
def switchModelType(self, modelType: ModelType):
if hasattr(self, "voiceChanger") and self.voiceChanger != None:
# return {"status": "ERROR", "msg": "vc is already selected. currently re-select is not implemented"}
del self.voiceChanger
self.voiceChanger = None
self.modelType = modelType
if self.modelType == "MMVCv15": if self.modelType == "MMVCv15":
from voice_changer.MMVCv15.MMVCv15 import MMVCv15 from voice_changer.MMVCv15.MMVCv15 import MMVCv15
self.voiceChanger = MMVCv15() # type: ignore self.voiceChanger = MMVCv15() # type: ignore
@ -74,25 +118,27 @@ class VoiceChanger():
self.voiceChanger = MMVCv13() self.voiceChanger = MMVCv13()
elif self.modelType == "so-vits-svc-40v2": elif self.modelType == "so-vits-svc-40v2":
from voice_changer.SoVitsSvc40v2.SoVitsSvc40v2 import SoVitsSvc40v2 from voice_changer.SoVitsSvc40v2.SoVitsSvc40v2 import SoVitsSvc40v2
self.voiceChanger = SoVitsSvc40v2(params) self.voiceChanger = SoVitsSvc40v2(self.params)
elif self.modelType == "so-vits-svc-40" or self.modelType == "so-vits-svc-40_c": elif self.modelType == "so-vits-svc-40" or self.modelType == "so-vits-svc-40_c":
from voice_changer.SoVitsSvc40.SoVitsSvc40 import SoVitsSvc40 from voice_changer.SoVitsSvc40.SoVitsSvc40 import SoVitsSvc40
self.voiceChanger = SoVitsSvc40(params) self.voiceChanger = SoVitsSvc40(self.params)
elif self.modelType == "DDSP-SVC": elif self.modelType == "DDSP-SVC":
from voice_changer.DDSP_SVC.DDSP_SVC import DDSP_SVC from voice_changer.DDSP_SVC.DDSP_SVC import DDSP_SVC
self.voiceChanger = DDSP_SVC(params) self.voiceChanger = DDSP_SVC(self.params)
elif self.modelType == "RVC": elif self.modelType == "RVC":
from voice_changer.RVC.RVC import RVC from voice_changer.RVC.RVC import RVC
self.voiceChanger = RVC(params) self.voiceChanger = RVC(self.params)
else: else:
from voice_changer.MMVCv13.MMVCv13 import MMVCv13 from voice_changer.MMVCv13.MMVCv13 import MMVCv13
self.voiceChanger = MMVCv13() self.voiceChanger = MMVCv13()
self.gpu_num = torch.cuda.device_count() return {"status": "OK", "msg": "vc is switched."}
self.prev_audio = np.zeros(4096)
self.mps_enabled: bool = getattr(torch.backends, "mps", None) is not None and torch.backends.mps.is_available()
print(f"VoiceChanger Initialized (GPU_NUM:{self.gpu_num}, mps_enabled:{self.mps_enabled})") def getModelType(self):
if self.modelType != None:
return {"status": "OK", "vc": self.modelType}
else:
return {"status": "OK", "vc": "none"}
def loadModel( def loadModel(
self, self,
@ -115,7 +161,8 @@ class VoiceChanger():
def get_info(self): def get_info(self):
data = asdict(self.settings) data = asdict(self.settings)
data.update(self.voiceChanger.get_info()) if hasattr(self, "voiceChanger"):
data.update(self.voiceChanger.get_info())
return data return data
def update_settings(self, key: str, val: Any): def update_settings(self, key: str, val: Any):
@ -148,10 +195,12 @@ class VoiceChanger():
elif key in self.settings.strData: elif key in self.settings.strData:
setattr(self.settings, key, str(val)) setattr(self.settings, key, str(val))
else: else:
ret = self.voiceChanger.update_settings(key, val) if hasattr(self, "voiceChanger"):
if ret == False: ret = self.voiceChanger.update_settings(key, val)
print(f"{key} is not mutable variable or unknown variable!") if ret == False:
print(f"{key} is not mutable variable or unknown variable!")
else:
print(f"voice changer is not initialized!")
return self.get_info() return self.get_info()
def _generate_strength(self, crossfadeSize: int): def _generate_strength(self, crossfadeSize: int):

View File

@ -1,5 +1,6 @@
import numpy as np import numpy as np
from voice_changer.VoiceChanger import VoiceChanger from voice_changer.VoiceChanger import VoiceChanger
from const import ModelType
class VoiceChangerManager(): class VoiceChangerManager():
@ -37,3 +38,9 @@ class VoiceChangerManager():
else: else:
print("Voice Change is not loaded. Did you load a correct model?") print("Voice Change is not loaded. Did you load a correct model?")
return np.zeros(1).astype(np.int16), [] return np.zeros(1).astype(np.int16), []
def switchModelType(self, modelType: ModelType):
return self.voiceChanger.switchModelType(modelType)
def getModelType(self):
return self.voiceChanger.getModelType()