diff --git a/client/demo/src/001_globalHooks/100_useWebInfo.ts b/client/demo/src/001_globalHooks/100_useWebInfo.ts index ff71d7c4..daddb70a 100644 --- a/client/demo/src/001_globalHooks/100_useWebInfo.ts +++ b/client/demo/src/001_globalHooks/100_useWebInfo.ts @@ -125,10 +125,10 @@ const f0ModelUrl: { [modelType in VoiceChangerType]: { [inputLength in InputLeng }; export const useWebInfo = (props: UseWebInfoProps): WebInfoStateAndMethod => { - const initVoiceChangerType: VoiceChangerType = "rvcv1"; + const initVoiceChangerType: VoiceChangerType = "rvcv2"; const initInputLength: InputLengthKey = "24000"; const initUseF0 = false; - const initSampleRate: ModelSampleRateStr = "40k"; + const initSampleRate: ModelSampleRateStr = "32k"; const progressCallback = (data: ProgreeeUpdateCallbcckInfo) => { if (data.progressUpdateType === ProgressUpdateType.loadPreprocessModel) { diff --git a/client/demo/src/components/demo/components2/101_CharacterArea.tsx b/client/demo/src/components/demo/components2/101_CharacterArea.tsx index 5519d5dc..bc21780a 100644 --- a/client/demo/src/components/demo/components2/101_CharacterArea.tsx +++ b/client/demo/src/components/demo/components2/101_CharacterArea.tsx @@ -142,21 +142,37 @@ export const CharacterArea = (_props: CharacterAreaProps) => { throw new Error("invalid webModelLoadingState"); } } else { - return ( -
-
-
- start -
-
- stop -
-
- passthru + if (webEdition) { + return ( +
+
+
+ start +
+
+ stop +
-
- ); + ); + } else { + return ( +
+
+
+ start +
+
+ stop +
+ +
+ passthru +
+
+
+ ); + } } }, [guiState.isConverting, start, stop, serverSetting.serverSetting, serverSetting.updateServerSettings, webInfoState.progressLoadPreprocess, webInfoState.progressLoadVCModel, webInfoState.progressWarmup, webInfoState.webModelLoadingState]); diff --git a/client/demo/src/components/demo/components2/102-3_DeviceArea.tsx b/client/demo/src/components/demo/components2/102-3_DeviceArea.tsx index 113072a1..59a654fd 100644 --- a/client/demo/src/components/demo/components2/102-3_DeviceArea.tsx +++ b/client/demo/src/components/demo/components2/102-3_DeviceArea.tsx @@ -4,6 +4,7 @@ import { fileSelectorAsDataURL, useIndexedDB } from "@dannadori/voice-changer-cl import { useGuiState } from "../001_GuiStateProvider"; import { AUDIO_ELEMENT_FOR_PLAY_MONITOR, AUDIO_ELEMENT_FOR_PLAY_RESULT, AUDIO_ELEMENT_FOR_TEST_CONVERTED, AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK, AUDIO_ELEMENT_FOR_TEST_ORIGINAL, INDEXEDDB_KEY_AUDIO_MONITR, INDEXEDDB_KEY_AUDIO_OUTPUT } from "../../../const"; import { isDesktopApp } from "../../../const"; +import { useAppRoot } from "../../../001_provider/001_AppRootProvider"; export type DeviceAreaProps = {}; @@ -19,8 +20,19 @@ export const DeviceArea = (_props: DeviceAreaProps) => { const { getItem, setItem } = useIndexedDB({ clientType: null }); const [outputRecordingStarted, setOutputRecordingStarted] = useState(false); + const { appGuiSettingState } = useAppRoot(); + const webEdition = appGuiSettingState.edition.indexOf("web") >= 0; + // (1) Audio Mode const deviceModeRow = useMemo(() => { + if (webEdition) { + return ( +
+
AUDIO:
+
+
+ ); + } const enableServerAudio = serverSetting.serverSetting.enableServerAudio; const clientChecked = enableServerAudio == 1 ? false : true; const serverChecked = enableServerAudio == 1 ? true : false; diff --git a/client/lib/worklet/src/voice-changer-worklet-processor.ts b/client/lib/worklet/src/voice-changer-worklet-processor.ts index 4a199db3..6f3b8be4 100644 --- a/client/lib/worklet/src/voice-changer-worklet-processor.ts +++ b/client/lib/worklet/src/voice-changer-worklet-processor.ts @@ -1,207 +1,191 @@ export const RequestType = { - voice: "voice", - config: "config", - start: "start", - stop: "stop", - trancateBuffer: "trancateBuffer", + voice: "voice", + config: "config", + start: "start", + stop: "stop", + trancateBuffer: "trancateBuffer", } as const; export type RequestType = (typeof RequestType)[keyof typeof RequestType]; export const ResponseType = { - volume: "volume", - inputData: "inputData", - start_ok: "start_ok", - stop_ok: "stop_ok", + volume: "volume", + inputData: "inputData", + start_ok: "start_ok", + stop_ok: "stop_ok", } as const; export type ResponseType = (typeof ResponseType)[keyof typeof ResponseType]; export type VoiceChangerWorkletProcessorRequest = { - requestType: RequestType; - voice: Float32Array; - numTrancateTreshold: number; - volTrancateThreshold: number; - volTrancateLength: number; + requestType: RequestType; + voice: Float32Array; + numTrancateTreshold: number; + volTrancateThreshold: number; + volTrancateLength: number; }; export type VoiceChangerWorkletProcessorResponse = { - responseType: ResponseType; - volume?: number; - recordData?: Float32Array[]; - inputData?: Float32Array; + responseType: ResponseType; + volume?: number; + recordData?: Float32Array[]; + inputData?: Float32Array; }; class VoiceChangerWorkletProcessor extends AudioWorkletProcessor { - private BLOCK_SIZE = 128; - private initialized = false; - private volume = 0; - // private numTrancateTreshold = 100; - // private volTrancateThreshold = 0.0005 - // private volTrancateLength = 32 - // private volTrancateCount = 0 + private BLOCK_SIZE = 128; + private initialized = false; + private volume = 0; + // private numTrancateTreshold = 100; + // private volTrancateThreshold = 0.0005 + // private volTrancateLength = 32 + // private volTrancateCount = 0 - private isRecording = false; + private isRecording = false; - playBuffer: Float32Array[] = []; - unpushedF32Data: Float32Array = new Float32Array(0); - /** - * @constructor - */ - constructor() { - super(); - console.log("[AudioWorkletProcessor] created."); - this.initialized = true; - this.port.onmessage = this.handleMessage.bind(this); - } - - calcVol = (data: Float32Array, prevVol: number) => { - const sum = data.reduce((prev, cur) => { - return prev + cur * cur; - }, 0); - const rms = Math.sqrt(sum / data.length); - return Math.max(rms, prevVol * 0.95); - }; - - trancateBuffer = () => { - console.log("[worklet] Buffer truncated"); - while (this.playBuffer.length > 2) { - this.playBuffer.shift(); - } - }; - handleMessage(event: any) { - const request = event.data as VoiceChangerWorkletProcessorRequest; - if (request.requestType === "config") { - // this.numTrancateTreshold = request.numTrancateTreshold; - // this.volTrancateLength = request.volTrancateLength - // this.volTrancateThreshold = request.volTrancateThreshold - console.log("[worklet] worklet configured", request); - return; - } else if (request.requestType === "start") { - if (this.isRecording) { - console.warn("[worklet] recoring is already started"); - return; - } - this.isRecording = true; - const startResponse: VoiceChangerWorkletProcessorResponse = { - responseType: "start_ok", - }; - this.port.postMessage(startResponse); - return; - } else if (request.requestType === "stop") { - if (!this.isRecording) { - console.warn("[worklet] recoring is not started"); - return; - } - this.isRecording = false; - const stopResponse: VoiceChangerWorkletProcessorResponse = { - responseType: "stop_ok", - }; - this.port.postMessage(stopResponse); - return; - } else if (request.requestType === "trancateBuffer") { - this.trancateBuffer(); - return; + playBuffer: Float32Array[] = []; + unpushedF32Data: Float32Array = new Float32Array(0); + /** + * @constructor + */ + constructor() { + super(); + console.log("[AudioWorkletProcessor] created."); + this.initialized = true; + this.port.onmessage = this.handleMessage.bind(this); } - const f32Data = request.voice; - // if (this.playBuffer.length > this.numTrancateTreshold) { - // console.log(`[worklet] Truncate ${this.playBuffer.length} > ${this.numTrancateTreshold}`); - // this.trancateBuffer(); - // } - if (this.playBuffer.length > (f32Data.length / this.BLOCK_SIZE) * 1.5) { - console.log( - `[worklet] Truncate ${this.playBuffer.length} > ${ - f32Data.length / this.BLOCK_SIZE - }` - ); - this.trancateBuffer(); - } - - const concatedF32Data = new Float32Array( - this.unpushedF32Data.length + f32Data.length - ); - concatedF32Data.set(this.unpushedF32Data); - concatedF32Data.set(f32Data, this.unpushedF32Data.length); - - const chunkNum = Math.floor(concatedF32Data.length / this.BLOCK_SIZE); - for (let i = 0; i < chunkNum; i++) { - const block = concatedF32Data.slice( - i * this.BLOCK_SIZE, - (i + 1) * this.BLOCK_SIZE - ); - this.playBuffer.push(block); - } - this.unpushedF32Data = concatedF32Data.slice(chunkNum * this.BLOCK_SIZE); - } - - pushData = (inputData: Float32Array) => { - const volumeResponse: VoiceChangerWorkletProcessorResponse = { - responseType: ResponseType.inputData, - inputData: inputData, + calcVol = (data: Float32Array, prevVol: number) => { + const sum = data.reduce((prev, cur) => { + return prev + cur * cur; + }, 0); + const rms = Math.sqrt(sum / data.length); + return Math.max(rms, prevVol * 0.95); }; - this.port.postMessage(volumeResponse); - }; - process( - _inputs: Float32Array[][], - outputs: Float32Array[][], - _parameters: Record - ) { - if (!this.initialized) { - console.warn("[worklet] worklet_process not ready"); - return true; + trancateBuffer = () => { + console.log("[worklet] Buffer truncated"); + while (this.playBuffer.length > 2) { + this.playBuffer.shift(); + } + }; + handleMessage(event: any) { + const request = event.data as VoiceChangerWorkletProcessorRequest; + if (request.requestType === "config") { + // this.numTrancateTreshold = request.numTrancateTreshold; + // this.volTrancateLength = request.volTrancateLength + // this.volTrancateThreshold = request.volTrancateThreshold + console.log("[worklet] worklet configured", request); + return; + } else if (request.requestType === "start") { + if (this.isRecording) { + console.warn("[worklet] recoring is already started"); + return; + } + this.isRecording = true; + const startResponse: VoiceChangerWorkletProcessorResponse = { + responseType: "start_ok", + }; + this.port.postMessage(startResponse); + return; + } else if (request.requestType === "stop") { + if (!this.isRecording) { + console.warn("[worklet] recoring is not started"); + return; + } + this.isRecording = false; + const stopResponse: VoiceChangerWorkletProcessorResponse = { + responseType: "stop_ok", + }; + this.port.postMessage(stopResponse); + return; + } else if (request.requestType === "trancateBuffer") { + this.trancateBuffer(); + return; + } + + const f32Data = request.voice; + // if (this.playBuffer.length > this.numTrancateTreshold) { + // console.log(`[worklet] Truncate ${this.playBuffer.length} > ${this.numTrancateTreshold}`); + // this.trancateBuffer(); + // } + if (this.playBuffer.length > (f32Data.length / this.BLOCK_SIZE) * 1.5) { + console.log(`[worklet] Truncate ${this.playBuffer.length} > ${f32Data.length / this.BLOCK_SIZE}`); + this.trancateBuffer(); + } + + const concatedF32Data = new Float32Array(this.unpushedF32Data.length + f32Data.length); + concatedF32Data.set(this.unpushedF32Data); + concatedF32Data.set(f32Data, this.unpushedF32Data.length); + + const chunkNum = Math.floor(concatedF32Data.length / this.BLOCK_SIZE); + for (let i = 0; i < chunkNum; i++) { + const block = concatedF32Data.slice(i * this.BLOCK_SIZE, (i + 1) * this.BLOCK_SIZE); + this.playBuffer.push(block); + } + this.unpushedF32Data = concatedF32Data.slice(chunkNum * this.BLOCK_SIZE); } - if (this.isRecording) { - if (_inputs.length > 0 && _inputs[0].length > 0) { - this.pushData(_inputs[0][0]); - } - } + pushData = (inputData: Float32Array) => { + const volumeResponse: VoiceChangerWorkletProcessorResponse = { + responseType: ResponseType.inputData, + inputData: inputData, + }; + this.port.postMessage(volumeResponse); + }; - if (this.playBuffer.length === 0) { - // console.log("[worklet] no play buffer"); - return true; - } - // console.log("[worklet] play buffer"); - //// 一定期間無音状態が続いている場合はスキップ。 - // let voice: Float32Array | undefined - // while (true) { - // voice = this.playBuffer.shift() - // if (!voice) { - // break - // } - // this.volume = this.calcVol(voice, this.volume) - // if (this.volume < this.volTrancateThreshold) { - // this.volTrancateCount += 1 - // } else { - // this.volTrancateCount = 0 - // } + process(_inputs: Float32Array[][], outputs: Float32Array[][], _parameters: Record) { + if (!this.initialized) { + console.warn("[worklet] worklet_process not ready"); + return true; + } - // // V.1.5.0よりsilent skipで音飛びするようになったので無効化 - // if (this.volTrancateCount < this.volTrancateLength || this.volTrancateLength < 0) { - // break - // } else { - // break - // // console.log("silent...skip") - // } - // } - let voice = this.playBuffer.shift(); - if (voice) { - this.volume = this.calcVol(voice, this.volume); - const volumeResponse: VoiceChangerWorkletProcessorResponse = { - responseType: ResponseType.volume, - volume: this.volume, - }; - this.port.postMessage(volumeResponse); - outputs[0][0].set(voice); - if (outputs[0].length == 2) { - outputs[0][1].set(voice); - } - } + if (this.isRecording) { + if (_inputs.length > 0 && _inputs[0].length > 0) { + this.pushData(_inputs[0][0]); + } + } - return true; - } + if (this.playBuffer.length === 0) { + // console.log("[worklet] no play buffer"); + return true; + } + // console.log("[worklet] play buffer"); + //// 一定期間無音状態が続いている場合はスキップ。 + // let voice: Float32Array | undefined + // while (true) { + // voice = this.playBuffer.shift() + // if (!voice) { + // break + // } + // this.volume = this.calcVol(voice, this.volume) + // if (this.volume < this.volTrancateThreshold) { + // this.volTrancateCount += 1 + // } else { + // this.volTrancateCount = 0 + // } + + // // V.1.5.0よりsilent skipで音飛びするようになったので無効化 + // if (this.volTrancateCount < this.volTrancateLength || this.volTrancateLength < 0) { + // break + // } else { + // break + // // console.log("silent...skip") + // } + // } + let voice = this.playBuffer.shift(); + if (voice) { + this.volume = this.calcVol(voice, this.volume); + const volumeResponse: VoiceChangerWorkletProcessorResponse = { + responseType: ResponseType.volume, + volume: this.volume, + }; + this.port.postMessage(volumeResponse); + outputs[0][0].set(voice); + if (outputs[0].length == 2) { + outputs[0][1].set(voice); + } + } + + return true; + } } -registerProcessor( - "voice-changer-worklet-processor", - VoiceChangerWorkletProcessor -); +registerProcessor("voice-changer-worklet-processor", VoiceChangerWorkletProcessor);