voice-changer/client/lib/src/hooks/useServerSetting.ts

440 lines
19 KiB
TypeScript
Raw Normal View History

2023-01-12 18:06:15 +09:00
import { useState, useMemo, useRef, useEffect } from "react"
2023-02-18 20:53:15 +09:00
import { VoiceChangerServerSetting, ServerInfo, Framework, OnnxExecutionProvider, DefaultVoiceChangerServerSetting, ServerSettingKey, INDEXEDDB_KEY_SERVER, INDEXEDDB_KEY_MODEL_DATA, ServerAudioDevices, InputSampleRate } from "../const"
2023-01-12 23:01:45 +09:00
import { VoiceChangerClient } from "../VoiceChangerClient"
2023-01-29 09:42:45 +09:00
import { useIndexedDB } from "./useIndexedDB"
2023-01-12 16:38:45 +09:00
2023-01-29 14:41:44 +09:00
// export type FileUploadSetting = {
// pyTorchModel: File | null
// configFile: File | null
// onnxModel: File | null
// }
type ModelData = {
2023-01-29 15:25:44 +09:00
file?: File
data?: ArrayBuffer
filename?: string
2023-01-29 14:41:44 +09:00
}
2023-01-12 16:38:45 +09:00
export type FileUploadSetting = {
2023-01-29 14:41:44 +09:00
pyTorchModel: ModelData | null
onnxModel: ModelData | null
configFile: ModelData | null
2023-01-12 16:38:45 +09:00
}
2023-01-29 14:41:44 +09:00
2023-01-12 16:38:45 +09:00
const InitialFileUploadSetting: FileUploadSetting = {
pyTorchModel: null,
configFile: null,
onnxModel: null,
}
2023-01-29 14:41:44 +09:00
2023-01-12 16:38:45 +09:00
export type UseServerSettingProps = {
voiceChangerClient: VoiceChangerClient | null
}
export type ServerSettingState = {
setting: VoiceChangerServerSetting;
2023-01-29 09:42:45 +09:00
clearSetting: () => Promise<void>
2023-01-12 16:38:45 +09:00
serverInfo: ServerInfo | undefined;
fileUploadSetting: FileUploadSetting
setFramework: (framework: Framework) => Promise<boolean>;
setOnnxExecutionProvider: (provider: OnnxExecutionProvider) => Promise<boolean>;
setSrcId: (num: number) => Promise<boolean>;
setDstId: (num: number) => Promise<boolean>;
setConvertChunkNum: (num: number) => Promise<boolean>;
2023-01-12 21:42:02 +09:00
setMinConvertSize: (num: number) => Promise<boolean>
2023-01-12 16:38:45 +09:00
setGpu: (num: number) => Promise<boolean>;
setCrossFadeOffsetRate: (num: number) => Promise<boolean>;
setCrossFadeEndRate: (num: number) => Promise<boolean>;
setCrossFadeOverlapRate: (num: number) => Promise<boolean>;
setCrossFadeOverlapSize: (num: number) => Promise<boolean>;
2023-02-11 00:59:44 +09:00
setF0Factor: (num: number) => Promise<boolean>;
2023-02-15 05:02:51 +09:00
setF0Detector: (val: string) => Promise<boolean>;
setRecordIO: (num: number) => Promise<boolean>;
2023-02-18 04:15:34 +09:00
setServerMicrophone: (index: number) => Promise<boolean | undefined>
2023-02-18 20:53:15 +09:00
setInputSampleRate: (num: InputSampleRate) => Promise<boolean>
2023-01-12 16:38:45 +09:00
reloadServerInfo: () => Promise<void>;
setFileUploadSetting: (val: FileUploadSetting) => void
loadModel: () => Promise<void>
2023-02-18 04:15:34 +09:00
getServerDevices: () => Promise<ServerAudioDevices>
2023-01-12 16:38:45 +09:00
uploadProgress: number
isUploading: boolean
}
export const useServerSetting = (props: UseServerSettingProps): ServerSettingState => {
const settingRef = useRef<VoiceChangerServerSetting>(DefaultVoiceChangerServerSetting)
const [setting, _setSetting] = useState<VoiceChangerServerSetting>(settingRef.current)
const [serverInfo, _setServerInfo] = useState<ServerInfo>()
const [fileUploadSetting, setFileUploadSetting] = useState<FileUploadSetting>(InitialFileUploadSetting)
2023-01-29 09:42:45 +09:00
const { setItem, getItem, removeItem } = useIndexedDB()
// DBから設定取得キャッシュによる初期化
2023-01-29 09:42:45 +09:00
useEffect(() => {
const loadCache = async () => {
const setting = await getItem(INDEXEDDB_KEY_SERVER)
if (!setting) {
} else {
settingRef.current = setting as VoiceChangerServerSetting
}
_setSetting({ ...settingRef.current })
2023-01-29 15:25:44 +09:00
const fileuploadSetting = await getItem(INDEXEDDB_KEY_MODEL_DATA)
if (!fileuploadSetting) {
} else {
setFileUploadSetting(fileuploadSetting as FileUploadSetting)
}
2023-01-29 09:42:45 +09:00
}
loadCache()
}, [])
// クライアントへ設定反映 初期化, 設定変更
2023-01-29 09:42:45 +09:00
useEffect(() => {
if (!props.voiceChangerClient) return
2023-01-29 11:14:52 +09:00
props.voiceChangerClient.updateServerSettings(ServerSettingKey.framework, setting.framework)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.onnxExecutionProvider, setting.onnxExecutionProvider)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.srcId, "" + setting.srcId)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.dstId, "" + setting.dstId)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.convertChunkNum, "" + setting.convertChunkNum)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.minConvertSize, "" + setting.minConvertSize)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.gpu, "" + setting.gpu)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.crossFadeOffsetRate, "" + setting.crossFadeOffsetRate)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.crossFadeEndRate, "" + setting.crossFadeEndRate)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.crossFadeOverlapRate, "" + setting.crossFadeOverlapRate)
2023-02-11 00:59:44 +09:00
props.voiceChangerClient.updateServerSettings(ServerSettingKey.f0Factor, "" + setting.f0Factor)
2023-02-15 05:02:51 +09:00
props.voiceChangerClient.updateServerSettings(ServerSettingKey.f0Detector, "" + setting.f0Detector)
props.voiceChangerClient.updateServerSettings(ServerSettingKey.recordIO, "" + setting.recordIO)
2023-01-29 11:14:52 +09:00
// setting["convertChunkNum"] = 1
// const a = "convertChunkNum"
// setting[a] = ""
}, [props.voiceChangerClient, setting])
2023-01-12 16:38:45 +09:00
//////////////
// 設定
/////////////
//// サーバに設定後、反映された情報と照合して値が一致していることを確認。一致していない場合はalert
const _set_and_store = async (key: ServerSettingKey, newVal: string) => {
if (!props.voiceChangerClient) return false
const res = await props.voiceChangerClient.updateServerSettings(key, "" + newVal)
_setServerInfo(res)
if (newVal == res[key]) {
2023-01-29 09:42:45 +09:00
const newSetting: VoiceChangerServerSetting = {
2023-01-12 16:38:45 +09:00
...settingRef.current,
convertChunkNum: res.convertChunkNum,
2023-01-12 21:42:02 +09:00
minConvertSize: res.minConvertSize,
2023-01-12 16:38:45 +09:00
srcId: res.srcId,
dstId: res.dstId,
gpu: res.gpu,
crossFadeOffsetRate: res.crossFadeOffsetRate,
crossFadeEndRate: res.crossFadeEndRate,
crossFadeOverlapRate: res.crossFadeOverlapRate,
crossFadeOverlapSize: res.crossFadeOverlapSize,
2023-01-12 16:38:45 +09:00
framework: res.framework,
2023-02-11 00:59:44 +09:00
onnxExecutionProvider: (!!res.onnxExecutionProvider && res.onnxExecutionProvider.length > 0) ? res.onnxExecutionProvider[0] as OnnxExecutionProvider : DefaultVoiceChangerServerSetting.onnxExecutionProvider,
2023-02-15 05:02:51 +09:00
f0Factor: res.f0Factor,
f0Detector: res.f0Detector,
recordIO: res.recordIO
2023-01-29 09:42:45 +09:00
}
_setSetting(newSetting)
setItem(INDEXEDDB_KEY_SERVER, newSetting)
2023-01-12 16:38:45 +09:00
return true
} else {
2023-01-16 07:26:24 +09:00
alert(`[ServerSetting] 設定が反映されていません([key:${key}, new:${newVal}, res:${res[key]}])。モデルの切り替えの場合、処理が非同期で行われるため反映されていないように見える場合があります。サーバコントロールのリロードボタンを押すとGUIに反映されるます。`)
2023-01-12 16:38:45 +09:00
return false
}
}
// // New Trial
// // 設定 _setSettingがトリガでuseEffectが呼ばれて、workletに設定が飛ぶ
// const setSetting = useMemo(() => {
// return (setting: ) => {
// if (!props.voiceChangerClient) return false
// const res = await props.voiceChangerClient.updateServerSettings(key, "" + newVal)
// _setServerInfo(res)
// if (newVal == res[key]) {
// const newSetting: VoiceChangerServerSetting = {
// ...settingRef.current,
// convertChunkNum: res.convertChunkNum,
// minConvertSize: res.minConvertSize,
// srcId: res.srcId,
// dstId: res.dstId,
// gpu: res.gpu,
// crossFadeOffsetRate: res.crossFadeOffsetRate,
// crossFadeEndRate: res.crossFadeEndRate,
// crossFadeOverlapRate: res.crossFadeOverlapRate,
// crossFadeOverlapSize: res.crossFadeOverlapSize,
// framework: res.framework,
// onnxExecutionProvider: (!!res.onnxExecutionProvider && res.onnxExecutionProvider.length > 0) ? res.onnxExecutionProvider[0] as OnnxExecutionProvider : DefaultVoiceChangerServerSetting.onnxExecutionProvider,
// f0Factor: res.f0Factor,
// f0Detector: res.f0Detector,
// recordIO: res.recordIO
// }
// _setSetting(newSetting)
// setItem(INDEXEDDB_KEY_SERVER, newSetting)
// return true
// } else {
// alert(`[ServerSetting] 設定が反映されていません([key:${key}, new:${newVal}, res:${res[key]}])。モデルの切り替えの場合、処理が非同期で行われるため反映されていないように見える場合があります。サーバコントロールのリロードボタンを押すとGUIに反映されるます。`)
// return false
// }
// }
// }, [props.voiceChangerClient])
2023-01-12 16:38:45 +09:00
const setFramework = useMemo(() => {
return async (framework: Framework) => {
return await _set_and_store(ServerSettingKey.framework, "" + framework)
}
}, [props.voiceChangerClient])
const setOnnxExecutionProvider = useMemo(() => {
return async (provider: OnnxExecutionProvider) => {
return await _set_and_store(ServerSettingKey.onnxExecutionProvider, "" + provider)
}
}, [props.voiceChangerClient])
const setSrcId = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.srcId, "" + num)
}
}, [props.voiceChangerClient])
const setDstId = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.dstId, "" + num)
}
}, [props.voiceChangerClient])
const setConvertChunkNum = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.convertChunkNum, "" + num)
}
}, [props.voiceChangerClient])
2023-01-12 21:42:02 +09:00
const setMinConvertSize = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.minConvertSize, "" + num)
}
}, [props.voiceChangerClient])
2023-01-12 16:38:45 +09:00
const setGpu = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.gpu, "" + num)
}
}, [props.voiceChangerClient])
const setCrossFadeOffsetRate = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.crossFadeOffsetRate, "" + num)
}
}, [props.voiceChangerClient])
const setCrossFadeEndRate = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.crossFadeEndRate, "" + num)
}
}, [props.voiceChangerClient])
const setCrossFadeOverlapRate = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.crossFadeOverlapRate, "" + num)
}
}, [props.voiceChangerClient])
const setCrossFadeOverlapSize = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.crossFadeOverlapSize, "" + num)
}
}, [props.voiceChangerClient])
2023-01-12 16:38:45 +09:00
2023-02-11 00:59:44 +09:00
const setF0Factor = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.f0Factor, "" + num)
}
}, [props.voiceChangerClient])
2023-02-15 05:02:51 +09:00
const setF0Detector = useMemo(() => {
return async (val: string) => {
return await _set_and_store(ServerSettingKey.f0Detector, "" + val)
}
}, [props.voiceChangerClient])
const setRecordIO = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.recordIO, "" + num)
}
}, [props.voiceChangerClient])
2023-02-18 04:15:34 +09:00
const setServerMicrophone = useMemo(() => {
return async (index: number) => {
if (!props.voiceChangerClient) {
return
}
const sid = props.voiceChangerClient.getSocketId()
const serverMicProps = {
sid: sid,
deviceIndex: index
}
return await _set_and_store(ServerSettingKey.serverMicProps, JSON.stringify(serverMicProps))
}
}, [props.voiceChangerClient])
2023-02-18 20:53:15 +09:00
const setInputSampleRate = useMemo(() => {
return async (num: number) => {
return await _set_and_store(ServerSettingKey.inputSampleRate, "" + num)
}
}, [props.voiceChangerClient])
2023-01-12 16:38:45 +09:00
//////////////
// 操作
/////////////
const [uploadProgress, setUploadProgress] = useState<number>(0)
const [isUploading, setIsUploading] = useState<boolean>(false)
// (e) モデルアップロード
const _uploadFile = useMemo(() => {
2023-01-29 14:41:44 +09:00
return async (modelData: ModelData, onprogress: (progress: number, end: boolean) => void) => {
2023-01-12 16:38:45 +09:00
if (!props.voiceChangerClient) return
2023-01-29 15:25:44 +09:00
const num = await props.voiceChangerClient.uploadFile(modelData.data!, modelData.filename!, onprogress)
const res = await props.voiceChangerClient.concatUploadedFile(modelData.filename!, num)
2023-01-12 16:38:45 +09:00
console.log("uploaded", num, res)
}
}, [props.voiceChangerClient])
const loadModel = useMemo(() => {
return async () => {
if (!fileUploadSetting.pyTorchModel && !fileUploadSetting.onnxModel) {
alert("PyTorchモデルとONNXモデルのどちらか一つ以上指定する必要があります。")
return
}
if (!fileUploadSetting.configFile) {
alert("Configファイルを指定する必要があります。")
return
}
if (!props.voiceChangerClient) return
2023-01-29 14:41:44 +09:00
2023-01-12 16:38:45 +09:00
setUploadProgress(0)
setIsUploading(true)
2023-01-29 14:41:44 +09:00
2023-01-29 15:25:44 +09:00
// ファイルをメモリにロード
if (fileUploadSetting.onnxModel && !fileUploadSetting.onnxModel.data) {
fileUploadSetting.onnxModel.data = await fileUploadSetting.onnxModel.file!.arrayBuffer()
fileUploadSetting.onnxModel.filename = await fileUploadSetting.onnxModel.file!.name
}
if (fileUploadSetting.pyTorchModel && !fileUploadSetting.pyTorchModel.data) {
fileUploadSetting.pyTorchModel.data = await fileUploadSetting.pyTorchModel.file!.arrayBuffer()
fileUploadSetting.pyTorchModel.filename = await fileUploadSetting.pyTorchModel.file!.name
}
if (!fileUploadSetting.configFile.data) {
fileUploadSetting.configFile.data = await fileUploadSetting.configFile.file!.arrayBuffer()
fileUploadSetting.configFile.filename = await fileUploadSetting.configFile.file!.name
}
// ファイルをサーバにアップロード
2023-01-29 14:41:44 +09:00
const models = [fileUploadSetting.onnxModel, fileUploadSetting.pyTorchModel].filter(x => { return x != null }) as ModelData[]
2023-01-12 16:38:45 +09:00
for (let i = 0; i < models.length; i++) {
const progRate = 1 / models.length
const progOffset = 100 * i * progRate
2023-01-12 23:01:45 +09:00
await _uploadFile(models[i], (progress: number, _end: boolean) => {
2023-01-12 16:38:45 +09:00
// console.log(progress * progRate + progOffset, end, progRate,)
setUploadProgress(progress * progRate + progOffset)
})
}
await _uploadFile(fileUploadSetting.configFile, (progress: number, end: boolean) => {
console.log(progress, end)
})
2023-01-29 15:25:44 +09:00
const loadPromise = props.voiceChangerClient.loadModel(fileUploadSetting.configFile.filename!, fileUploadSetting.pyTorchModel?.filename || null, fileUploadSetting.onnxModel?.filename || null)
// サーバでロード中にキャッシュにセーブ
const saveData: FileUploadSetting = {
pyTorchModel: fileUploadSetting.pyTorchModel ? { data: fileUploadSetting.pyTorchModel.data, filename: fileUploadSetting.pyTorchModel.filename } : null,
onnxModel: fileUploadSetting.onnxModel ? { data: fileUploadSetting.onnxModel.data, filename: fileUploadSetting.onnxModel.filename } : null,
configFile: { data: fileUploadSetting.configFile.data, filename: fileUploadSetting.configFile.filename }
}
setItem(INDEXEDDB_KEY_MODEL_DATA, saveData)
await loadPromise
2023-01-12 16:38:45 +09:00
setUploadProgress(0)
setIsUploading(false)
2023-01-28 15:56:56 +09:00
reloadServerInfo()
2023-01-12 16:38:45 +09:00
}
}, [fileUploadSetting, props.voiceChangerClient])
const reloadServerInfo = useMemo(() => {
return async () => {
if (!props.voiceChangerClient) return
const res = await props.voiceChangerClient.getServerSettings()
_setServerInfo(res)
_setSetting({
...settingRef.current,
convertChunkNum: res.convertChunkNum,
srcId: res.srcId,
dstId: res.dstId,
gpu: res.gpu,
crossFadeOffsetRate: res.crossFadeOffsetRate,
crossFadeEndRate: res.crossFadeEndRate,
crossFadeOverlapRate: res.crossFadeOverlapRate,
framework: res.framework,
2023-02-11 00:59:44 +09:00
onnxExecutionProvider: (!!res.onnxExecutionProvider && res.onnxExecutionProvider.length > 0) ? res.onnxExecutionProvider[0] as OnnxExecutionProvider : DefaultVoiceChangerServerSetting.onnxExecutionProvider,
2023-02-15 05:02:51 +09:00
f0Factor: res.f0Factor,
f0Detector: res.f0Detector,
recordIO: res.recordIO
2023-01-12 16:38:45 +09:00
})
}
}, [props.voiceChangerClient])
2023-01-29 09:42:45 +09:00
const clearSetting = async () => {
await removeItem(INDEXEDDB_KEY_SERVER)
2023-01-29 15:25:44 +09:00
await removeItem(INDEXEDDB_KEY_MODEL_DATA)
2023-01-29 09:42:45 +09:00
}
2023-01-12 18:06:15 +09:00
2023-02-18 04:15:34 +09:00
const getServerDevices = async (): Promise<ServerAudioDevices> => {
if (!props.voiceChangerClient) {
return {
audio_input_devices: [],
audio_output_devices: []
}
}
const res = await props.voiceChangerClient.getServerDevices()
return res
}
2023-01-12 18:06:15 +09:00
2023-01-12 16:38:45 +09:00
return {
setting,
2023-01-29 09:42:45 +09:00
clearSetting,
2023-01-12 16:38:45 +09:00
serverInfo,
fileUploadSetting,
setFramework,
setOnnxExecutionProvider,
setSrcId,
setDstId,
setConvertChunkNum,
2023-01-12 21:42:02 +09:00
setMinConvertSize,
2023-01-12 16:38:45 +09:00
setGpu,
setCrossFadeOffsetRate,
setCrossFadeEndRate,
setCrossFadeOverlapRate,
setCrossFadeOverlapSize,
2023-02-11 00:59:44 +09:00
setF0Factor,
2023-02-15 05:02:51 +09:00
setF0Detector,
setRecordIO,
2023-02-18 04:15:34 +09:00
setServerMicrophone,
2023-02-18 20:53:15 +09:00
setInputSampleRate,
2023-01-12 16:38:45 +09:00
reloadServerInfo,
setFileUploadSetting,
loadModel,
2023-02-18 04:15:34 +09:00
getServerDevices,
2023-01-12 16:38:45 +09:00
uploadProgress,
isUploading,
}
}