refactoring, aggrigate to hooks
This commit is contained in:
parent
eda0296ce8
commit
e4b7eaebb4
2
client/demo/dist/index.js
vendored
2
client/demo/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@ -8,41 +8,21 @@ import { useAdvancedSetting } from "./105_advanced_setting";
|
|||||||
import { useSpeakerSetting } from "./103_speaker_setting";
|
import { useSpeakerSetting } from "./103_speaker_setting";
|
||||||
import { useClient } from "./hooks/useClient";
|
import { useClient } from "./hooks/useClient";
|
||||||
import { useServerControl } from "./106_server_control";
|
import { useServerControl } from "./106_server_control";
|
||||||
import { ServerSettingKey } from "@dannadori/voice-changer-client-js";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const useMicrophoneOptions = () => {
|
export const useMicrophoneOptions = () => {
|
||||||
const [audioContext, setAudioContext] = useState<AudioContext | null>(null)
|
const [audioContext, setAudioContext] = useState<AudioContext | null>(null)
|
||||||
const [loadModelFunc, setLoadModelFunc] = useState<() => Promise<void>>()
|
|
||||||
const [uploadProgress, setUploadProgress] = useState<number>(0)
|
|
||||||
const [isUploading, setIsUploading] = useState<boolean>(false)
|
|
||||||
const clientState = useClient({
|
const clientState = useClient({
|
||||||
audioContext: audioContext,
|
audioContext: audioContext,
|
||||||
audioOutputElementId: AUDIO_ELEMENT_FOR_PLAY_RESULT
|
audioOutputElementId: AUDIO_ELEMENT_FOR_PLAY_RESULT
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverSetting = useServerSetting({
|
const serverSetting = useServerSetting({ clientState })
|
||||||
clientState,
|
const deviceSetting = useDeviceSetting(audioContext, { clientState })
|
||||||
loadModelFunc,
|
const speakerSetting = useSpeakerSetting({ clientState })
|
||||||
uploadProgress: uploadProgress,
|
const convertSetting = useConvertSetting({ clientState })
|
||||||
isUploading: isUploading
|
const advancedSetting = useAdvancedSetting({ clientState })
|
||||||
})
|
const serverControl = useServerControl({ clientState })
|
||||||
const deviceSetting = useDeviceSetting(audioContext)
|
|
||||||
const speakerSetting = useSpeakerSetting()
|
|
||||||
const convertSetting = useConvertSetting()
|
|
||||||
const advancedSetting = useAdvancedSetting()
|
|
||||||
|
|
||||||
|
|
||||||
const serverControl = useServerControl({
|
|
||||||
convertStart: async () => { await clientState.start(serverSetting.mmvcServerUrl, serverSetting.protocol) },
|
|
||||||
convertStop: async () => { clientState.stop() },
|
|
||||||
getInfo: clientState.getInfo,
|
|
||||||
volume: clientState.volume,
|
|
||||||
bufferingTime: clientState.bufferingTime,
|
|
||||||
responseTime: clientState.responseTime,
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const createAudioContext = () => {
|
const createAudioContext = () => {
|
||||||
@ -55,100 +35,6 @@ export const useMicrophoneOptions = () => {
|
|||||||
document.addEventListener('mousedown', createAudioContext);
|
document.addEventListener('mousedown', createAudioContext);
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// 101 ServerSetting
|
|
||||||
//// サーバ変更
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.setServerUrl(serverSetting.mmvcServerUrl)
|
|
||||||
}, [serverSetting.mmvcServerUrl])
|
|
||||||
//// プロトコル変更
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.setProtocol(serverSetting.protocol)
|
|
||||||
}, [serverSetting.protocol])
|
|
||||||
//// フレームワーク変更
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.framework, serverSetting.framework)
|
|
||||||
}, [serverSetting.framework])
|
|
||||||
//// OnnxExecutionProvider変更
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.onnxExecutionProvider, serverSetting.onnxExecutionProvider)
|
|
||||||
}, [serverSetting.onnxExecutionProvider])
|
|
||||||
|
|
||||||
// 102 DeviceSetting
|
|
||||||
//// 入力情報の設定
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.changeInput(deviceSetting.audioInput, convertSetting.bufferSize, advancedSetting.vfForceDisabled)
|
|
||||||
}, [deviceSetting.audioInput, convertSetting.bufferSize, advancedSetting.vfForceDisabled])
|
|
||||||
|
|
||||||
// 103 SpeakerSetting
|
|
||||||
// 音声変換元、変換先の設定
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.srcId, speakerSetting.srcId)
|
|
||||||
}, [speakerSetting.srcId])
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.dstId, speakerSetting.dstId)
|
|
||||||
}, [speakerSetting.dstId])
|
|
||||||
|
|
||||||
// 104 ConvertSetting
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.setInputChunkNum(convertSetting.inputChunkNum)
|
|
||||||
}, [convertSetting.inputChunkNum])
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.convertChunkNum, convertSetting.convertChunkNum)
|
|
||||||
}, [convertSetting.convertChunkNum])
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.gpu, convertSetting.gpu)
|
|
||||||
}, [convertSetting.gpu])
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.crossFadeOffsetRate, convertSetting.crossFadeOffsetRate)
|
|
||||||
}, [convertSetting.crossFadeOffsetRate])
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.updateSettings(ServerSettingKey.crossFadeEndRate, convertSetting.crossFadeEndRate)
|
|
||||||
}, [convertSetting.crossFadeEndRate])
|
|
||||||
|
|
||||||
// 105 AdvancedSetting
|
|
||||||
useEffect(() => {
|
|
||||||
clientState.setVoiceChangerMode(advancedSetting.voiceChangerMode)
|
|
||||||
}, [advancedSetting.voiceChangerMode])
|
|
||||||
|
|
||||||
|
|
||||||
// Model Load
|
|
||||||
useEffect(() => {
|
|
||||||
const loadModel = () => {
|
|
||||||
return async () => {
|
|
||||||
if (!serverSetting.pyTorchModel && !serverSetting.onnxModel) {
|
|
||||||
alert("PyTorchモデルとONNXモデルのどちらか一つ以上指定する必要があります。")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!serverSetting.configFile) {
|
|
||||||
alert("Configファイルを指定する必要があります。")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setUploadProgress(0)
|
|
||||||
setIsUploading(true)
|
|
||||||
const models = [serverSetting.pyTorchModel, serverSetting.onnxModel].filter(x => { return x != null }) as File[]
|
|
||||||
for (let i = 0; i < models.length; i++) {
|
|
||||||
const progRate = 1 / models.length
|
|
||||||
const progOffset = 100 * i * progRate
|
|
||||||
await clientState.uploadFile(models[i], (progress: number, end: boolean) => {
|
|
||||||
// console.log(progress * progRate + progOffset, end, progRate,)
|
|
||||||
setUploadProgress(progress * progRate + progOffset)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
await clientState.uploadFile(serverSetting.configFile, (progress: number, end: boolean) => {
|
|
||||||
console.log(progress, end)
|
|
||||||
})
|
|
||||||
|
|
||||||
await clientState.loadModel(serverSetting.configFile, serverSetting.pyTorchModel, serverSetting.onnxModel)
|
|
||||||
setUploadProgress(0)
|
|
||||||
setIsUploading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setLoadModelFunc(loadModel)
|
|
||||||
}, [serverSetting.configFile, serverSetting.pyTorchModel, serverSetting.onnxModel,
|
|
||||||
serverSetting.framework, serverSetting.onnxExecutionProvider, speakerSetting.srcId, speakerSetting.dstId, convertSetting.gpu, convertSetting.crossFadeOffsetRate, convertSetting.crossFadeEndRate
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
const voiceChangerSetting = useMemo(() => {
|
const voiceChangerSetting = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
@ -1,53 +1,37 @@
|
|||||||
import { DefaultVoiceChangerOptions, OnnxExecutionProvider, Protocol, Framework, fileSelector, ServerSettingKey } from "@dannadori/voice-changer-client-js"
|
import { OnnxExecutionProvider, Protocol, Framework, fileSelector } from "@dannadori/voice-changer-client-js"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { useMemo, useState } from "react"
|
import { useMemo } from "react"
|
||||||
import { ClientState } from "./hooks/useClient"
|
import { ClientState } from "./hooks/useClient"
|
||||||
|
|
||||||
export type UseServerSettingProps = {
|
export type UseServerSettingProps = {
|
||||||
clientState: ClientState
|
clientState: ClientState
|
||||||
loadModelFunc: (() => Promise<void>) | undefined
|
|
||||||
uploadProgress: number,
|
|
||||||
isUploading: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ServerSettingState = {
|
export type ServerSettingState = {
|
||||||
serverSetting: JSX.Element;
|
serverSetting: JSX.Element;
|
||||||
mmvcServerUrl: string;
|
|
||||||
pyTorchModel: File | null;
|
|
||||||
configFile: File | null;
|
|
||||||
onnxModel: File | null;
|
|
||||||
framework: string;
|
|
||||||
onnxExecutionProvider: OnnxExecutionProvider;
|
|
||||||
protocol: Protocol;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useServerSetting = (props: UseServerSettingProps): ServerSettingState => {
|
export const useServerSetting = (props: UseServerSettingProps): ServerSettingState => {
|
||||||
const [mmvcServerUrl, setMmvcServerUrl] = useState<string>(DefaultVoiceChangerOptions.mmvcServerUrl)
|
|
||||||
const [pyTorchModel, setPyTorchModel] = useState<File | null>(null)
|
|
||||||
const [configFile, setConfigFile] = useState<File | null>(null)
|
|
||||||
const [onnxModel, setOnnxModel] = useState<File | null>(null)
|
|
||||||
const [protocol, setProtocol] = useState<Protocol>("sio")
|
|
||||||
const [onnxExecutionProvider, setOnnxExecutionProvider] = useState<OnnxExecutionProvider>("CPUExecutionProvider")
|
|
||||||
const [framework, setFramework] = useState<Framework>("PyTorch")
|
|
||||||
|
|
||||||
const mmvcServerUrlRow = useMemo(() => {
|
const mmvcServerUrlRow = useMemo(() => {
|
||||||
const onSetServerClicked = async () => {
|
const onSetServerClicked = async () => {
|
||||||
const input = document.getElementById("mmvc-server-url") as HTMLInputElement
|
const input = document.getElementById("mmvc-server-url") as HTMLInputElement
|
||||||
setMmvcServerUrl(input.value)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
mmvcServerUrl: input.value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<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">MMVC Server</div>
|
<div className="body-item-title left-padding-1">MMVC Server</div>
|
||||||
<div className="body-input-container">
|
<div className="body-input-container">
|
||||||
<input type="text" defaultValue={mmvcServerUrl} id="mmvc-server-url" className="body-item-input" />
|
<input type="text" defaultValue={props.clientState.settingState.mmvcServerUrl} id="mmvc-server-url" className="body-item-input" />
|
||||||
</div>
|
</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
<div className="body-button" onClick={onSetServerClicked}>set</div>
|
<div className="body-button" onClick={onSetServerClicked}>set</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const uploadeModelRow = useMemo(() => {
|
const uploadeModelRow = useMemo(() => {
|
||||||
const onPyTorchFileLoadClicked = async () => {
|
const onPyTorchFileLoadClicked = async () => {
|
||||||
@ -56,10 +40,16 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
alert("モデルファイルの拡張子はpthである必要があります。")
|
alert("モデルファイルの拡張子はpthである必要があります。")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setPyTorchModel(file)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
pyTorchModel: file
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onPyTorchFileClearClicked = () => {
|
const onPyTorchFileClearClicked = () => {
|
||||||
setPyTorchModel(null)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
pyTorchModel: null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onConfigFileLoadClicked = async () => {
|
const onConfigFileLoadClicked = async () => {
|
||||||
const file = await fileSelector("")
|
const file = await fileSelector("")
|
||||||
@ -67,10 +57,16 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
alert("モデルファイルの拡張子はjsonである必要があります。")
|
alert("モデルファイルの拡張子はjsonである必要があります。")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setConfigFile(file)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
configFile: file
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onConfigFileClearClicked = () => {
|
const onConfigFileClearClicked = () => {
|
||||||
setConfigFile(null)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
configFile: null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onOnnxFileLoadClicked = async () => {
|
const onOnnxFileLoadClicked = async () => {
|
||||||
const file = await fileSelector("")
|
const file = await fileSelector("")
|
||||||
@ -78,16 +74,19 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
alert("モデルファイルの拡張子はonnxである必要があります。")
|
alert("モデルファイルの拡張子はonnxである必要があります。")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setOnnxModel(file)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
onnxModel: file
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onOnnxFileClearClicked = () => {
|
const onOnnxFileClearClicked = () => {
|
||||||
setOnnxModel(null)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
onnxModel: null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onModelUploadClicked = async () => {
|
const onModelUploadClicked = async () => {
|
||||||
if (!props.loadModelFunc) {
|
props.clientState.loadModel()
|
||||||
return
|
|
||||||
}
|
|
||||||
props.loadModelFunc()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -104,7 +103,7 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
<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-2">PyTorch(.pth)</div>
|
<div className="body-item-title left-padding-2">PyTorch(.pth)</div>
|
||||||
<div className="body-item-text">
|
<div className="body-item-text">
|
||||||
<div>{pyTorchModel?.name}</div>
|
<div>{props.clientState.settingState.pyTorchModel?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
<div className="body-button" onClick={onPyTorchFileLoadClicked}>select</div>
|
<div className="body-button" onClick={onPyTorchFileLoadClicked}>select</div>
|
||||||
@ -114,7 +113,7 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
<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-2">Config(.json)</div>
|
<div className="body-item-title left-padding-2">Config(.json)</div>
|
||||||
<div className="body-item-text">
|
<div className="body-item-text">
|
||||||
<div>{configFile?.name}</div>
|
<div>{props.clientState.settingState.configFile?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
<div className="body-button" onClick={onConfigFileLoadClicked}>select</div>
|
<div className="body-button" onClick={onConfigFileLoadClicked}>select</div>
|
||||||
@ -124,7 +123,7 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
<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-2">Onnx(.onnx)</div>
|
<div className="body-item-title left-padding-2">Onnx(.onnx)</div>
|
||||||
<div className="body-item-text">
|
<div className="body-item-text">
|
||||||
<div>{onnxModel?.name}</div>
|
<div>{props.clientState.settingState.onnxModel?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
<div className="body-button" onClick={onOnnxFileLoadClicked}>select</div>
|
<div className="body-button" onClick={onOnnxFileLoadClicked}>select</div>
|
||||||
@ -134,7 +133,7 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
<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-2"></div>
|
<div className="body-item-title left-padding-2"></div>
|
||||||
<div className="body-item-text">
|
<div className="body-item-text">
|
||||||
{props.isUploading ? `uploading.... ${props.uploadProgress}%` : ""}
|
{props.clientState.isUploading ? `uploading.... ${props.clientState.uploadProgress}%` : ""}
|
||||||
</div>
|
</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
<div className="body-button" onClick={onModelUploadClicked}>upload</div>
|
<div className="body-button" onClick={onModelUploadClicked}>upload</div>
|
||||||
@ -142,17 +141,24 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}, [pyTorchModel, configFile, onnxModel, props.loadModelFunc, props.isUploading, props.uploadProgress])
|
}, [
|
||||||
|
props.clientState.settingState,
|
||||||
|
props.clientState.loadModel,
|
||||||
|
props.clientState.isUploading,
|
||||||
|
props.clientState.uploadProgress])
|
||||||
|
|
||||||
const protocolRow = useMemo(() => {
|
const protocolRow = useMemo(() => {
|
||||||
const onProtocolChanged = async (val: Protocol) => {
|
const onProtocolChanged = async (val: Protocol) => {
|
||||||
setProtocol(val)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
protocol: val
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<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">Protocol</div>
|
<div className="body-item-title left-padding-1">Protocol</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={protocol} onChange={(e) => {
|
<select className="body-select" value={props.clientState.settingState.protocol} onChange={(e) => {
|
||||||
onProtocolChanged(e.target.value as
|
onProtocolChanged(e.target.value as
|
||||||
Protocol)
|
Protocol)
|
||||||
}}>
|
}}>
|
||||||
@ -165,17 +171,20 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [protocol])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const frameworkRow = useMemo(() => {
|
const frameworkRow = useMemo(() => {
|
||||||
const onFrameworkChanged = async (val: Framework) => {
|
const onFrameworkChanged = async (val: Framework) => {
|
||||||
setFramework(val)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
framework: val
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<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">Framework</div>
|
<div className="body-item-title left-padding-1">Framework</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={framework} onChange={(e) => {
|
<select className="body-select" value={props.clientState.settingState.framework} onChange={(e) => {
|
||||||
onFrameworkChanged(e.target.value as
|
onFrameworkChanged(e.target.value as
|
||||||
Framework)
|
Framework)
|
||||||
}}>
|
}}>
|
||||||
@ -188,20 +197,23 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [framework])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const onnxExecutionProviderRow = useMemo(() => {
|
const onnxExecutionProviderRow = useMemo(() => {
|
||||||
if (framework != "ONNX") {
|
if (props.clientState.settingState.framework != "ONNX") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const onOnnxExecutionProviderChanged = async (val: OnnxExecutionProvider) => {
|
const onOnnxExecutionProviderChanged = async (val: OnnxExecutionProvider) => {
|
||||||
setOnnxExecutionProvider(val)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
onnxExecutionProvider: val
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="body-row split-3-7 left-padding-1">
|
<div className="body-row split-3-7 left-padding-1">
|
||||||
<div className="body-item-title left-padding-2">OnnxExecutionProvider</div>
|
<div className="body-item-title left-padding-2">OnnxExecutionProvider</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={onnxExecutionProvider} onChange={(e) => {
|
<select className="body-select" value={props.clientState.settingState.onnxExecutionProvider} onChange={(e) => {
|
||||||
onOnnxExecutionProviderChanged(e.target.value as
|
onOnnxExecutionProviderChanged(e.target.value as
|
||||||
OnnxExecutionProvider)
|
OnnxExecutionProvider)
|
||||||
}}>
|
}}>
|
||||||
@ -214,7 +226,7 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [onnxExecutionProvider, framework, mmvcServerUrl])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const serverSetting = useMemo(() => {
|
const serverSetting = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -236,13 +248,5 @@ export const useServerSetting = (props: UseServerSettingProps): ServerSettingSta
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
serverSetting,
|
serverSetting,
|
||||||
mmvcServerUrl,
|
|
||||||
pyTorchModel,
|
|
||||||
configFile,
|
|
||||||
onnxModel,
|
|
||||||
framework,
|
|
||||||
onnxExecutionProvider,
|
|
||||||
protocol,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { fileSelectorAsDataURL, createDummyMediaStream, SampleRate } from "@dannadori/voice-changer-client-js"
|
import { fileSelectorAsDataURL, createDummyMediaStream, SampleRate } from "@dannadori/voice-changer-client-js"
|
||||||
import React, { useEffect, useMemo, useState } from "react"
|
import React, { useEffect, useMemo, useState } from "react"
|
||||||
import { AUDIO_ELEMENT_FOR_PLAY_RESULT, AUDIO_ELEMENT_FOR_TEST_CONVERTED, AUDIO_ELEMENT_FOR_TEST_ORIGINAL } from "./const"
|
import { AUDIO_ELEMENT_FOR_PLAY_RESULT, AUDIO_ELEMENT_FOR_TEST_CONVERTED, AUDIO_ELEMENT_FOR_TEST_ORIGINAL } from "./const"
|
||||||
|
import { ClientState } from "./hooks/useClient";
|
||||||
|
|
||||||
|
|
||||||
const reloadDevices = async () => {
|
const reloadDevices = async () => {
|
||||||
@ -29,22 +30,20 @@ const reloadDevices = async () => {
|
|||||||
const audioOutputs = mediaDeviceInfos.filter(x => { return x.kind == "audiooutput" })
|
const audioOutputs = mediaDeviceInfos.filter(x => { return x.kind == "audiooutput" })
|
||||||
return [audioInputs, audioOutputs]
|
return [audioInputs, audioOutputs]
|
||||||
}
|
}
|
||||||
|
export type UseDeviceSettingProps = {
|
||||||
|
clientState: ClientState
|
||||||
|
}
|
||||||
|
|
||||||
export type DeviceSettingState = {
|
export type DeviceSettingState = {
|
||||||
deviceSetting: JSX.Element;
|
deviceSetting: JSX.Element;
|
||||||
audioInput: string | MediaStream;
|
|
||||||
sampleRate: SampleRate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useDeviceSetting = (audioContext: AudioContext | null): DeviceSettingState => {
|
export const useDeviceSetting = (audioContext: AudioContext | null, props: UseDeviceSettingProps): DeviceSettingState => {
|
||||||
const [inputAudioDeviceInfo, setInputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([])
|
const [inputAudioDeviceInfo, setInputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([])
|
||||||
const [outputAudioDeviceInfo, setOutputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([])
|
const [outputAudioDeviceInfo, setOutputAudioDeviceInfo] = useState<MediaDeviceInfo[]>([])
|
||||||
|
|
||||||
const [audioInputForGUI, setAudioInputForGUI] = useState<string>("none")
|
const [audioInputForGUI, setAudioInputForGUI] = useState<string>("none")
|
||||||
const [audioInput, setAudioInput] = useState<string | MediaStream>("none")
|
|
||||||
const [audioOutputForGUI, setAudioOutputForGUI] = useState<string>("none")
|
const [audioOutputForGUI, setAudioOutputForGUI] = useState<string>("none")
|
||||||
const [sampleRate, setSampleRate] = useState<SampleRate>(48000)
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -88,11 +87,17 @@ export const useDeviceSetting = (audioContext: AudioContext | null): DeviceSetti
|
|||||||
}
|
}
|
||||||
if (audioInputForGUI == "none") {
|
if (audioInputForGUI == "none") {
|
||||||
const ms = createDummyMediaStream(audioContext)
|
const ms = createDummyMediaStream(audioContext)
|
||||||
setAudioInput(ms)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
audioInput: ms
|
||||||
|
})
|
||||||
} else if (audioInputForGUI == "file") {
|
} else if (audioInputForGUI == "file") {
|
||||||
// file selector (audioMediaInputRow)
|
// file selector (audioMediaInputRow)
|
||||||
} else {
|
} else {
|
||||||
setAudioInput(audioInputForGUI)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
audioInput: audioInputForGUI
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, [audioContext, audioInputForGUI])
|
}, [audioContext, audioInputForGUI])
|
||||||
|
|
||||||
@ -111,8 +116,10 @@ export const useDeviceSetting = (audioContext: AudioContext | null): DeviceSetti
|
|||||||
const src = audioContext!.createMediaElementSource(audio);
|
const src = audioContext!.createMediaElementSource(audio);
|
||||||
const dst = audioContext!.createMediaStreamDestination()
|
const dst = audioContext!.createMediaStreamDestination()
|
||||||
src.connect(dst)
|
src.connect(dst)
|
||||||
setAudioInput(dst.stream)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
audioInput: dst.stream
|
||||||
|
})
|
||||||
// original stream to play.
|
// original stream to play.
|
||||||
const audio_org = document.getElementById(AUDIO_ELEMENT_FOR_TEST_ORIGINAL) as HTMLAudioElement
|
const audio_org = document.getElementById(AUDIO_ELEMENT_FOR_TEST_ORIGINAL) as HTMLAudioElement
|
||||||
audio_org.src = url
|
audio_org.src = url
|
||||||
@ -179,7 +186,13 @@ export const useDeviceSetting = (audioContext: AudioContext | null): DeviceSetti
|
|||||||
<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">Sample Rate</div>
|
<div className="body-item-title left-padding-1">Sample Rate</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={sampleRate} onChange={(e) => { setSampleRate(Number(e.target.value) as SampleRate) }}>
|
<select className="body-select" value={props.clientState.settingState.sampleRate} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
sampleRate: Number(e.target.value) as SampleRate
|
||||||
|
})
|
||||||
|
|
||||||
|
}}>
|
||||||
{
|
{
|
||||||
Object.values(SampleRate).map(x => {
|
Object.values(SampleRate).map(x => {
|
||||||
return <option key={x} value={x}>{x}</option>
|
return <option key={x} value={x}>{x}</option>
|
||||||
@ -189,7 +202,7 @@ export const useDeviceSetting = (audioContext: AudioContext | null): DeviceSetti
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [sampleRate])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -211,7 +224,5 @@ export const useDeviceSetting = (audioContext: AudioContext | null): DeviceSetti
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
deviceSetting,
|
deviceSetting,
|
||||||
audioInput,
|
|
||||||
sampleRate,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
import { DefaultVoiceChangerRequestParamas, DefaultVoiceChangerOptions, Speaker } from "@dannadori/voice-changer-client-js"
|
import React, { useMemo } from "react"
|
||||||
import React, { useMemo, useState } from "react"
|
import { ClientState } from "./hooks/useClient"
|
||||||
|
|
||||||
|
export type UseSpeakerSettingProps = {
|
||||||
|
clientState: ClientState
|
||||||
|
}
|
||||||
|
|
||||||
export const useSpeakerSetting = () => {
|
export const useSpeakerSetting = (props: UseSpeakerSettingProps) => {
|
||||||
const [speakers, setSpeakers] = useState<Speaker[]>(DefaultVoiceChangerOptions.speakers)
|
|
||||||
const [editSpeakerTargetId, setEditSpeakerTargetId] = useState<number>(0)
|
|
||||||
const [editSpeakerTargetName, setEditSpeakerTargetName] = useState<string>("")
|
|
||||||
|
|
||||||
const [srcId, setSrcId] = useState<number>(DefaultVoiceChangerRequestParamas.srcId)
|
|
||||||
const [dstId, setDstId] = useState<number>(DefaultVoiceChangerRequestParamas.dstId)
|
|
||||||
|
|
||||||
|
|
||||||
const srcIdRow = useMemo(() => {
|
const srcIdRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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">Source Speaker Id</div>
|
<div className="body-item-title left-padding-1">Source Speaker Id</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={srcId} onChange={(e) => { setSrcId(Number(e.target.value)) }}>
|
<select className="body-select" value={props.clientState.settingState.srcId} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
srcId: Number(e.target.value)
|
||||||
|
})
|
||||||
|
}}>
|
||||||
{
|
{
|
||||||
speakers.map(x => {
|
props.clientState.settingState.speakers.map(x => {
|
||||||
return <option key={x.id} value={x.id}>{x.name}({x.id})</option>
|
return <option key={x.id} value={x.id}>{x.name}({x.id})</option>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -26,16 +27,21 @@ export const useSpeakerSetting = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [srcId, speakers])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const dstIdRow = useMemo(() => {
|
const dstIdRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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">Destination Speaker Id</div>
|
<div className="body-item-title left-padding-1">Destination Speaker Id</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={dstId} onChange={(e) => { setDstId(Number(e.target.value)) }}>
|
<select className="body-select" value={props.clientState.settingState.dstId} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
dstId: Number(e.target.value)
|
||||||
|
})
|
||||||
|
}}>
|
||||||
{
|
{
|
||||||
speakers.map(x => {
|
props.clientState.settingState.speakers.map(x => {
|
||||||
return <option key={x.id} value={x.id}>{x.name}({x.id})</option>
|
return <option key={x.id} value={x.id}>{x.name}({x.id})</option>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -43,29 +49,38 @@ export const useSpeakerSetting = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [dstId, speakers])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const editSpeakerIdMappingRow = useMemo(() => {
|
const editSpeakerIdMappingRow = useMemo(() => {
|
||||||
const onSetSpeakerMappingClicked = async () => {
|
const onSetSpeakerMappingClicked = async () => {
|
||||||
const targetId = editSpeakerTargetId
|
const targetId = props.clientState.settingState.editSpeakerTargetId
|
||||||
const targetName = editSpeakerTargetName
|
const targetName = props.clientState.settingState.editSpeakerTargetName
|
||||||
const targetSpeaker = speakers.find(x => { return x.id == targetId })
|
const targetSpeaker = props.clientState.settingState.speakers.find(x => { return x.id == targetId })
|
||||||
if (targetSpeaker) {
|
if (targetSpeaker) {
|
||||||
if (targetName.length == 0) { // Delete
|
if (targetName.length == 0) { // Delete
|
||||||
const newSpeakers = speakers.filter(x => { return x.id != targetId })
|
const newSpeakers = props.clientState.settingState.speakers.filter(x => { return x.id != targetId })
|
||||||
setSpeakers(newSpeakers)
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
speakers: newSpeakers
|
||||||
|
})
|
||||||
} else { // Update
|
} else { // Update
|
||||||
targetSpeaker.name = targetName
|
targetSpeaker.name = targetName
|
||||||
setSpeakers([...speakers])
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
speakers: props.clientState.settingState.speakers
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetName.length == 0) { // Noop
|
if (targetName.length == 0) { // Noop
|
||||||
} else {// add
|
} else {// add
|
||||||
speakers.push({
|
props.clientState.settingState.speakers.push({
|
||||||
id: targetId,
|
id: targetId,
|
||||||
name: targetName
|
name: targetName
|
||||||
})
|
})
|
||||||
setSpeakers([...speakers])
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
speakers: props.clientState.settingState.speakers
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,21 +88,29 @@ export const useSpeakerSetting = () => {
|
|||||||
<div className="body-row split-3-1-2-4 left-padding-1 guided">
|
<div className="body-row split-3-1-2-4 left-padding-1 guided">
|
||||||
<div className="body-item-title left-padding-1">Edit Speaker Mapping</div>
|
<div className="body-item-title left-padding-1">Edit Speaker Mapping</div>
|
||||||
<div className="body-input-container">
|
<div className="body-input-container">
|
||||||
<input type="number" min={1} max={256} step={1} value={editSpeakerTargetId} onChange={(e) => {
|
<input type="number" min={1} max={256} step={1} value={props.clientState.settingState.editSpeakerTargetId} onChange={(e) => {
|
||||||
const id = Number(e.target.value)
|
const id = Number(e.target.value)
|
||||||
setEditSpeakerTargetId(id)
|
props.clientState.setSettingState({
|
||||||
setEditSpeakerTargetName(speakers.find(x => { return x.id == id })?.name || "")
|
...props.clientState.settingState,
|
||||||
|
editSpeakerTargetId: id,
|
||||||
|
editSpeakerTargetName: props.clientState.settingState.speakers.find(x => { return x.id == id })?.name || ""
|
||||||
|
})
|
||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<div className="body-input-container">
|
<div className="body-input-container">
|
||||||
<input type="text" value={editSpeakerTargetName} onChange={(e) => { setEditSpeakerTargetName(e.target.value) }} />
|
<input type="text" value={props.clientState.settingState.editSpeakerTargetName} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
editSpeakerTargetName: e.target.value
|
||||||
|
})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
<div className="body-button" onClick={onSetSpeakerMappingClicked}>set</div>
|
<div className="body-button" onClick={onSetSpeakerMappingClicked}>set</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [speakers, editSpeakerTargetId, editSpeakerTargetName])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
|
|
||||||
const speakerSetting = useMemo(() => {
|
const speakerSetting = useMemo(() => {
|
||||||
@ -107,8 +130,6 @@ export const useSpeakerSetting = () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
speakerSetting,
|
speakerSetting,
|
||||||
srcId,
|
|
||||||
dstId,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
import { DefaultVoiceChangerRequestParamas, DefaultVoiceChangerOptions, BufferSize } from "@dannadori/voice-changer-client-js"
|
import { DefaultVoiceChangerRequestParamas, DefaultVoiceChangerOptions, BufferSize } from "@dannadori/voice-changer-client-js"
|
||||||
import React, { useMemo, useState } from "react"
|
import React, { useMemo, useState } from "react"
|
||||||
|
import { ClientState } from "./hooks/useClient"
|
||||||
|
|
||||||
export type SpeakerSettingState = {
|
export type UseConvertSettingProps = {
|
||||||
convertSetting: JSX.Element;
|
clientState: ClientState
|
||||||
bufferSize: BufferSize;
|
|
||||||
inputChunkNum: number;
|
|
||||||
convertChunkNum: number;
|
|
||||||
gpu: number;
|
|
||||||
crossFadeOffsetRate: number;
|
|
||||||
crossFadeEndRate: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useConvertSetting = (): SpeakerSettingState => {
|
export type ConvertSettingState = {
|
||||||
|
convertSetting: JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
const [bufferSize, setBufferSize] = useState<BufferSize>(1024)
|
export const useConvertSetting = (props: UseConvertSettingProps): ConvertSettingState => {
|
||||||
const [inputChunkNum, setInputChunkNum] = useState<number>(DefaultVoiceChangerOptions.inputChunkNum)
|
|
||||||
const [convertChunkNum, setConvertChunkNum] = useState<number>(DefaultVoiceChangerRequestParamas.convertChunkNum)
|
|
||||||
const [gpu, setGpu] = useState<number>(DefaultVoiceChangerRequestParamas.gpu)
|
|
||||||
|
|
||||||
const [crossFadeOffsetRate, setCrossFadeOffsetRate] = useState<number>(DefaultVoiceChangerRequestParamas.crossFadeOffsetRate)
|
|
||||||
const [crossFadeEndRate, setCrossFadeEndRate] = useState<number>(DefaultVoiceChangerRequestParamas.crossFadeEndRate)
|
|
||||||
|
|
||||||
const bufferSizeRow = useMemo(() => {
|
const bufferSizeRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -27,7 +18,12 @@ export const useConvertSetting = (): SpeakerSettingState => {
|
|||||||
<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">Buffer Size</div>
|
<div className="body-item-title left-padding-1">Buffer Size</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={bufferSize} onChange={(e) => { setBufferSize(Number(e.target.value) as BufferSize) }}>
|
<select className="body-select" value={props.clientState.settingState.bufferSize} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
bufferSize: Number(e.target.value) as BufferSize
|
||||||
|
})
|
||||||
|
}}>
|
||||||
{
|
{
|
||||||
Object.values(BufferSize).map(x => {
|
Object.values(BufferSize).map(x => {
|
||||||
return <option key={x} value={x}>{x}</option>
|
return <option key={x} value={x}>{x}</option>
|
||||||
@ -37,18 +33,23 @@ export const useConvertSetting = (): SpeakerSettingState => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [bufferSize])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const inputChunkNumRow = useMemo(() => {
|
const inputChunkNumRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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">Input Chunk Num(128sample/chunk)</div>
|
<div className="body-item-title left-padding-1">Input Chunk Num(128sample/chunk)</div>
|
||||||
<div className="body-input-container">
|
<div className="body-input-container">
|
||||||
<input type="number" min={1} max={256} step={1} value={inputChunkNum} onChange={(e) => { setInputChunkNum(Number(e.target.value)) }} />
|
<input type="number" min={1} max={256} step={1} value={props.clientState.settingState.inputChunkNum} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
inputChunkNum: Number(e.target.value)
|
||||||
|
})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [inputChunkNum])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const convertChunkNumRow = useMemo(() => {
|
const convertChunkNumRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -56,44 +57,64 @@ export const useConvertSetting = (): SpeakerSettingState => {
|
|||||||
<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">Convert Chunk Num(128sample/chunk)</div>
|
<div className="body-item-title left-padding-1">Convert Chunk Num(128sample/chunk)</div>
|
||||||
<div className="body-input-container">
|
<div className="body-input-container">
|
||||||
<input type="number" min={1} max={256} step={1} value={convertChunkNum} onChange={(e) => { setConvertChunkNum(Number(e.target.value)) }} />
|
<input type="number" min={1} max={256} step={1} value={props.clientState.settingState.convertChunkNum} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
convertChunkNum: Number(e.target.value)
|
||||||
|
})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [convertChunkNum])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const gpuRow = useMemo(() => {
|
const gpuRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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={gpu} onChange={(e) => { setGpu(Number(e.target.value)) }} />
|
<input type="number" min={-2} max={5} step={1} value={props.clientState.settingState.gpu} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
gpu: Number(e.target.value)
|
||||||
|
})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [gpu])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const crossFadeOffsetRateRow = useMemo(() => {
|
const crossFadeOffsetRateRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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">Cross Fade Offset Rate</div>
|
<div className="body-item-title left-padding-1">Cross Fade Offset Rate</div>
|
||||||
<div className="body-input-container">
|
<div className="body-input-container">
|
||||||
<input type="number" min={0} max={1} step={0.1} value={crossFadeOffsetRate} onChange={(e) => { setCrossFadeOffsetRate(Number(e.target.value)) }} />
|
<input type="number" min={0} max={1} step={0.1} value={props.clientState.settingState.crossFadeOffsetRate} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
crossFadeOffsetRate: Number(e.target.value)
|
||||||
|
})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [crossFadeOffsetRate])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const crossFadeEndRateRow = useMemo(() => {
|
const crossFadeEndRateRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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">Cross Fade End Rate</div>
|
<div className="body-item-title left-padding-1">Cross Fade End Rate</div>
|
||||||
<div className="body-input-container">
|
<div className="body-input-container">
|
||||||
<input type="number" min={0} max={1} step={0.1} value={crossFadeEndRate} onChange={(e) => { setCrossFadeEndRate(Number(e.target.value)) }} />
|
<input type="number" min={0} max={1} step={0.1} value={props.clientState.settingState.crossFadeEndRate} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
crossFadeEndRate: Number(e.target.value)
|
||||||
|
})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [crossFadeEndRate])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const convertSetting = useMemo(() => {
|
const convertSetting = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -115,12 +136,6 @@ export const useConvertSetting = (): SpeakerSettingState => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
convertSetting,
|
convertSetting,
|
||||||
bufferSize,
|
|
||||||
inputChunkNum,
|
|
||||||
convertChunkNum,
|
|
||||||
gpu,
|
|
||||||
crossFadeOffsetRate,
|
|
||||||
crossFadeEndRate,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,47 @@
|
|||||||
import { VoiceChangerMode } from "@dannadori/voice-changer-client-js"
|
import { VoiceChangerMode } from "@dannadori/voice-changer-client-js"
|
||||||
import React, { useMemo, useState } from "react"
|
import React, { useMemo, useState } from "react"
|
||||||
|
import { ClientState } from "./hooks/useClient"
|
||||||
|
|
||||||
|
|
||||||
|
export type UseAdvancedSettingProps = {
|
||||||
|
clientState: ClientState
|
||||||
|
}
|
||||||
|
|
||||||
export type AdvancedSettingState = {
|
export type AdvancedSettingState = {
|
||||||
advancedSetting: JSX.Element;
|
advancedSetting: JSX.Element;
|
||||||
vfForceDisabled: boolean;
|
|
||||||
voiceChangerMode: VoiceChangerMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useAdvancedSetting = (props: UseAdvancedSettingProps): AdvancedSettingState => {
|
||||||
export const useAdvancedSetting = (): AdvancedSettingState => {
|
|
||||||
|
|
||||||
const [vfForceDisabled, setVfForceDisabled] = useState<boolean>(false)
|
|
||||||
const [voiceChangerMode, setVoiceChangerMode] = useState<VoiceChangerMode>("realtime")
|
|
||||||
|
|
||||||
const vfForceDisableRow = useMemo(() => {
|
const vfForceDisableRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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 ">VF Disabled</div>
|
<div className="body-item-title left-padding-1 ">VF Disabled</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox" checked={vfForceDisabled} onChange={(e) => setVfForceDisabled(e.target.checked)} />
|
<input type="checkbox" checked={props.clientState.settingState.vfForceDisabled} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
vfForceDisabled: e.target.checked
|
||||||
|
})
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [vfForceDisabled])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const voiceChangeModeRow = useMemo(() => {
|
const voiceChangeModeRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<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 ">Voice Change Mode</div>
|
<div className="body-item-title left-padding-1 ">Voice Change Mode</div>
|
||||||
<div className="body-select-container">
|
<div className="body-select-container">
|
||||||
<select className="body-select" value={voiceChangerMode} onChange={(e) => { setVoiceChangerMode(e.target.value as VoiceChangerMode) }}>
|
<select className="body-select" value={props.clientState.settingState.voiceChangerMode} onChange={(e) => {
|
||||||
|
props.clientState.setSettingState({
|
||||||
|
...props.clientState.settingState,
|
||||||
|
voiceChangerMode: e.target.value as VoiceChangerMode
|
||||||
|
})
|
||||||
|
}}>
|
||||||
{
|
{
|
||||||
Object.values(VoiceChangerMode).map(x => {
|
Object.values(VoiceChangerMode).map(x => {
|
||||||
return <option key={x} value={x}>{x}</option>
|
return <option key={x} value={x}>{x}</option>
|
||||||
@ -41,7 +51,7 @@ export const useAdvancedSetting = (): AdvancedSettingState => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}, [])
|
}, [props.clientState.settingState])
|
||||||
|
|
||||||
const advancedSetting = useMemo(() => {
|
const advancedSetting = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@ -59,8 +69,6 @@ export const useAdvancedSetting = (): AdvancedSettingState => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
advancedSetting,
|
advancedSetting,
|
||||||
vfForceDisabled,
|
|
||||||
voiceChangerMode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
import { ServerInfo } from "@dannadori/voice-changer-client-js"
|
|
||||||
import React, { useMemo, useState } from "react"
|
import React, { useMemo, useState } from "react"
|
||||||
|
import { ClientState } from "./hooks/useClient"
|
||||||
|
|
||||||
export type UseServerControlProps = {
|
export type UseServerControlProps = {
|
||||||
convertStart: () => Promise<void>
|
clientState: ClientState
|
||||||
convertStop: () => Promise<void>
|
|
||||||
getInfo: () => Promise<void>
|
|
||||||
volume: number,
|
|
||||||
bufferingTime: number,
|
|
||||||
responseTime: number
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useServerControl = (props: UseServerControlProps) => {
|
export const useServerControl = (props: UseServerControlProps) => {
|
||||||
@ -17,11 +11,11 @@ export const useServerControl = (props: UseServerControlProps) => {
|
|||||||
const startButtonRow = useMemo(() => {
|
const startButtonRow = useMemo(() => {
|
||||||
const onStartClicked = async () => {
|
const onStartClicked = async () => {
|
||||||
setIsStarted(true)
|
setIsStarted(true)
|
||||||
await props.convertStart()
|
await props.clientState.start()
|
||||||
}
|
}
|
||||||
const onStopClicked = async () => {
|
const onStopClicked = async () => {
|
||||||
setIsStarted(false)
|
setIsStarted(false)
|
||||||
await props.convertStop()
|
await props.clientState.stop()
|
||||||
}
|
}
|
||||||
const startClassName = isStarted ? "body-button-active" : "body-button-stanby"
|
const startClassName = isStarted ? "body-button-active" : "body-button-stanby"
|
||||||
const stopClassName = isStarted ? "body-button-stanby" : "body-button-active"
|
const stopClassName = isStarted ? "body-button-stanby" : "body-button-active"
|
||||||
@ -38,43 +32,43 @@ export const useServerControl = (props: UseServerControlProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
}, [isStarted, props.convertStart, props.convertStop])
|
}, [isStarted, props.clientState.start, props.clientState.stop])
|
||||||
|
|
||||||
const performanceRow = useMemo(() => {
|
const performanceRow = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="body-row split-3-1-1-1-4 left-padding-1 guided">
|
<div className="body-row split-3-1-1-1-4 left-padding-1 guided">
|
||||||
<div className="body-item-title left-padding-1">monitor:</div>
|
<div className="body-item-title left-padding-1">monitor:</div>
|
||||||
<div className="body-item-text">vol(rms):{props.volume.toFixed(4)}</div>
|
<div className="body-item-text">vol(rms):{props.clientState.volume.toFixed(4)}</div>
|
||||||
<div className="body-item-text">buf(ms):{props.bufferingTime}</div>
|
<div className="body-item-text">buf(ms):{props.clientState.bufferingTime}</div>
|
||||||
<div className="body-item-text">res(ms):{props.responseTime}</div>
|
<div className="body-item-text">res(ms):{props.clientState.responseTime}</div>
|
||||||
<div className="body-item-text"></div>
|
<div className="body-item-text"></div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}, [props.volume, props.bufferingTime, props.responseTime])
|
}, [props.clientState.volume, props.clientState.bufferingTime, props.clientState.responseTime])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const infoRow = useMemo(() => {
|
const infoRow = useMemo(() => {
|
||||||
const onReloadClicked = async () => {
|
const onReloadClicked = async () => {
|
||||||
const info = await props.getInfo()
|
const info = await props.clientState.getInfo()
|
||||||
console.log("info", info)
|
console.log("info", info)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="body-row split-3-1-1-1-4 left-padding-1 guided">
|
<div className="body-row split-3-1-1-1-4 left-padding-1 guided">
|
||||||
<div className="body-item-title left-padding-1">Info:</div>
|
<div className="body-item-title left-padding-1">Info:</div>
|
||||||
<div className="body-item-text">vol(rms):{props.volume.toFixed(4)}</div>
|
<div className="body-item-text">a</div>
|
||||||
<div className="body-item-text">buf(ms):{props.bufferingTime}</div>
|
<div className="body-item-text">b</div>
|
||||||
<div className="body-item-text">res(ms):{props.responseTime}</div>
|
<div className="body-item-text">c</div>
|
||||||
<div className="body-button-container">
|
<div className="body-button-container">
|
||||||
<div className="body-button" onClick={onReloadClicked}>reload</div>
|
<div className="body-button" onClick={onReloadClicked}>reload</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}, [props.getInfo])
|
}, [props.clientState.getInfo])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { BufferSize, createDummyMediaStream, Protocol, ServerSettingKey, VoiceChangerMode, VoiceChnagerClient } from "@dannadori/voice-changer-client-js"
|
import { BufferSize, createDummyMediaStream, DefaultVoiceChangerOptions, DefaultVoiceChangerRequestParamas, Framework, OnnxExecutionProvider, Protocol, SampleRate, ServerSettingKey, Speaker, VoiceChangerMode, VoiceChnagerClient } from "@dannadori/voice-changer-client-js"
|
||||||
import { useEffect, useMemo, useRef, useState } from "react"
|
import { useEffect, useMemo, useRef, useState } from "react"
|
||||||
|
|
||||||
export type UseClientProps = {
|
export type UseClientProps = {
|
||||||
@ -6,40 +6,91 @@ export type UseClientProps = {
|
|||||||
audioOutputElementId: string
|
audioOutputElementId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SettingState = {
|
||||||
|
// server setting
|
||||||
|
mmvcServerUrl: string
|
||||||
|
pyTorchModel: File | null
|
||||||
|
configFile: File | null
|
||||||
|
onnxModel: File | null
|
||||||
|
protocol: Protocol
|
||||||
|
framework: Framework
|
||||||
|
onnxExecutionProvider: OnnxExecutionProvider
|
||||||
|
|
||||||
|
// device setting
|
||||||
|
audioInput: string | MediaStream | null;
|
||||||
|
sampleRate: SampleRate;
|
||||||
|
|
||||||
|
// speaker setting
|
||||||
|
speakers: Speaker[]
|
||||||
|
editSpeakerTargetId: number
|
||||||
|
editSpeakerTargetName: string
|
||||||
|
srcId: number
|
||||||
|
dstId: number
|
||||||
|
|
||||||
|
// convert setting
|
||||||
|
bufferSize: BufferSize
|
||||||
|
inputChunkNum: number
|
||||||
|
convertChunkNum: number
|
||||||
|
gpu: number
|
||||||
|
crossFadeOffsetRate: number
|
||||||
|
crossFadeEndRate: number
|
||||||
|
|
||||||
|
// advanced setting
|
||||||
|
vfForceDisabled: boolean
|
||||||
|
voiceChangerMode: VoiceChangerMode
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const InitialSettingState: SettingState = {
|
||||||
|
mmvcServerUrl: DefaultVoiceChangerOptions.mmvcServerUrl,
|
||||||
|
pyTorchModel: null,
|
||||||
|
configFile: null,
|
||||||
|
onnxModel: null,
|
||||||
|
protocol: DefaultVoiceChangerOptions.protocol,
|
||||||
|
framework: DefaultVoiceChangerOptions.framework,
|
||||||
|
onnxExecutionProvider: DefaultVoiceChangerOptions.onnxExecutionProvider,
|
||||||
|
|
||||||
|
audioInput: "none",
|
||||||
|
sampleRate: DefaultVoiceChangerOptions.sampleRate,
|
||||||
|
|
||||||
|
speakers: DefaultVoiceChangerOptions.speakers,
|
||||||
|
editSpeakerTargetId: 0,
|
||||||
|
editSpeakerTargetName: "",
|
||||||
|
srcId: DefaultVoiceChangerRequestParamas.srcId,
|
||||||
|
dstId: DefaultVoiceChangerRequestParamas.dstId,
|
||||||
|
|
||||||
|
bufferSize: DefaultVoiceChangerOptions.bufferSize,
|
||||||
|
inputChunkNum: DefaultVoiceChangerOptions.inputChunkNum,
|
||||||
|
convertChunkNum: DefaultVoiceChangerRequestParamas.convertChunkNum,
|
||||||
|
gpu: DefaultVoiceChangerRequestParamas.gpu,
|
||||||
|
crossFadeOffsetRate: DefaultVoiceChangerRequestParamas.crossFadeOffsetRate,
|
||||||
|
crossFadeEndRate: DefaultVoiceChangerRequestParamas.crossFadeEndRate,
|
||||||
|
vfForceDisabled: DefaultVoiceChangerOptions.forceVfDisable,
|
||||||
|
voiceChangerMode: DefaultVoiceChangerOptions.voiceChangerMode
|
||||||
|
}
|
||||||
|
|
||||||
export type ClientState = {
|
export type ClientState = {
|
||||||
clientInitialized: boolean
|
clientInitialized: boolean
|
||||||
bufferingTime: number;
|
bufferingTime: number;
|
||||||
responseTime: number;
|
responseTime: number;
|
||||||
volume: number;
|
volume: number;
|
||||||
|
uploadProgress: number;
|
||||||
|
isUploading: boolean
|
||||||
|
|
||||||
// Setting
|
// Setting
|
||||||
|
settingState: SettingState
|
||||||
|
setSettingState: (setting: SettingState) => void
|
||||||
|
|
||||||
|
|
||||||
// Client Setting
|
|
||||||
setServerUrl: (mmvcServerUrl: string) => Promise<void>
|
|
||||||
setProtocol: (protocol: Protocol) => Promise<void>
|
|
||||||
setInputChunkNum: (num: number) => Promise<void>
|
|
||||||
setVoiceChangerMode: (val: VoiceChangerMode) => Promise<void>
|
|
||||||
|
|
||||||
// Client Control
|
// Client Control
|
||||||
start: (mmvcServerUrl: string, protocol: Protocol) => Promise<void>;
|
loadModel: () => Promise<void>
|
||||||
|
start: () => Promise<void>;
|
||||||
stop: () => Promise<void>;
|
stop: () => Promise<void>;
|
||||||
|
|
||||||
// Device Setting
|
|
||||||
changeInput: (audioInput: MediaStream | string, bufferSize: BufferSize, vfForceDisable: boolean) => Promise<void>
|
|
||||||
|
|
||||||
// Server Setting
|
|
||||||
uploadFile: (file: File, onprogress: (progress: number, end: boolean) => void) => Promise<void>
|
|
||||||
loadModel: (configFile: File, pyTorchModelFile: File | null, onnxModelFile: File | null) => Promise<void>
|
|
||||||
updateSettings: (key: ServerSettingKey, val: string | number) => Promise<any>
|
|
||||||
|
|
||||||
// Information
|
|
||||||
getInfo: () => Promise<void>
|
getInfo: () => Promise<void>
|
||||||
}
|
}
|
||||||
export const useClient = (props: UseClientProps): ClientState => {
|
export const useClient = (props: UseClientProps): ClientState => {
|
||||||
|
|
||||||
|
// (1) クライアント初期化
|
||||||
const voiceChangerClientRef = useRef<VoiceChnagerClient | null>(null)
|
const voiceChangerClientRef = useRef<VoiceChnagerClient | null>(null)
|
||||||
const [clientInitialized, setClientInitialized] = useState<boolean>(false)
|
const [clientInitialized, setClientInitialized] = useState<boolean>(false)
|
||||||
const initializedResolveRef = useRef<(value: void | PromiseLike<void>) => void>()
|
const initializedResolveRef = useRef<(value: void | PromiseLike<void>) => void>()
|
||||||
@ -88,73 +139,45 @@ export const useClient = (props: UseClientProps): ClientState => {
|
|||||||
initialized()
|
initialized()
|
||||||
}, [props.audioContext])
|
}, [props.audioContext])
|
||||||
|
|
||||||
// Client Setting
|
|
||||||
const setServerUrl = useMemo(() => {
|
|
||||||
return async (mmvcServerUrl: string) => {
|
// (2) 設定
|
||||||
|
const [settingState, setSettingState] = useState<SettingState>(InitialSettingState)
|
||||||
|
const [uploadProgress, setUploadProgress] = useState<number>(0)
|
||||||
|
const [isUploading, setIsUploading] = useState<boolean>(false)
|
||||||
|
|
||||||
|
// (2-1) server setting
|
||||||
|
// (a) サーバURL設定
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
await initializedPromise
|
await initializedPromise
|
||||||
voiceChangerClientRef.current!.setServerUrl(mmvcServerUrl, true)
|
voiceChangerClientRef.current!.setServerUrl(settingState.mmvcServerUrl, true)
|
||||||
voiceChangerClientRef.current!.stop()
|
voiceChangerClientRef.current!.stop()
|
||||||
}
|
})()
|
||||||
}, [])
|
}, [settingState.mmvcServerUrl])
|
||||||
|
// (b) プロトコル設定
|
||||||
const setProtocol = useMemo(() => {
|
useEffect(() => {
|
||||||
return async (protocol: Protocol) => {
|
(async () => {
|
||||||
await initializedPromise
|
await initializedPromise
|
||||||
voiceChangerClientRef.current!.setProtocol(protocol)
|
voiceChangerClientRef.current!.setProtocol(settingState.protocol)
|
||||||
}
|
})()
|
||||||
}, [])
|
}, [settingState.protocol])
|
||||||
|
// (c) フレームワーク設定
|
||||||
const setInputChunkNum = useMemo(() => {
|
useEffect(() => {
|
||||||
return async (num: number) => {
|
(async () => {
|
||||||
await initializedPromise
|
await initializedPromise
|
||||||
voiceChangerClientRef.current!.setInputChunkNum(num)
|
const info = await voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.framework, "" + settingState.framework)
|
||||||
}
|
})()
|
||||||
}, [])
|
}, [settingState.framework])
|
||||||
|
// (d) OnnxExecutionProvider設定
|
||||||
const setVoiceChangerMode = useMemo(() => {
|
useEffect(() => {
|
||||||
return async (val: VoiceChangerMode) => {
|
(async () => {
|
||||||
await initializedPromise
|
await initializedPromise
|
||||||
voiceChangerClientRef.current!.setVoiceChangerMode(val)
|
const info = voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.onnxExecutionProvider, settingState.onnxExecutionProvider)
|
||||||
voiceChangerClientRef.current!.stop()
|
})()
|
||||||
}
|
}, [settingState.onnxExecutionProvider])
|
||||||
}, [])
|
|
||||||
|
|
||||||
|
// (e) モデルアップロード
|
||||||
// Client Control
|
|
||||||
const start = useMemo(() => {
|
|
||||||
return async (mmvcServerUrl: string) => {
|
|
||||||
await initializedPromise
|
|
||||||
voiceChangerClientRef.current!.setServerUrl(mmvcServerUrl, true)
|
|
||||||
voiceChangerClientRef.current!.start()
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
const stop = useMemo(() => {
|
|
||||||
return async () => {
|
|
||||||
await initializedPromise
|
|
||||||
voiceChangerClientRef.current!.stop()
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
|
|
||||||
// Device Setting
|
|
||||||
const changeInput = useMemo(() => {
|
|
||||||
return async (audioInput: MediaStream | string, bufferSize: BufferSize, vfForceDisable: boolean) => {
|
|
||||||
await initializedPromise
|
|
||||||
if (!audioInput || audioInput == "none") {
|
|
||||||
console.log("[useClient] setup!(1)", audioInput)
|
|
||||||
const ms = createDummyMediaStream(props.audioContext!)
|
|
||||||
await voiceChangerClientRef.current!.setup(ms, bufferSize, vfForceDisable)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("[useClient] setup!(2)", audioInput)
|
|
||||||
await voiceChangerClientRef.current!.setup(audioInput, bufferSize, vfForceDisable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [props.audioContext])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Server Setting
|
|
||||||
const uploadFile = useMemo(() => {
|
const uploadFile = useMemo(() => {
|
||||||
return async (file: File, onprogress: (progress: number, end: boolean) => void) => {
|
return async (file: File, onprogress: (progress: number, end: boolean) => void) => {
|
||||||
await initializedPromise
|
await initializedPromise
|
||||||
@ -163,23 +186,146 @@ export const useClient = (props: UseClientProps): ClientState => {
|
|||||||
console.log("uploaded", num, res)
|
console.log("uploaded", num, res)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const loadModel = useMemo(() => {
|
const loadModel = useMemo(() => {
|
||||||
return async (configFile: File, pyTorchModelFile: File | null, onnxModelFile: File | null) => {
|
return async () => {
|
||||||
|
if (!settingState.pyTorchModel && !settingState.onnxModel) {
|
||||||
|
alert("PyTorchモデルとONNXモデルのどちらか一つ以上指定する必要があります。")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!settingState.configFile) {
|
||||||
|
alert("Configファイルを指定する必要があります。")
|
||||||
|
return
|
||||||
|
}
|
||||||
await initializedPromise
|
await initializedPromise
|
||||||
await voiceChangerClientRef.current!.loadModel(configFile, pyTorchModelFile, onnxModelFile)
|
setUploadProgress(0)
|
||||||
console.log("loaded model")
|
setIsUploading(true)
|
||||||
|
const models = [settingState.pyTorchModel, settingState.onnxModel].filter(x => { return x != null }) as File[]
|
||||||
|
for (let i = 0; i < models.length; i++) {
|
||||||
|
const progRate = 1 / models.length
|
||||||
|
const progOffset = 100 * i * progRate
|
||||||
|
await uploadFile(models[i], (progress: number, end: boolean) => {
|
||||||
|
// console.log(progress * progRate + progOffset, end, progRate,)
|
||||||
|
setUploadProgress(progress * progRate + progOffset)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await uploadFile(settingState.configFile, (progress: number, end: boolean) => {
|
||||||
|
console.log(progress, end)
|
||||||
|
})
|
||||||
|
|
||||||
|
const serverInfo = await voiceChangerClientRef.current!.loadModel(settingState.configFile, settingState.pyTorchModel, settingState.onnxModel)
|
||||||
|
console.log(serverInfo)
|
||||||
|
setUploadProgress(0)
|
||||||
|
setIsUploading(false)
|
||||||
|
}
|
||||||
|
}, [settingState.pyTorchModel, settingState.onnxModel, settingState.configFile])
|
||||||
|
|
||||||
|
// (2-2) device setting
|
||||||
|
// (a) インプット設定。audio nodes の設定の都合上、バッファサイズの変更も併せて反映させる。
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
if (!settingState.audioInput || settingState.audioInput == "none") {
|
||||||
|
console.log("[useClient] setup!(1)", settingState.audioInput)
|
||||||
|
const ms = createDummyMediaStream(props.audioContext!)
|
||||||
|
await voiceChangerClientRef.current!.setup(ms, settingState.bufferSize, settingState.vfForceDisabled)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("[useClient] setup!(2)", settingState.audioInput)
|
||||||
|
await voiceChangerClientRef.current!.setup(settingState.audioInput, settingState.bufferSize, settingState.vfForceDisabled)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [settingState.audioInput, settingState.bufferSize, settingState.vfForceDisabled])
|
||||||
|
|
||||||
|
|
||||||
|
// (2-3) speaker setting
|
||||||
|
// (a) srcId設定。
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
const info = await voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.srcId, "" + settingState.srcId)
|
||||||
|
})()
|
||||||
|
}, [settingState.srcId])
|
||||||
|
|
||||||
|
// (b) dstId設定。
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
const info = await voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.dstId, "" + settingState.dstId)
|
||||||
|
})()
|
||||||
|
}, [settingState.dstId])
|
||||||
|
|
||||||
|
|
||||||
|
// (2-4) convert setting
|
||||||
|
// (a) input chunk num設定
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
voiceChangerClientRef.current!.setInputChunkNum(settingState.inputChunkNum)
|
||||||
|
})()
|
||||||
|
}, [settingState.inputChunkNum])
|
||||||
|
|
||||||
|
// (b) input chunk num設定
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
const info = await voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.convertChunkNum, "" + settingState.convertChunkNum)
|
||||||
|
})()
|
||||||
|
}, [settingState.convertChunkNum])
|
||||||
|
|
||||||
|
// (c) gpu設定
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
const info = await voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.gpu, "" + settingState.gpu)
|
||||||
|
})()
|
||||||
|
}, [settingState.gpu])
|
||||||
|
|
||||||
|
// (d) crossfade設定1
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
const info = await voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.crossFadeOffsetRate, "" + settingState.crossFadeOffsetRate)
|
||||||
|
})()
|
||||||
|
}, [settingState.crossFadeOffsetRate])
|
||||||
|
|
||||||
|
// (e) crossfade設定2
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
const info = await voiceChangerClientRef.current!.updateServerSettings(ServerSettingKey.crossFadeEndRate, "" + settingState.crossFadeEndRate)
|
||||||
|
})()
|
||||||
|
}, [settingState.crossFadeEndRate])
|
||||||
|
|
||||||
|
// (2-5) advanced setting
|
||||||
|
//// VFDisableはinput設定で合わせて設定。
|
||||||
|
// (a) voice changer mode
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await initializedPromise
|
||||||
|
voiceChangerClientRef.current!.setVoiceChangerMode(settingState.voiceChangerMode)
|
||||||
|
voiceChangerClientRef.current!.stop()
|
||||||
|
})()
|
||||||
|
}, [settingState.voiceChangerMode])
|
||||||
|
|
||||||
|
// (2-6) server control
|
||||||
|
// (1) start
|
||||||
|
const start = useMemo(() => {
|
||||||
|
return async () => {
|
||||||
|
await initializedPromise
|
||||||
|
voiceChangerClientRef.current!.setServerUrl(settingState.mmvcServerUrl, true)
|
||||||
|
voiceChangerClientRef.current!.start()
|
||||||
|
}
|
||||||
|
}, [settingState.mmvcServerUrl])
|
||||||
|
// (2) stop
|
||||||
|
const stop = useMemo(() => {
|
||||||
|
return async () => {
|
||||||
|
await initializedPromise
|
||||||
|
voiceChangerClientRef.current!.stop()
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const updateSettings = useMemo(() => {
|
// (3) get info
|
||||||
return async (key: ServerSettingKey, val: string | number) => {
|
|
||||||
await initializedPromise
|
|
||||||
return await voiceChangerClientRef.current!.updateServerSettings(key, "" + val)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// Information
|
|
||||||
const getInfo = useMemo(() => {
|
const getInfo = useMemo(() => {
|
||||||
return async () => {
|
return async () => {
|
||||||
await initializedPromise
|
await initializedPromise
|
||||||
@ -195,21 +341,14 @@ export const useClient = (props: UseClientProps): ClientState => {
|
|||||||
bufferingTime,
|
bufferingTime,
|
||||||
responseTime,
|
responseTime,
|
||||||
volume,
|
volume,
|
||||||
|
uploadProgress,
|
||||||
|
isUploading,
|
||||||
|
|
||||||
setServerUrl,
|
settingState,
|
||||||
setProtocol,
|
setSettingState,
|
||||||
setInputChunkNum,
|
loadModel,
|
||||||
setVoiceChangerMode,
|
|
||||||
|
|
||||||
start,
|
start,
|
||||||
stop,
|
stop,
|
||||||
|
|
||||||
changeInput,
|
|
||||||
|
|
||||||
uploadFile,
|
|
||||||
loadModel,
|
|
||||||
updateSettings,
|
|
||||||
|
|
||||||
getInfo,
|
getInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,8 +26,8 @@ export type VoiceChangerOptions = {
|
|||||||
speakers: Speaker[],
|
speakers: Speaker[],
|
||||||
forceVfDisable: boolean,
|
forceVfDisable: boolean,
|
||||||
voiceChangerMode: VoiceChangerMode,
|
voiceChangerMode: VoiceChangerMode,
|
||||||
OnnxExecutionProvider: OnnxExecutionProvider,
|
onnxExecutionProvider: OnnxExecutionProvider,
|
||||||
Framework: Framework
|
framework: Framework
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -141,8 +141,8 @@ export const DefaultVoiceChangerOptions: VoiceChangerOptions = {
|
|||||||
],
|
],
|
||||||
forceVfDisable: false,
|
forceVfDisable: false,
|
||||||
voiceChangerMode: "realtime",
|
voiceChangerMode: "realtime",
|
||||||
Framework: "PyTorch",
|
framework: "PyTorch",
|
||||||
OnnxExecutionProvider: "CPUExecutionProvider"
|
onnxExecutionProvider: "CPUExecutionProvider"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,6 +42,8 @@ class VoiceChanger():
|
|||||||
self.unpackedData_length=0
|
self.unpackedData_length=0
|
||||||
self.net_g = None
|
self.net_g = None
|
||||||
self.onnx_session = None
|
self.onnx_session = None
|
||||||
|
self.currentCrossFadeOffsetRate=0
|
||||||
|
self.currentCrossFadeEndRate=0
|
||||||
# 共通で使用する情報を収集
|
# 共通で使用する情報を収集
|
||||||
self.hps = utils.get_hparams_from_file(config)
|
self.hps = utils.get_hparams_from_file(config)
|
||||||
self.gpu_num = torch.cuda.device_count()
|
self.gpu_num = torch.cuda.device_count()
|
||||||
@ -109,7 +111,7 @@ class VoiceChanger():
|
|||||||
setattr(self.settings, key, int(val))
|
setattr(self.settings, key, int(val))
|
||||||
if key == "gpu" and val >= 0 and val < self.gpu_num and self.onnx_session != None:
|
if key == "gpu" and val >= 0 and val < self.gpu_num and self.onnx_session != None:
|
||||||
providers = self.onnx_session.get_providers()
|
providers = self.onnx_session.get_providers()
|
||||||
print("Providers::::", providers)
|
print("Providers:", providers)
|
||||||
if "CUDAExecutionProvider" in providers:
|
if "CUDAExecutionProvider" in providers:
|
||||||
provider_options=[{'device_id': self.settings.gpu}]
|
provider_options=[{'device_id': self.settings.gpu}]
|
||||||
self.onnx_session.set_providers(providers=["CUDAExecutionProvider"], provider_options=provider_options)
|
self.onnx_session.set_providers(providers=["CUDAExecutionProvider"], provider_options=provider_options)
|
||||||
@ -121,14 +123,18 @@ class VoiceChanger():
|
|||||||
setattr(self.settings, key, str(val))
|
setattr(self.settings, key, str(val))
|
||||||
else:
|
else:
|
||||||
print(f"{key} is not mutalbe variable!")
|
print(f"{key} is not mutalbe variable!")
|
||||||
|
|
||||||
return self.get_info()
|
return self.get_info()
|
||||||
|
|
||||||
|
self.currentCrossFadeOffsetRate=0
|
||||||
|
self.currentCrossFadeEndRate=0
|
||||||
|
|
||||||
def _generate_strength(self, unpackedData):
|
def _generate_strength(self, unpackedData):
|
||||||
|
|
||||||
if self.unpackedData_length != unpackedData.shape[0]:
|
if self.unpackedData_length != unpackedData.shape[0] or self.currentCrossFadeOffsetRate != self.settings.crossFadeOffsetRate or self.currentCrossFadeEndRate != self.settings.crossFadeEndRate :
|
||||||
self.unpackedData_length = unpackedData.shape[0]
|
self.unpackedData_length = unpackedData.shape[0]
|
||||||
|
self.currentCrossFadeOffsetRate = self.settings.crossFadeOffsetRate
|
||||||
|
self.currentCrossFadeEndRate = self.settings.crossFadeEndRate
|
||||||
cf_offset = int(unpackedData.shape[0] * self.settings.crossFadeOffsetRate)
|
cf_offset = int(unpackedData.shape[0] * self.settings.crossFadeOffsetRate)
|
||||||
cf_end = int(unpackedData.shape[0] * self.settings.crossFadeEndRate)
|
cf_end = int(unpackedData.shape[0] * self.settings.crossFadeEndRate)
|
||||||
cf_range = cf_end - cf_offset
|
cf_range = cf_end - cf_offset
|
||||||
|
Loading…
x
Reference in New Issue
Block a user