Bugfix:
- device output recorder button is showed in server device mode. Feature: - server device monitor Improve: - default uvicorn error log
This commit is contained in:
parent
b051d08ae0
commit
75668e1534
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
1767
client/demo/package-lock.json
generated
1767
client/demo/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -26,14 +26,14 @@
|
|||||||
"@babel/preset-env": "^7.22.5",
|
"@babel/preset-env": "^7.22.5",
|
||||||
"@babel/preset-react": "^7.22.5",
|
"@babel/preset-react": "^7.22.5",
|
||||||
"@babel/preset-typescript": "^7.22.5",
|
"@babel/preset-typescript": "^7.22.5",
|
||||||
"@types/node": "^20.3.2",
|
"@types/node": "^20.3.3",
|
||||||
"@types/react": "^18.2.14",
|
"@types/react": "^18.2.14",
|
||||||
"@types/react-dom": "^18.2.6",
|
"@types/react-dom": "^18.2.6",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"babel-loader": "^9.1.2",
|
"babel-loader": "^9.1.2",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.8.1",
|
"css-loader": "^6.8.1",
|
||||||
"eslint": "^8.43.0",
|
"eslint": "^8.44.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.32.2",
|
"eslint-plugin-react": "^7.32.2",
|
||||||
@ -54,7 +54,7 @@
|
|||||||
"webpack-dev-server": "^4.15.1"
|
"webpack-dev-server": "^4.15.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dannadori/voice-changer-client-js": "^1.0.155",
|
"@dannadori/voice-changer-client-js": "^1.0.157",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||||
|
@ -1,35 +1,34 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from "react"
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useAppState } from "../../../001_provider/001_AppStateProvider"
|
import { useAppState } from "../../../001_provider/001_AppStateProvider";
|
||||||
import { fileSelectorAsDataURL, useIndexedDB, } from "@dannadori/voice-changer-client-js"
|
import { fileSelectorAsDataURL, useIndexedDB } from "@dannadori/voice-changer-client-js";
|
||||||
import { useGuiState } from "../001_GuiStateProvider"
|
import { useGuiState } from "../001_GuiStateProvider";
|
||||||
import { AUDIO_ELEMENT_FOR_PLAY_RESULT, AUDIO_ELEMENT_FOR_TEST_CONVERTED, AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK, AUDIO_ELEMENT_FOR_TEST_ORIGINAL, INDEXEDDB_KEY_AUDIO_OUTPUT } from "../../../const"
|
import { AUDIO_ELEMENT_FOR_PLAY_RESULT, AUDIO_ELEMENT_FOR_TEST_CONVERTED, AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK, AUDIO_ELEMENT_FOR_TEST_ORIGINAL, INDEXEDDB_KEY_AUDIO_OUTPUT } from "../../../const";
|
||||||
|
|
||||||
export type DeviceAreaProps = {
|
export type DeviceAreaProps = {};
|
||||||
}
|
|
||||||
|
|
||||||
export const DeviceArea = (_props: DeviceAreaProps) => {
|
export const DeviceArea = (_props: DeviceAreaProps) => {
|
||||||
const { setting, serverSetting, audioContext, setAudioOutputElementId, initializedRef, setVoiceChangerClientSetting, startOutputRecording, stopOutputRecording } = useAppState()
|
const { setting, serverSetting, audioContext, setAudioOutputElementId, initializedRef, setVoiceChangerClientSetting, startOutputRecording, stopOutputRecording } = useAppState();
|
||||||
const { isConverting, audioInputForGUI, inputAudioDeviceInfo, setAudioInputForGUI, fileInputEchoback, setFileInputEchoback, setAudioOutputForGUI, audioOutputForGUI, outputAudioDeviceInfo } = useGuiState()
|
const { isConverting, audioInputForGUI, inputAudioDeviceInfo, setAudioInputForGUI, fileInputEchoback, setFileInputEchoback, setAudioOutputForGUI, audioOutputForGUI, outputAudioDeviceInfo } = useGuiState();
|
||||||
const [inputHostApi, setInputHostApi] = useState<string>("ALL")
|
const [inputHostApi, setInputHostApi] = useState<string>("ALL");
|
||||||
const [outputHostApi, setOutputHostApi] = useState<string>("ALL")
|
const [outputHostApi, setOutputHostApi] = useState<string>("ALL");
|
||||||
const audioSrcNode = useRef<MediaElementAudioSourceNode>()
|
const audioSrcNode = useRef<MediaElementAudioSourceNode>();
|
||||||
|
|
||||||
const { getItem, setItem } = useIndexedDB({ clientType: null })
|
const { getItem, setItem } = useIndexedDB({ clientType: null });
|
||||||
const [outputRecordingStarted, setOutputRecordingStarted] = useState<boolean>(false)
|
const [outputRecordingStarted, setOutputRecordingStarted] = useState<boolean>(false);
|
||||||
|
|
||||||
// (1) Audio Mode
|
// (1) Audio Mode
|
||||||
const deviceModeRow = useMemo(() => {
|
const deviceModeRow = useMemo(() => {
|
||||||
const enableServerAudio = serverSetting.serverSetting.enableServerAudio
|
const enableServerAudio = serverSetting.serverSetting.enableServerAudio;
|
||||||
const clientChecked = enableServerAudio == 1 ? false : true
|
const clientChecked = enableServerAudio == 1 ? false : true;
|
||||||
const serverChecked = enableServerAudio == 1 ? true : false
|
const serverChecked = enableServerAudio == 1 ? true : false;
|
||||||
|
|
||||||
const onDeviceModeChanged = (val: number) => {
|
const onDeviceModeChanged = (val: number) => {
|
||||||
if (isConverting) {
|
if (isConverting) {
|
||||||
alert("cannot change mode when voice conversion is enabled")
|
alert("cannot change mode when voice conversion is enabled");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, enableServerAudio: val })
|
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, enableServerAudio: val });
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area-control">
|
<div className="config-sub-area-control">
|
||||||
@ -37,131 +36,182 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
|
|||||||
<div className="config-sub-area-control-field">
|
<div className="config-sub-area-control-field">
|
||||||
<div className="config-sub-area-noise-container">
|
<div className="config-sub-area-noise-container">
|
||||||
<div className="config-sub-area-noise-checkbox-container">
|
<div className="config-sub-area-noise-checkbox-container">
|
||||||
<input type="radio" id="client-device" name="device-mode" checked={clientChecked} onChange={() => { onDeviceModeChanged(0) }} /> <label htmlFor="client-device">client</label>
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="client-device"
|
||||||
|
name="device-mode"
|
||||||
|
checked={clientChecked}
|
||||||
|
onChange={() => {
|
||||||
|
onDeviceModeChanged(0);
|
||||||
|
}}
|
||||||
|
/>{" "}
|
||||||
|
<label htmlFor="client-device">client</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="config-sub-area-noise-checkbox-container">
|
<div className="config-sub-area-noise-checkbox-container">
|
||||||
<input className="left-padding-1" type="radio" id="server-device" name="device-mode" checked={serverChecked} onChange={() => { onDeviceModeChanged(1) }} />
|
<input
|
||||||
|
className="left-padding-1"
|
||||||
|
type="radio"
|
||||||
|
id="server-device"
|
||||||
|
name="device-mode"
|
||||||
|
checked={serverChecked}
|
||||||
|
onChange={() => {
|
||||||
|
onDeviceModeChanged(1);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<label htmlFor="server-device">server</label>
|
<label htmlFor="server-device">server</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}, [serverSetting.serverSetting, serverSetting.updateServerSettings, isConverting])
|
}, [serverSetting.serverSetting, serverSetting.updateServerSettings, isConverting]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// (2) Audio Input
|
// (2) Audio Input
|
||||||
// キャッシュの設定は反映(たぶん、設定操作の時も起動していしまう。が問題は起こらないはず)
|
// キャッシュの設定は反映(たぶん、設定操作の時も起動していしまう。が問題は起こらないはず)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof setting.voiceChangerClientSetting.audioInput == "string") {
|
if (typeof setting.voiceChangerClientSetting.audioInput == "string") {
|
||||||
if (inputAudioDeviceInfo.find(x => {
|
if (
|
||||||
// console.log("COMPARE:", x.deviceId, appState.clientSetting.setting.audioInput)
|
inputAudioDeviceInfo.find((x) => {
|
||||||
return x.deviceId == setting.voiceChangerClientSetting.audioInput
|
// console.log("COMPARE:", x.deviceId, appState.clientSetting.setting.audioInput)
|
||||||
})) {
|
return x.deviceId == setting.voiceChangerClientSetting.audioInput;
|
||||||
setAudioInputForGUI(setting.voiceChangerClientSetting.audioInput)
|
})
|
||||||
|
) {
|
||||||
|
setAudioInputForGUI(setting.voiceChangerClientSetting.audioInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [inputAudioDeviceInfo, setting.voiceChangerClientSetting.audioInput])
|
}, [inputAudioDeviceInfo, setting.voiceChangerClientSetting.audioInput]);
|
||||||
|
|
||||||
// (2-1) クライアント
|
// (2-1) クライアント
|
||||||
const clientAudioInputRow = useMemo(() => {
|
const clientAudioInputRow = useMemo(() => {
|
||||||
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
||||||
return <></>
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area-control">
|
<div className="config-sub-area-control">
|
||||||
<div className="config-sub-area-control-title left-padding-1">input</div>
|
<div className="config-sub-area-control-title left-padding-1">input</div>
|
||||||
<div className="config-sub-area-control-field">
|
<div className="config-sub-area-control-field">
|
||||||
<select className="body-select" value={audioInputForGUI} onChange={async (e) => {
|
<select
|
||||||
setAudioInputForGUI(e.target.value)
|
className="body-select"
|
||||||
if (e.target.value != "file") {
|
value={audioInputForGUI}
|
||||||
try {
|
onChange={async (e) => {
|
||||||
await setVoiceChangerClientSetting({ ...setting.voiceChangerClientSetting, audioInput: e.target.value })
|
setAudioInputForGUI(e.target.value);
|
||||||
} catch (e) {
|
if (e.target.value != "file") {
|
||||||
alert(e)
|
try {
|
||||||
console.error(e)
|
await setVoiceChangerClientSetting({ ...setting.voiceChangerClientSetting, audioInput: e.target.value });
|
||||||
setAudioInputForGUI("none")
|
} catch (e) {
|
||||||
await setVoiceChangerClientSetting({ ...setting.voiceChangerClientSetting, audioInput: null })
|
alert(e);
|
||||||
|
console.error(e);
|
||||||
|
setAudioInputForGUI("none");
|
||||||
|
await setVoiceChangerClientSetting({ ...setting.voiceChangerClientSetting, audioInput: null });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}}>
|
>
|
||||||
{
|
{inputAudioDeviceInfo.map((x) => {
|
||||||
inputAudioDeviceInfo.map(x => {
|
return (
|
||||||
return <option key={x.deviceId} value={x.deviceId}>{x.label}</option>
|
<option key={x.deviceId} value={x.deviceId}>
|
||||||
})
|
{x.label}
|
||||||
}
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}, [setVoiceChangerClientSetting, setting, inputAudioDeviceInfo, audioInputForGUI, serverSetting.serverSetting.enableServerAudio])
|
}, [setVoiceChangerClientSetting, setting, inputAudioDeviceInfo, audioInputForGUI, serverSetting.serverSetting.enableServerAudio]);
|
||||||
|
|
||||||
|
|
||||||
// (2-2) サーバ
|
// (2-2) サーバ
|
||||||
const serverAudioInputRow = useMemo(() => {
|
const serverAudioInputRow = useMemo(() => {
|
||||||
if (serverSetting.serverSetting.enableServerAudio == 0) {
|
if (serverSetting.serverSetting.enableServerAudio == 0) {
|
||||||
return <></>
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const devices = serverSetting.serverSetting.serverAudioInputDevices
|
const devices = serverSetting.serverSetting.serverAudioInputDevices;
|
||||||
const hostAPIs = new Set(devices.map(x => { return x.hostAPI }))
|
const hostAPIs = new Set(
|
||||||
const hostAPIOptions = Array.from(hostAPIs).map((x, index) => { return <option value={x} key={index} >{x}</option> })
|
devices.map((x) => {
|
||||||
|
return x.hostAPI;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const hostAPIOptions = Array.from(hostAPIs).map((x, index) => {
|
||||||
|
return (
|
||||||
|
<option value={x} key={index}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const filteredDevice = devices.map((x, index) => {
|
const filteredDevice = devices
|
||||||
if (inputHostApi != "ALL" && x.hostAPI != inputHostApi) {
|
.map((x, index) => {
|
||||||
return null
|
if (inputHostApi != "ALL" && x.hostAPI != inputHostApi) {
|
||||||
}
|
return null;
|
||||||
return <option value={x.index} key={index}>[{x.hostAPI}]{x.name}</option>
|
}
|
||||||
}).filter(x => x != null)
|
return (
|
||||||
|
<option value={x.index} key={index}>
|
||||||
|
[{x.hostAPI}]{x.name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter((x) => x != null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area-control">
|
<div className="config-sub-area-control">
|
||||||
<div className="config-sub-area-control-title left-padding-1">input</div>
|
<div className="config-sub-area-control-title left-padding-1">input</div>
|
||||||
<div className="config-sub-area-control-field">
|
<div className="config-sub-area-control-field">
|
||||||
<div className="config-sub-area-control-field-auido-io">
|
<div className="config-sub-area-control-field-auido-io">
|
||||||
<select className="config-sub-area-control-field-auido-io-filter" name="kinds" id="kinds" value={inputHostApi} onChange={(e) => { setInputHostApi(e.target.value) }}>
|
<select
|
||||||
<option value="ALL" key="ALL" >ALL</option>
|
className="config-sub-area-control-field-auido-io-filter"
|
||||||
|
name="kinds"
|
||||||
|
id="kinds"
|
||||||
|
value={inputHostApi}
|
||||||
|
onChange={(e) => {
|
||||||
|
setInputHostApi(e.target.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="ALL" key="ALL">
|
||||||
|
ALL
|
||||||
|
</option>
|
||||||
{hostAPIOptions}
|
{hostAPIOptions}
|
||||||
</select>
|
</select>
|
||||||
<select className="config-sub-area-control-field-auido-io-select" value={serverSetting.serverSetting.serverInputDeviceId} onChange={(e) => {
|
<select
|
||||||
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverInputDeviceId: Number(e.target.value) })
|
className="config-sub-area-control-field-auido-io-select"
|
||||||
|
value={serverSetting.serverSetting.serverInputDeviceId}
|
||||||
}}>
|
onChange={(e) => {
|
||||||
|
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverInputDeviceId: Number(e.target.value) });
|
||||||
|
}}
|
||||||
|
>
|
||||||
{filteredDevice}
|
{filteredDevice}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
}, [inputHostApi, serverSetting.serverSetting, serverSetting.updateServerSettings, serverSetting.serverSetting.enableServerAudio]);
|
||||||
}, [inputHostApi, serverSetting.serverSetting, serverSetting.updateServerSettings, serverSetting.serverSetting.enableServerAudio])
|
|
||||||
|
|
||||||
// (2-3) File
|
// (2-3) File
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
[AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK].forEach(x => {
|
[AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK].forEach((x) => {
|
||||||
const audio = document.getElementById(x) as HTMLAudioElement
|
const audio = document.getElementById(x) as HTMLAudioElement;
|
||||||
if (audio) {
|
if (audio) {
|
||||||
audio.volume = fileInputEchoback ? 1 : 0
|
audio.volume = fileInputEchoback ? 1 : 0;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}, [fileInputEchoback])
|
}, [fileInputEchoback]);
|
||||||
|
|
||||||
const audioInputMediaRow = useMemo(() => {
|
const audioInputMediaRow = useMemo(() => {
|
||||||
if (audioInputForGUI != "file" || serverSetting.serverSetting.enableServerAudio == 1) {
|
if (audioInputForGUI != "file" || serverSetting.serverSetting.enableServerAudio == 1) {
|
||||||
return <></>
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onFileLoadClicked = async () => {
|
const onFileLoadClicked = async () => {
|
||||||
const url = await fileSelectorAsDataURL("")
|
const url = await fileSelectorAsDataURL("");
|
||||||
|
|
||||||
// input stream for client.
|
// input stream for client.
|
||||||
const audio = document.getElementById(AUDIO_ELEMENT_FOR_TEST_CONVERTED) as HTMLAudioElement
|
const audio = document.getElementById(AUDIO_ELEMENT_FOR_TEST_CONVERTED) as HTMLAudioElement;
|
||||||
audio.pause()
|
audio.pause();
|
||||||
audio.srcObject = null
|
audio.srcObject = null;
|
||||||
audio.src = url
|
audio.src = url;
|
||||||
await audio.play()
|
await audio.play();
|
||||||
if (!audioSrcNode.current) {
|
if (!audioSrcNode.current) {
|
||||||
audioSrcNode.current = audioContext!.createMediaElementSource(audio);
|
audioSrcNode.current = audioContext!.createMediaElementSource(audio);
|
||||||
}
|
}
|
||||||
@ -169,27 +219,27 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
|
|||||||
audioSrcNode.current = audioContext!.createMediaElementSource(audio);
|
audioSrcNode.current = audioContext!.createMediaElementSource(audio);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dst = audioContext.createMediaStreamDestination()
|
const dst = audioContext.createMediaStreamDestination();
|
||||||
audioSrcNode.current.connect(dst)
|
audioSrcNode.current.connect(dst);
|
||||||
try {
|
try {
|
||||||
setVoiceChangerClientSetting({ ...setting.voiceChangerClientSetting, audioInput: dst.stream })
|
setVoiceChangerClientSetting({ ...setting.voiceChangerClientSetting, audioInput: dst.stream });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
const audio_echo = document.getElementById(AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK) as HTMLAudioElement
|
const audio_echo = document.getElementById(AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK) as HTMLAudioElement;
|
||||||
audio_echo.srcObject = dst.stream
|
audio_echo.srcObject = dst.stream;
|
||||||
audio_echo.play()
|
audio_echo.play();
|
||||||
audio_echo.volume = 0
|
audio_echo.volume = 0;
|
||||||
setFileInputEchoback(false)
|
setFileInputEchoback(false);
|
||||||
|
|
||||||
// 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;
|
||||||
audio_org.pause()
|
audio_org.pause();
|
||||||
}
|
};
|
||||||
|
|
||||||
const echobackClass = fileInputEchoback ? "config-sub-area-control-field-wav-file-echoback-button-active" : "config-sub-area-control-field-wav-file-echoback-button"
|
const echobackClass = fileInputEchoback ? "config-sub-area-control-field-wav-file-echoback-button-active" : "config-sub-area-control-field-wav-file-echoback-button";
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area-control">
|
<div className="config-sub-area-control">
|
||||||
<div className="config-sub-area-control-field">
|
<div className="config-sub-area-control-field">
|
||||||
@ -202,190 +252,332 @@ export const DeviceArea = (_props: DeviceAreaProps) => {
|
|||||||
<div>
|
<div>
|
||||||
<img className="config-sub-area-control-field-wav-file-folder" src="./assets/icons/folder.svg" onClick={onFileLoadClicked} />
|
<img className="config-sub-area-control-field-wav-file-folder" src="./assets/icons/folder.svg" onClick={onFileLoadClicked} />
|
||||||
</div>
|
</div>
|
||||||
<div className={echobackClass} onClick={() => { setFileInputEchoback(!fileInputEchoback) }}>
|
<div
|
||||||
|
className={echobackClass}
|
||||||
|
onClick={() => {
|
||||||
|
setFileInputEchoback(!fileInputEchoback);
|
||||||
|
}}
|
||||||
|
>
|
||||||
echo{fileInputEchoback}
|
echo{fileInputEchoback}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}, [audioInputForGUI, fileInputEchoback, serverSetting.serverSetting])
|
}, [audioInputForGUI, fileInputEchoback, serverSetting.serverSetting]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// (3) Audio Output
|
// (3) Audio Output
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadCache = async () => {
|
const loadCache = async () => {
|
||||||
const key = await getItem(INDEXEDDB_KEY_AUDIO_OUTPUT)
|
const key = await getItem(INDEXEDDB_KEY_AUDIO_OUTPUT);
|
||||||
if (key) {
|
if (key) {
|
||||||
setAudioOutputForGUI(key as string)
|
setAudioOutputForGUI(key as string);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
loadCache()
|
loadCache();
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setAudioOutput = async () => {
|
const setAudioOutput = async () => {
|
||||||
const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices();
|
const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
|
||||||
[AUDIO_ELEMENT_FOR_PLAY_RESULT, AUDIO_ELEMENT_FOR_TEST_ORIGINAL, AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK].forEach(x => {
|
[AUDIO_ELEMENT_FOR_PLAY_RESULT, AUDIO_ELEMENT_FOR_TEST_ORIGINAL, AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK].forEach((x) => {
|
||||||
const audio = document.getElementById(x) as HTMLAudioElement
|
const audio = document.getElementById(x) as HTMLAudioElement;
|
||||||
if (audio) {
|
if (audio) {
|
||||||
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
||||||
|
|
||||||
// Server Audio を使う場合はElementから音は出さない。
|
// Server Audio を使う場合はElementから音は出さない。
|
||||||
audio.volume = 0
|
audio.volume = 0;
|
||||||
} else if (audioOutputForGUI == "none") {
|
} else if (audioOutputForGUI == "none") {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
audio.setSinkId("")
|
audio.setSinkId("");
|
||||||
if (x == AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK) {
|
if (x == AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK) {
|
||||||
audio.volume = 0
|
audio.volume = 0;
|
||||||
} else {
|
} else {
|
||||||
audio.volume = 0
|
audio.volume = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const audioOutputs = mediaDeviceInfos.filter(x => { return x.kind == "audiooutput" })
|
const audioOutputs = mediaDeviceInfos.filter((x) => {
|
||||||
const found = audioOutputs.some(x => { return x.deviceId == audioOutputForGUI })
|
return x.kind == "audiooutput";
|
||||||
|
});
|
||||||
|
const found = audioOutputs.some((x) => {
|
||||||
|
return x.deviceId == audioOutputForGUI;
|
||||||
|
});
|
||||||
if (found) {
|
if (found) {
|
||||||
// @ts-ignore // 例外キャッチできないので事前にIDチェックが必要らしい。!?
|
// @ts-ignore // 例外キャッチできないので事前にIDチェックが必要らしい。!?
|
||||||
audio.setSinkId(audioOutputForGUI)
|
audio.setSinkId(audioOutputForGUI);
|
||||||
} else {
|
} else {
|
||||||
console.warn("No audio output device. use default")
|
console.warn("No audio output device. use default");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x == AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK) {
|
if (x == AUDIO_ELEMENT_FOR_TEST_CONVERTED_ECHOBACK) {
|
||||||
audio.volume = fileInputEchoback ? 1 : 0
|
audio.volume = fileInputEchoback ? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
audio.volume = 1
|
audio.volume = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
setAudioOutput()
|
setAudioOutput();
|
||||||
}, [audioOutputForGUI, fileInputEchoback, serverSetting.serverSetting.enableServerAudio])
|
}, [audioOutputForGUI, fileInputEchoback, serverSetting.serverSetting.enableServerAudio]);
|
||||||
|
|
||||||
|
|
||||||
// (3-1) クライアント
|
// (3-1) クライアント
|
||||||
const clientAudioOutputRow = useMemo(() => {
|
const clientAudioOutputRow = useMemo(() => {
|
||||||
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
||||||
return <></>
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area-control">
|
<div className="config-sub-area-control">
|
||||||
<div className="config-sub-area-control-title left-padding-1">output</div>
|
<div className="config-sub-area-control-title left-padding-1">output</div>
|
||||||
<div className="config-sub-area-control-field">
|
<div className="config-sub-area-control-field">
|
||||||
<select className="body-select" value={audioOutputForGUI} onChange={(e) => {
|
<select
|
||||||
setAudioOutputForGUI(e.target.value)
|
className="body-select"
|
||||||
setItem(INDEXEDDB_KEY_AUDIO_OUTPUT, e.target.value)
|
value={audioOutputForGUI}
|
||||||
}}>
|
onChange={(e) => {
|
||||||
{
|
setAudioOutputForGUI(e.target.value);
|
||||||
outputAudioDeviceInfo.map(x => {
|
setItem(INDEXEDDB_KEY_AUDIO_OUTPUT, e.target.value);
|
||||||
return <option key={x.deviceId} value={x.deviceId}>{x.label}</option>
|
}}
|
||||||
})
|
>
|
||||||
}
|
{outputAudioDeviceInfo.map((x) => {
|
||||||
|
return (
|
||||||
|
<option key={x.deviceId} value={x.deviceId}>
|
||||||
|
{x.label}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}, [serverSetting.serverSetting.enableServerAudio, outputAudioDeviceInfo, audioOutputForGUI])
|
}, [serverSetting.serverSetting.enableServerAudio, outputAudioDeviceInfo, audioOutputForGUI]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("initializedRef.current", initializedRef.current)
|
console.log("initializedRef.current", initializedRef.current);
|
||||||
setAudioOutputElementId(AUDIO_ELEMENT_FOR_PLAY_RESULT)
|
setAudioOutputElementId(AUDIO_ELEMENT_FOR_PLAY_RESULT);
|
||||||
}, [initializedRef.current])
|
}, [initializedRef.current]);
|
||||||
|
|
||||||
// (3-2) サーバ
|
// (3-2) サーバ
|
||||||
const serverAudioOutputRow = useMemo(() => {
|
const serverAudioOutputRow = useMemo(() => {
|
||||||
if (serverSetting.serverSetting.enableServerAudio == 0) {
|
if (serverSetting.serverSetting.enableServerAudio == 0) {
|
||||||
return <></>
|
return <></>;
|
||||||
}
|
}
|
||||||
const devices = serverSetting.serverSetting.serverAudioOutputDevices
|
const devices = serverSetting.serverSetting.serverAudioOutputDevices;
|
||||||
const hostAPIs = new Set(devices.map(x => { return x.hostAPI }))
|
const hostAPIs = new Set(
|
||||||
const hostAPIOptions = Array.from(hostAPIs).map((x, index) => { return <option value={x} key={index} >{x}</option> })
|
devices.map((x) => {
|
||||||
|
return x.hostAPI;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const hostAPIOptions = Array.from(hostAPIs).map((x, index) => {
|
||||||
|
return (
|
||||||
|
<option value={x} key={index}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const filteredDevice = devices.map((x, index) => {
|
const filteredDevice = devices
|
||||||
if (outputHostApi != "ALL" && x.hostAPI != outputHostApi) {
|
.map((x, index) => {
|
||||||
return null
|
if (outputHostApi != "ALL" && x.hostAPI != outputHostApi) {
|
||||||
}
|
return null;
|
||||||
return <option value={x.index} key={index}>[{x.hostAPI}]{x.name}</option>
|
}
|
||||||
}).filter(x => x != null)
|
return (
|
||||||
|
<option value={x.index} key={index}>
|
||||||
|
[{x.hostAPI}]{x.name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter((x) => x != null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area-control">
|
<div className="config-sub-area-control">
|
||||||
<div className="config-sub-area-control-title left-padding-1">output</div>
|
<div className="config-sub-area-control-title left-padding-1">output</div>
|
||||||
<div className="config-sub-area-control-field">
|
<div className="config-sub-area-control-field">
|
||||||
<div className="config-sub-area-control-field-auido-io">
|
<div className="config-sub-area-control-field-auido-io">
|
||||||
<select className="config-sub-area-control-field-auido-io-filter" name="kinds" id="kinds" value={outputHostApi} onChange={(e) => { setOutputHostApi(e.target.value) }}>
|
<select
|
||||||
<option value="ALL" key="ALL" >ALL</option>
|
className="config-sub-area-control-field-auido-io-filter"
|
||||||
|
name="kinds"
|
||||||
|
id="kinds"
|
||||||
|
value={outputHostApi}
|
||||||
|
onChange={(e) => {
|
||||||
|
setOutputHostApi(e.target.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="ALL" key="ALL">
|
||||||
|
ALL
|
||||||
|
</option>
|
||||||
{hostAPIOptions}
|
{hostAPIOptions}
|
||||||
</select>
|
</select>
|
||||||
<select className="config-sub-area-control-field-auido-io-select" value={serverSetting.serverSetting.serverOutputDeviceId} onChange={(e) => {
|
<select
|
||||||
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverOutputDeviceId: Number(e.target.value) })
|
className="config-sub-area-control-field-auido-io-select"
|
||||||
}}>
|
value={serverSetting.serverSetting.serverOutputDeviceId}
|
||||||
|
onChange={(e) => {
|
||||||
|
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverOutputDeviceId: Number(e.target.value) });
|
||||||
|
}}
|
||||||
|
>
|
||||||
{filteredDevice}
|
{filteredDevice}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}, [outputHostApi, serverSetting.serverSetting, serverSetting.updateServerSettings, serverSetting.serverSetting.enableServerAudio])
|
}, [outputHostApi, serverSetting.serverSetting, serverSetting.updateServerSettings, serverSetting.serverSetting.enableServerAudio]);
|
||||||
|
|
||||||
|
|
||||||
// (4) レコーダー
|
// (4) レコーダー
|
||||||
const outputRecorderRow = useMemo(() => {
|
const outputRecorderRow = useMemo(() => {
|
||||||
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
if (serverSetting.serverSetting.enableServerAudio == 1) {
|
||||||
return <></>
|
return <></>;
|
||||||
}
|
}
|
||||||
const onOutputRecordStartClicked = async () => {
|
const onOutputRecordStartClicked = async () => {
|
||||||
setOutputRecordingStarted(true)
|
setOutputRecordingStarted(true);
|
||||||
await startOutputRecording()
|
await startOutputRecording();
|
||||||
}
|
};
|
||||||
const onOutputRecordStopClicked = async () => {
|
const onOutputRecordStopClicked = async () => {
|
||||||
setOutputRecordingStarted(false)
|
setOutputRecordingStarted(false);
|
||||||
const record = await stopOutputRecording()
|
const record = await stopOutputRecording();
|
||||||
downloadRecord(record)
|
downloadRecord(record);
|
||||||
}
|
};
|
||||||
|
|
||||||
const startClassName = outputRecordingStarted ? "config-sub-area-button-active" : "config-sub-area-button"
|
const startClassName = outputRecordingStarted ? "config-sub-area-button-active" : "config-sub-area-button";
|
||||||
const stopClassName = outputRecordingStarted ? "config-sub-area-button" : "config-sub-area-button-active"
|
const stopClassName = outputRecordingStarted ? "config-sub-area-button" : "config-sub-area-button-active";
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area-control">
|
<div className="config-sub-area-control">
|
||||||
<div className="config-sub-area-control-title">REC.</div>
|
<div className="config-sub-area-control-title">REC.</div>
|
||||||
<div className="config-sub-area-control-field">
|
<div className="config-sub-area-control-field">
|
||||||
<div className="config-sub-area-buttons">
|
<div className="config-sub-area-buttons">
|
||||||
<div onClick={onOutputRecordStartClicked} className={startClassName}>start</div>
|
<div onClick={onOutputRecordStartClicked} className={startClassName}>
|
||||||
<div onClick={onOutputRecordStopClicked} className={stopClassName}>stop</div>
|
start
|
||||||
|
</div>
|
||||||
|
<div onClick={onOutputRecordStopClicked} className={stopClassName}>
|
||||||
|
stop
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
}, [outputRecordingStarted, startOutputRecording, stopOutputRecording, serverSetting.serverSetting.enableServerAudio]);
|
||||||
|
|
||||||
}, [outputRecordingStarted, startOutputRecording, stopOutputRecording])
|
// (5) サンプリングレート
|
||||||
|
const sampleRateRow = useMemo(() => {
|
||||||
|
if (serverSetting.serverSetting.enableServerAudio == 0) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="config-sub-area-control">
|
||||||
|
<div className="config-sub-area-control-title left-padding-1">S.R.</div>
|
||||||
|
<div className="config-sub-area-control-field">
|
||||||
|
<div className="config-sub-area-control-field-auido-io">
|
||||||
|
<select
|
||||||
|
className="config-sub-area-control-field-sample-rate-select"
|
||||||
|
value={serverSetting.serverSetting.serverAudioSampleRate}
|
||||||
|
onChange={(e) => {
|
||||||
|
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverAudioSampleRate: Number(e.target.value) });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{[16000, 32000, 44100, 48000, 96000, 192000].map((x) => {
|
||||||
|
return (
|
||||||
|
<option key={x} value={x}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [serverSetting.serverSetting, serverSetting.updateServerSettings, serverSetting.serverSetting.enableServerAudio]);
|
||||||
|
|
||||||
|
// (6) Monitor
|
||||||
|
const serverMonitorRow = useMemo(() => {
|
||||||
|
if (serverSetting.serverSetting.enableServerAudio == 0) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
const devices = serverSetting.serverSetting.serverAudioOutputDevices;
|
||||||
|
const hostAPIs = new Set(
|
||||||
|
devices.map((x) => {
|
||||||
|
return x.hostAPI;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const hostAPIOptions = Array.from(hostAPIs).map((x, index) => {
|
||||||
|
return (
|
||||||
|
<option value={x} key={index}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredDevice = devices
|
||||||
|
.map((x, index) => {
|
||||||
|
if (outputHostApi != "ALL" && x.hostAPI != outputHostApi) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<option value={x.index} key={index}>
|
||||||
|
[{x.hostAPI}]{x.name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter((x) => x != null);
|
||||||
|
filteredDevice.unshift(
|
||||||
|
<option value={-1} key={-1}>
|
||||||
|
None
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="config-sub-area-control">
|
||||||
|
<div className="config-sub-area-control-title left-padding-1">monitor</div>
|
||||||
|
<div className="config-sub-area-control-field">
|
||||||
|
<div className="config-sub-area-control-field-auido-io">
|
||||||
|
<select
|
||||||
|
className="config-sub-area-control-field-auido-io-filter"
|
||||||
|
name="kinds"
|
||||||
|
id="kinds"
|
||||||
|
value={outputHostApi}
|
||||||
|
onChange={(e) => {
|
||||||
|
setOutputHostApi(e.target.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="ALL" key="ALL">
|
||||||
|
ALL
|
||||||
|
</option>
|
||||||
|
{hostAPIOptions}
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
className="config-sub-area-control-field-auido-io-select"
|
||||||
|
value={serverSetting.serverSetting.serverMonitorDeviceId}
|
||||||
|
onChange={(e) => {
|
||||||
|
serverSetting.updateServerSettings({ ...serverSetting.serverSetting, serverMonitorDeviceId: Number(e.target.value) });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{filteredDevice}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [outputHostApi, serverSetting.serverSetting, serverSetting.updateServerSettings, serverSetting.serverSetting.enableServerAudio]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="config-sub-area">
|
<div className="config-sub-area">
|
||||||
{deviceModeRow}
|
{deviceModeRow}
|
||||||
|
{sampleRateRow}
|
||||||
{clientAudioInputRow}
|
{clientAudioInputRow}
|
||||||
{serverAudioInputRow}
|
{serverAudioInputRow}
|
||||||
{audioInputMediaRow}
|
{audioInputMediaRow}
|
||||||
{clientAudioOutputRow}
|
{clientAudioOutputRow}
|
||||||
{serverAudioOutputRow}
|
{serverAudioOutputRow}
|
||||||
|
{serverMonitorRow}
|
||||||
|
|
||||||
{outputRecorderRow}
|
{outputRecorderRow}
|
||||||
<audio hidden id={AUDIO_ELEMENT_FOR_PLAY_RESULT}></audio>
|
<audio hidden id={AUDIO_ELEMENT_FOR_PLAY_RESULT}></audio>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const downloadRecord = (data: Float32Array) => {
|
const downloadRecord = (data: Float32Array) => {
|
||||||
|
|
||||||
const writeString = (view: DataView, offset: number, string: string) => {
|
const writeString = (view: DataView, offset: number, string: string) => {
|
||||||
for (var i = 0; i < string.length; i++) {
|
for (var i = 0; i < string.length; i++) {
|
||||||
view.setUint8(offset + i, string.charCodeAt(i));
|
view.setUint8(offset + i, string.charCodeAt(i));
|
||||||
@ -395,7 +587,7 @@ const downloadRecord = (data: Float32Array) => {
|
|||||||
const floatTo16BitPCM = (output: DataView, offset: number, input: Float32Array) => {
|
const floatTo16BitPCM = (output: DataView, offset: number, input: Float32Array) => {
|
||||||
for (var i = 0; i < input.length; i++, offset += 2) {
|
for (var i = 0; i < input.length; i++, offset += 2) {
|
||||||
var s = Math.max(-1, Math.min(1, input[i]));
|
var s = Math.max(-1, Math.min(1, input[i]));
|
||||||
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -403,10 +595,10 @@ const downloadRecord = (data: Float32Array) => {
|
|||||||
const view = new DataView(buffer);
|
const view = new DataView(buffer);
|
||||||
|
|
||||||
// https://www.youfit.co.jp/archives/1418
|
// https://www.youfit.co.jp/archives/1418
|
||||||
writeString(view, 0, 'RIFF'); // RIFFヘッダ
|
writeString(view, 0, "RIFF"); // RIFFヘッダ
|
||||||
view.setUint32(4, 32 + data.length * 2, true); // これ以降のファイルサイズ
|
view.setUint32(4, 32 + data.length * 2, true); // これ以降のファイルサイズ
|
||||||
writeString(view, 8, 'WAVE'); // WAVEヘッダ
|
writeString(view, 8, "WAVE"); // WAVEヘッダ
|
||||||
writeString(view, 12, 'fmt '); // fmtチャンク
|
writeString(view, 12, "fmt "); // fmtチャンク
|
||||||
view.setUint32(16, 16, true); // fmtチャンクのバイト数
|
view.setUint32(16, 16, true); // fmtチャンクのバイト数
|
||||||
view.setUint16(20, 1, true); // フォーマットID
|
view.setUint16(20, 1, true); // フォーマットID
|
||||||
view.setUint16(22, 1, true); // チャンネル数
|
view.setUint16(22, 1, true); // チャンネル数
|
||||||
@ -414,10 +606,10 @@ const downloadRecord = (data: Float32Array) => {
|
|||||||
view.setUint32(28, 48000 * 2, true); // データ速度
|
view.setUint32(28, 48000 * 2, true); // データ速度
|
||||||
view.setUint16(32, 2, true); // ブロックサイズ
|
view.setUint16(32, 2, true); // ブロックサイズ
|
||||||
view.setUint16(34, 16, true); // サンプルあたりのビット数
|
view.setUint16(34, 16, true); // サンプルあたりのビット数
|
||||||
writeString(view, 36, 'data'); // dataチャンク
|
writeString(view, 36, "data"); // dataチャンク
|
||||||
view.setUint32(40, data.length * 2, true); // 波形データのバイト数
|
view.setUint32(40, data.length * 2, true); // 波形データのバイト数
|
||||||
floatTo16BitPCM(view, 44, data); // 波形データ
|
floatTo16BitPCM(view, 44, data); // 波形データ
|
||||||
const audioBlob = new Blob([view], { type: 'audio/wav' });
|
const audioBlob = new Blob([view], { type: "audio/wav" });
|
||||||
|
|
||||||
const url = URL.createObjectURL(audioBlob);
|
const url = URL.createObjectURL(audioBlob);
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
@ -427,4 +619,4 @@ const downloadRecord = (data: Float32Array) => {
|
|||||||
a.click();
|
a.click();
|
||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
}
|
};
|
||||||
|
1780
client/lib/package-lock.json
generated
1780
client/lib/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@dannadori/voice-changer-client-js",
|
"name": "@dannadori/voice-changer-client-js",
|
||||||
"version": "1.0.155",
|
"version": "1.0.157",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
@ -27,10 +27,10 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/audioworklet": "^0.0.48",
|
"@types/audioworklet": "^0.0.48",
|
||||||
"@types/node": "^20.3.2",
|
"@types/node": "^20.3.3",
|
||||||
"@types/react": "18.2.14",
|
"@types/react": "18.2.14",
|
||||||
"@types/react-dom": "18.2.6",
|
"@types/react-dom": "18.2.6",
|
||||||
"eslint": "^8.43.0",
|
"eslint": "^8.44.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.32.2",
|
"eslint-plugin-react": "^7.32.2",
|
||||||
@ -47,7 +47,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/readable-stream": "^2.3.15",
|
"@types/readable-stream": "^2.3.15",
|
||||||
"amazon-chime-sdk-js": "^3.14.1",
|
"amazon-chime-sdk-js": "^3.15.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -83,12 +83,15 @@ export const ServerSettingKey = {
|
|||||||
|
|
||||||
"enableServerAudio": "enableServerAudio",
|
"enableServerAudio": "enableServerAudio",
|
||||||
"serverAudioStated": "serverAudioStated",
|
"serverAudioStated": "serverAudioStated",
|
||||||
|
"serverAudioSampleRate": "serverAudioSampleRate",
|
||||||
"serverInputAudioSampleRate": "serverInputAudioSampleRate",
|
"serverInputAudioSampleRate": "serverInputAudioSampleRate",
|
||||||
"serverOutputAudioSampleRate": "serverOutputAudioSampleRate",
|
"serverOutputAudioSampleRate": "serverOutputAudioSampleRate",
|
||||||
|
"serverMonitorAudioSampleRate": "serverMonitorAudioSampleRate",
|
||||||
"serverInputAudioBufferSize": "serverInputAudioBufferSize",
|
"serverInputAudioBufferSize": "serverInputAudioBufferSize",
|
||||||
"serverOutputAudioBufferSize": "serverOutputAudioBufferSize",
|
"serverOutputAudioBufferSize": "serverOutputAudioBufferSize",
|
||||||
"serverInputDeviceId": "serverInputDeviceId",
|
"serverInputDeviceId": "serverInputDeviceId",
|
||||||
"serverOutputDeviceId": "serverOutputDeviceId",
|
"serverOutputDeviceId": "serverOutputDeviceId",
|
||||||
|
"serverMonitorDeviceId": "serverMonitorDeviceId",
|
||||||
"serverReadChunkSize": "serverReadChunkSize",
|
"serverReadChunkSize": "serverReadChunkSize",
|
||||||
"serverInputAudioGain": "serverInputAudioGain",
|
"serverInputAudioGain": "serverInputAudioGain",
|
||||||
"serverOutputAudioGain": "serverOutputAudioGain",
|
"serverOutputAudioGain": "serverOutputAudioGain",
|
||||||
@ -138,12 +141,15 @@ export type VoiceChangerServerSetting = {
|
|||||||
|
|
||||||
enableServerAudio: number // 0:off, 1:on
|
enableServerAudio: number // 0:off, 1:on
|
||||||
serverAudioStated: number // 0:off, 1:on
|
serverAudioStated: number // 0:off, 1:on
|
||||||
|
serverAudioSampleRate: number
|
||||||
serverInputAudioSampleRate: number
|
serverInputAudioSampleRate: number
|
||||||
serverOutputAudioSampleRate: number
|
serverOutputAudioSampleRate: number
|
||||||
|
serverMonitorAudioSampleRate: number
|
||||||
serverInputAudioBufferSize: number
|
serverInputAudioBufferSize: number
|
||||||
serverOutputAudioBufferSize: number
|
serverOutputAudioBufferSize: number
|
||||||
serverInputDeviceId: number
|
serverInputDeviceId: number
|
||||||
serverOutputDeviceId: number
|
serverOutputDeviceId: number
|
||||||
|
serverMonitorDeviceId: number
|
||||||
serverReadChunkSize: number
|
serverReadChunkSize: number
|
||||||
serverInputAudioGain: number
|
serverInputAudioGain: number
|
||||||
serverOutputAudioGain: number
|
serverOutputAudioGain: number
|
||||||
@ -306,12 +312,15 @@ export const DefaultServerSetting: ServerInfo = {
|
|||||||
|
|
||||||
enableServerAudio: 0,
|
enableServerAudio: 0,
|
||||||
serverAudioStated: 0,
|
serverAudioStated: 0,
|
||||||
|
serverAudioSampleRate: 48000,
|
||||||
serverInputAudioSampleRate: 48000,
|
serverInputAudioSampleRate: 48000,
|
||||||
serverOutputAudioSampleRate: 48000,
|
serverOutputAudioSampleRate: 48000,
|
||||||
|
serverMonitorAudioSampleRate: 48000,
|
||||||
serverInputAudioBufferSize: 1024 * 24,
|
serverInputAudioBufferSize: 1024 * 24,
|
||||||
serverOutputAudioBufferSize: 1024 * 24,
|
serverOutputAudioBufferSize: 1024 * 24,
|
||||||
serverInputDeviceId: -1,
|
serverInputDeviceId: -1,
|
||||||
serverOutputDeviceId: -1,
|
serverOutputDeviceId: -1,
|
||||||
|
serverMonitorDeviceId: -1,
|
||||||
serverReadChunkSize: 256,
|
serverReadChunkSize: 256,
|
||||||
serverInputAudioGain: 1.0,
|
serverInputAudioGain: 1.0,
|
||||||
serverOutputAudioGain: 1.0,
|
serverOutputAudioGain: 1.0,
|
||||||
|
8
server/.vscode/settings.json
vendored
8
server/.vscode/settings.json
vendored
@ -9,11 +9,9 @@
|
|||||||
"editor.formatOnSave": true // ファイル保存時に自動フォーマット
|
"editor.formatOnSave": true // ファイル保存時に自動フォーマット
|
||||||
},
|
},
|
||||||
"python.formatting.blackArgs": ["--line-length", "550"],
|
"python.formatting.blackArgs": ["--line-length", "550"],
|
||||||
"flake8.args": [
|
|
||||||
"--ignore=E501,E402,E722,E741,E203,W503"
|
|
||||||
// "--max-line-length=150",
|
|
||||||
// "--max-complexity=20"
|
|
||||||
],
|
|
||||||
"python.linting.flake8Enabled": true,
|
"python.linting.flake8Enabled": true,
|
||||||
|
"python.linting.flake8Args": [
|
||||||
|
"--max-line-length=99999"
|
||||||
|
],
|
||||||
"python.linting.enabled": true
|
"python.linting.enabled": true
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ setup_loggers()
|
|||||||
|
|
||||||
def setupArgParser():
|
def setupArgParser():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--logLevel", type=str, default="critical", help="Log level info|critical. (default: critical)")
|
parser.add_argument("--logLevel", type=str, default="error", help="Log level info|critical|error. (default: error)")
|
||||||
parser.add_argument("-p", type=int, default=18888, help="port")
|
parser.add_argument("-p", type=int, default=18888, help="port")
|
||||||
parser.add_argument("--https", type=strtobool, default=False, help="use https")
|
parser.add_argument("--https", type=strtobool, default=False, help="use https")
|
||||||
parser.add_argument("--httpsKey", type=str, default="ssl.key", help="path for the key of https")
|
parser.add_argument("--httpsKey", type=str, default="ssl.key", help="path for the key of https")
|
||||||
@ -94,13 +94,16 @@ PORT = args.p
|
|||||||
|
|
||||||
|
|
||||||
def localServer(logLevel: str = "critical"):
|
def localServer(logLevel: str = "critical"):
|
||||||
uvicorn.run(
|
try:
|
||||||
f"{os.path.basename(__file__)[:-3]}:app_socketio",
|
uvicorn.run(
|
||||||
host="0.0.0.0",
|
f"{os.path.basename(__file__)[:-3]}:app_socketio",
|
||||||
port=int(PORT),
|
host="0.0.0.0",
|
||||||
reload=False if hasattr(sys, "_MEIPASS") else True,
|
port=int(PORT),
|
||||||
log_level=logLevel,
|
reload=False if hasattr(sys, "_MEIPASS") else True,
|
||||||
)
|
log_level=logLevel,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print("[Voice Changer] Web Server Launch Exception", e)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "MMVCServerSIO":
|
if __name__ == "MMVCServerSIO":
|
||||||
@ -204,15 +207,19 @@ if __name__ == "__main__":
|
|||||||
# サーバ起動
|
# サーバ起動
|
||||||
if args.https:
|
if args.https:
|
||||||
# HTTPS サーバ起動
|
# HTTPS サーバ起動
|
||||||
uvicorn.run(
|
try:
|
||||||
f"{os.path.basename(__file__)[:-3]}:app_socketio",
|
uvicorn.run(
|
||||||
host="0.0.0.0",
|
f"{os.path.basename(__file__)[:-3]}:app_socketio",
|
||||||
port=int(PORT),
|
host="0.0.0.0",
|
||||||
reload=False if hasattr(sys, "_MEIPASS") else True,
|
port=int(PORT),
|
||||||
ssl_keyfile=key_path,
|
reload=False if hasattr(sys, "_MEIPASS") else True,
|
||||||
ssl_certfile=cert_path,
|
ssl_keyfile=key_path,
|
||||||
log_level=args.logLevel,
|
ssl_certfile=cert_path,
|
||||||
)
|
log_level=args.logLevel,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print("[Voice Changer] Web Server Launch Exception", e)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
p = mp.Process(name="p", target=localServer, args=(args.logLevel,))
|
p = mp.Process(name="p", target=localServer, args=(args.logLevel,))
|
||||||
p.start()
|
p.start()
|
||||||
|
@ -23,6 +23,8 @@ ModelType: TypeAlias = Literal[
|
|||||||
|
|
||||||
STORED_SETTING_FILE = "stored_setting.json"
|
STORED_SETTING_FILE = "stored_setting.json"
|
||||||
|
|
||||||
|
SERVER_DEVICE_SAMPLE_RATES = [16000, 32000, 44100, 48000, 96000, 192000]
|
||||||
|
|
||||||
tmpdir = tempfile.TemporaryDirectory()
|
tmpdir = tempfile.TemporaryDirectory()
|
||||||
SSL_KEY_DIR = os.path.join(tmpdir.name, "keys") if hasattr(sys, "_MEIPASS") else "keys"
|
SSL_KEY_DIR = os.path.join(tmpdir.name, "keys") if hasattr(sys, "_MEIPASS") else "keys"
|
||||||
MODEL_DIR = os.path.join(tmpdir.name, "logs") if hasattr(sys, "_MEIPASS") else "logs"
|
MODEL_DIR = os.path.join(tmpdir.name, "logs") if hasattr(sys, "_MEIPASS") else "logs"
|
||||||
|
@ -76,7 +76,6 @@ class MMVC_Rest_Fileuploader:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("[Voice Changer] post_update_settings ex:", e)
|
print("[Voice Changer] post_update_settings ex:", e)
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
def post_load_model(
|
def post_load_model(
|
||||||
|
@ -3,19 +3,19 @@ import os
|
|||||||
|
|
||||||
|
|
||||||
class IORecorder:
|
class IORecorder:
|
||||||
def __init__(self, inputFilename: str, outputFilename: str, samplingRate: int):
|
def __init__(self, inputFilename: str, outputFilename: str, inputSamplingRate: int, outputSamplingRate: int):
|
||||||
self._clearFile(inputFilename)
|
self._clearFile(inputFilename)
|
||||||
self._clearFile(outputFilename)
|
self._clearFile(outputFilename)
|
||||||
|
|
||||||
self.fi = wave.open(inputFilename, "wb")
|
self.fi = wave.open(inputFilename, "wb")
|
||||||
self.fi.setnchannels(1)
|
self.fi.setnchannels(1)
|
||||||
self.fi.setsampwidth(2)
|
self.fi.setsampwidth(2)
|
||||||
self.fi.setframerate(samplingRate)
|
self.fi.setframerate(inputSamplingRate)
|
||||||
|
|
||||||
self.fo = wave.open(outputFilename, "wb")
|
self.fo = wave.open(outputFilename, "wb")
|
||||||
self.fo.setnchannels(1)
|
self.fo.setnchannels(1)
|
||||||
self.fo.setsampwidth(2)
|
self.fo.setsampwidth(2)
|
||||||
self.fo.setframerate(samplingRate)
|
self.fo.setframerate(outputSamplingRate)
|
||||||
|
|
||||||
def _clearFile(self, filename: str):
|
def _clearFile(self, filename: str):
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import sounddevice as sd
|
import sounddevice as sd
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from const import ServerAudioDeviceTypes
|
from const import ServerAudioDeviceTypes
|
||||||
|
import numpy as np
|
||||||
|
# from const import SERVER_DEVICE_SAMPLE_RATES
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -12,6 +15,40 @@ class ServerAudioDevice:
|
|||||||
maxInputChannels: int = 0
|
maxInputChannels: int = 0
|
||||||
maxOutputChannels: int = 0
|
maxOutputChannels: int = 0
|
||||||
default_samplerate: int = 0
|
default_samplerate: int = 0
|
||||||
|
available_samplerates: list[int] = field(default_factory=lambda: [])
|
||||||
|
|
||||||
|
|
||||||
|
def dummy_callback(data: np.ndarray, frames, times, status):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def checkSamplingRate(deviceId: int, desiredSamplingRate: int, type: ServerAudioDeviceTypes):
|
||||||
|
if type == "input":
|
||||||
|
try:
|
||||||
|
with sd.InputStream(
|
||||||
|
device=deviceId,
|
||||||
|
callback=dummy_callback,
|
||||||
|
dtype="float32",
|
||||||
|
samplerate=desiredSamplingRate
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
return True
|
||||||
|
except Exception as e: # NOQA
|
||||||
|
# print("[checkSamplingRate]", e)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
with sd.OutputStream(
|
||||||
|
device=deviceId,
|
||||||
|
callback=dummy_callback,
|
||||||
|
dtype="float32",
|
||||||
|
samplerate=desiredSamplingRate
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
return True
|
||||||
|
except Exception as e: # NOQA
|
||||||
|
# print("[checkSamplingRate]", e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def list_audio_device():
|
def list_audio_device():
|
||||||
@ -20,7 +57,7 @@ def list_audio_device():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("[Voice Changer] ex:query_devices")
|
print("[Voice Changer] ex:query_devices")
|
||||||
print(e)
|
print(e)
|
||||||
return [], []
|
raise e
|
||||||
|
|
||||||
inputAudioDeviceList = [d for d in audioDeviceList if d["max_input_channels"] > 0]
|
inputAudioDeviceList = [d for d in audioDeviceList if d["max_input_channels"] > 0]
|
||||||
outputAudioDeviceList = [d for d in audioDeviceList if d["max_output_channels"] > 0]
|
outputAudioDeviceList = [d for d in audioDeviceList if d["max_output_channels"] > 0]
|
||||||
@ -55,4 +92,20 @@ def list_audio_device():
|
|||||||
)
|
)
|
||||||
serverAudioOutputDevices.append(serverOutputAudioDevice)
|
serverAudioOutputDevices.append(serverOutputAudioDevice)
|
||||||
|
|
||||||
|
# print("check sample rate1")
|
||||||
|
# for d in serverAudioInputDevices:
|
||||||
|
# print("check sample rate1-1")
|
||||||
|
# for sr in SERVER_DEVICE_SAMPLE_RATES:
|
||||||
|
# print("check sample rate1-2")
|
||||||
|
# if checkSamplingRate(d.index, sr, "input"):
|
||||||
|
# d.available_samplerates.append(sr)
|
||||||
|
# print("check sample rate2")
|
||||||
|
# for d in serverAudioOutputDevices:
|
||||||
|
# print("check sample rate2-1")
|
||||||
|
# for sr in SERVER_DEVICE_SAMPLE_RATES:
|
||||||
|
# print("check sample rate2-2")
|
||||||
|
# if checkSamplingRate(d.index, sr, "output"):
|
||||||
|
# d.available_samplerates.append(sr)
|
||||||
|
# print("check sample rate3")
|
||||||
|
|
||||||
return serverAudioInputDevices, serverAudioOutputDevices
|
return serverAudioInputDevices, serverAudioOutputDevices
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from dataclasses import dataclass, asdict
|
from dataclasses import dataclass, asdict
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from const import SERVER_DEVICE_SAMPLE_RATES
|
||||||
|
|
||||||
from voice_changer.Local.AudioDeviceList import list_audio_device
|
from voice_changer.Local.AudioDeviceList import checkSamplingRate, list_audio_device
|
||||||
import time
|
import time
|
||||||
import sounddevice as sd
|
import sounddevice as sd
|
||||||
from voice_changer.utils.Timer import Timer
|
from voice_changer.utils.Timer import Timer
|
||||||
@ -10,6 +11,8 @@ import librosa
|
|||||||
|
|
||||||
from voice_changer.utils.VoiceChangerModel import AudioInOut
|
from voice_changer.utils.VoiceChangerModel import AudioInOut
|
||||||
from typing import Protocol
|
from typing import Protocol
|
||||||
|
from typing import Literal, TypeAlias
|
||||||
|
AudioDeviceKind: TypeAlias = Literal["input", "output"]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -18,12 +21,21 @@ class ServerDeviceSettings:
|
|||||||
serverAudioStated: int = 0 # 0:off, 1:on
|
serverAudioStated: int = 0 # 0:off, 1:on
|
||||||
serverInputAudioSampleRate: int = 44100
|
serverInputAudioSampleRate: int = 44100
|
||||||
serverOutputAudioSampleRate: int = 44100
|
serverOutputAudioSampleRate: int = 44100
|
||||||
|
serverMonitorAudioSampleRate: int = 44100
|
||||||
|
|
||||||
|
serverAudioSampleRate: int = 44100
|
||||||
|
# serverAudioSampleRate: int = 16000
|
||||||
|
# serverAudioSampleRate: int = 48000
|
||||||
|
|
||||||
serverInputDeviceId: int = -1
|
serverInputDeviceId: int = -1
|
||||||
serverOutputDeviceId: int = -1
|
serverOutputDeviceId: int = -1
|
||||||
|
serverMonitorDeviceId: int = -1 # -1 でモニター無効
|
||||||
serverReadChunkSize: int = 256
|
serverReadChunkSize: int = 256
|
||||||
serverInputAudioGain: float = 1.0
|
serverInputAudioGain: float = 1.0
|
||||||
serverOutputAudioGain: float = 1.0
|
serverOutputAudioGain: float = 1.0
|
||||||
|
|
||||||
|
exclusiveMode: bool = False
|
||||||
|
|
||||||
|
|
||||||
EditableServerDeviceSettings = {
|
EditableServerDeviceSettings = {
|
||||||
"intData": [
|
"intData": [
|
||||||
@ -31,14 +43,20 @@ EditableServerDeviceSettings = {
|
|||||||
"serverAudioStated",
|
"serverAudioStated",
|
||||||
"serverInputAudioSampleRate",
|
"serverInputAudioSampleRate",
|
||||||
"serverOutputAudioSampleRate",
|
"serverOutputAudioSampleRate",
|
||||||
|
"serverMonitorAudioSampleRate",
|
||||||
|
"serverAudioSampleRate",
|
||||||
"serverInputDeviceId",
|
"serverInputDeviceId",
|
||||||
"serverOutputDeviceId",
|
"serverOutputDeviceId",
|
||||||
|
"serverMonitorDeviceId",
|
||||||
"serverReadChunkSize",
|
"serverReadChunkSize",
|
||||||
],
|
],
|
||||||
"floatData": [
|
"floatData": [
|
||||||
"serverInputAudioGain",
|
"serverInputAudioGain",
|
||||||
"serverOutputAudioGain",
|
"serverOutputAudioGain",
|
||||||
],
|
],
|
||||||
|
"boolData": [
|
||||||
|
"exclusiveMode"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -52,7 +70,10 @@ class ServerDeviceCallbacks(Protocol):
|
|||||||
def get_processing_sampling_rate(self):
|
def get_processing_sampling_rate(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
def setSamplingRate(self, sr: int):
|
def setInputSamplingRate(self, sr: int):
|
||||||
|
...
|
||||||
|
|
||||||
|
def setOutputSamplingRate(self, sr: int):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
@ -60,6 +81,10 @@ class ServerDevice:
|
|||||||
def __init__(self, serverDeviceCallbacks: ServerDeviceCallbacks):
|
def __init__(self, serverDeviceCallbacks: ServerDeviceCallbacks):
|
||||||
self.settings = ServerDeviceSettings()
|
self.settings = ServerDeviceSettings()
|
||||||
self.serverDeviceCallbacks = serverDeviceCallbacks
|
self.serverDeviceCallbacks = serverDeviceCallbacks
|
||||||
|
self.out_wav = None
|
||||||
|
self.mon_wav = None
|
||||||
|
self.serverAudioInputDevices = None
|
||||||
|
self.serverAudioOutputDevices = None
|
||||||
|
|
||||||
def getServerInputAudioDevice(self, index: int):
|
def getServerInputAudioDevice(self, index: int):
|
||||||
audioinput, _audiooutput = list_audio_device()
|
audioinput, _audiooutput = list_audio_device()
|
||||||
@ -94,7 +119,221 @@ class ServerDevice:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("[Voice Changer] ex:", e)
|
print("[Voice Changer] ex:", e)
|
||||||
|
|
||||||
|
def audioInput_callback(self, indata: np.ndarray, frames, times, status):
|
||||||
|
try:
|
||||||
|
indata = indata * self.settings.serverInputAudioGain
|
||||||
|
with Timer("all_inference_time") as t:
|
||||||
|
unpackedData = librosa.to_mono(indata.T) * 32768.0
|
||||||
|
unpackedData = unpackedData.astype(np.int16)
|
||||||
|
out_wav, times = self.serverDeviceCallbacks.on_request(unpackedData)
|
||||||
|
self.out_wav = out_wav
|
||||||
|
self.mon_wav = out_wav
|
||||||
|
all_inference_time = t.secs
|
||||||
|
self.performance = [all_inference_time] + times
|
||||||
|
self.serverDeviceCallbacks.emitTo(self.performance)
|
||||||
|
self.performance = [round(x * 1000) for x in self.performance]
|
||||||
|
except Exception as e:
|
||||||
|
print("[Voice Changer][ServerDevice][audioInput_callback] ex:", e)
|
||||||
|
# import traceback
|
||||||
|
# traceback.print_exc()
|
||||||
|
|
||||||
|
def audioOutput_callback(self, outdata: np.ndarray, frames, times, status):
|
||||||
|
try:
|
||||||
|
if self.out_wav is None:
|
||||||
|
return
|
||||||
|
out_wav = self.out_wav
|
||||||
|
outputChannels = outdata.shape[1]
|
||||||
|
outdata[:] = np.repeat(out_wav, outputChannels).reshape(-1, outputChannels) / 32768.0
|
||||||
|
outdata[:] = outdata * self.settings.serverOutputAudioGain
|
||||||
|
except Exception as e:
|
||||||
|
print("[Voice Changer][ServerDevice][audioOutput_callback] ex:", e)
|
||||||
|
# import traceback
|
||||||
|
# traceback.print_exc()
|
||||||
|
|
||||||
|
def audioMonitor_callback(self, outdata: np.ndarray, frames, times, status):
|
||||||
|
try:
|
||||||
|
if self.mon_wav is None:
|
||||||
|
return
|
||||||
|
mon_wav = self.mon_wav
|
||||||
|
outputChannels = outdata.shape[1]
|
||||||
|
outdata[:] = np.repeat(mon_wav, outputChannels).reshape(-1, outputChannels) / 32768.0
|
||||||
|
outdata[:] = outdata * self.settings.serverOutputAudioGain # GainはOutputのものをを流用
|
||||||
|
# Monitorモードが有効の場合はサンプリングレートはmonitorデバイスが優先されているためリサンプリング不要
|
||||||
|
except Exception as e:
|
||||||
|
print("[Voice Changer][ServerDevice][audioMonitor_callback] ex:", e)
|
||||||
|
# import traceback
|
||||||
|
# traceback.print_exc()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
currentModelSamplingRate = -1
|
||||||
|
while True:
|
||||||
|
if self.settings.serverAudioStated == 0 or self.settings.serverInputDeviceId == -1:
|
||||||
|
time.sleep(2)
|
||||||
|
else:
|
||||||
|
sd._terminate()
|
||||||
|
sd._initialize()
|
||||||
|
|
||||||
|
# Curret Device ID
|
||||||
|
currentServerInputDeviceId = self.settings.serverInputDeviceId
|
||||||
|
currentServerOutputDeviceId = self.settings.serverOutputDeviceId
|
||||||
|
currentServerMonitorDeviceId = self.settings.serverMonitorDeviceId
|
||||||
|
|
||||||
|
# Device 特定
|
||||||
|
serverInputAudioDevice = self.getServerInputAudioDevice(self.settings.serverInputDeviceId)
|
||||||
|
serverOutputAudioDevice = self.getServerOutputAudioDevice(self.settings.serverOutputDeviceId)
|
||||||
|
serverMonitorAudioDevice = None
|
||||||
|
if self.settings.serverMonitorDeviceId != -1:
|
||||||
|
serverMonitorAudioDevice = self.getServerOutputAudioDevice(self.settings.serverMonitorDeviceId)
|
||||||
|
|
||||||
|
# Generate ExtraSetting
|
||||||
|
inputExtraSetting = None
|
||||||
|
outputExtraSetting = None
|
||||||
|
if self.settings.exclusiveMode:
|
||||||
|
if "WASAPI" in serverInputAudioDevice.hostAPI:
|
||||||
|
inputExtraSetting = sd.WasapiSettings(exclusive=True)
|
||||||
|
if "WASAPI" in serverOutputAudioDevice.hostAPI:
|
||||||
|
outputExtraSetting = sd.WasapiSettings(exclusive=True)
|
||||||
|
monitorExtraSetting = None
|
||||||
|
if self.settings.exclusiveMode and serverMonitorAudioDevice is not None:
|
||||||
|
if "WASAPI" in serverMonitorAudioDevice.hostAPI:
|
||||||
|
monitorExtraSetting = sd.WasapiSettings(exclusive=True)
|
||||||
|
|
||||||
|
print("Devices:")
|
||||||
|
print(" [Input]:", serverInputAudioDevice, inputExtraSetting)
|
||||||
|
print(" [Output]:", serverOutputAudioDevice, outputExtraSetting)
|
||||||
|
print(" [Monitor]:", serverMonitorAudioDevice, monitorExtraSetting)
|
||||||
|
|
||||||
|
# Deviceがなかったらいったんスリープ
|
||||||
|
if serverInputAudioDevice is None or serverOutputAudioDevice is None:
|
||||||
|
print("serverInputAudioDevice or serverOutputAudioDevice is None")
|
||||||
|
time.sleep(2)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# サンプリングレート
|
||||||
|
# 同一サンプリングレートに統一(変換時にサンプルが不足する場合があるため。パディング方法が明らかになれば、それぞれ設定できるかも)
|
||||||
|
currentAudioSampleRate = self.settings.serverAudioSampleRate
|
||||||
|
try:
|
||||||
|
currentModelSamplingRate = self.serverDeviceCallbacks.get_processing_sampling_rate()
|
||||||
|
except Exception as e:
|
||||||
|
print("[Voice Changer] ex: get_processing_sampling_rate", e)
|
||||||
|
time.sleep(2)
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.settings.serverInputAudioSampleRate = currentAudioSampleRate
|
||||||
|
self.settings.serverOutputAudioSampleRate = currentAudioSampleRate
|
||||||
|
self.settings.serverMonitorAudioSampleRate = currentAudioSampleRate
|
||||||
|
|
||||||
|
# Sample Rate Check
|
||||||
|
inputAudioSampleRateAvailable = checkSamplingRate(self.settings.serverInputDeviceId, self.settings.serverInputAudioSampleRate, "input")
|
||||||
|
outputAudioSampleRateAvailable = checkSamplingRate(self.settings.serverOutputDeviceId, self.settings.serverOutputAudioSampleRate, "output")
|
||||||
|
monitorAudioSampleRateAvailable = checkSamplingRate(self.settings.serverMonitorDeviceId, self.settings.serverMonitorAudioSampleRate, "output") if serverMonitorAudioDevice else True
|
||||||
|
|
||||||
|
print("Sample Rate:")
|
||||||
|
print(f" [Model]: {currentModelSamplingRate}")
|
||||||
|
print(f" [Input]: {self.settings.serverInputAudioSampleRate} -> {inputAudioSampleRateAvailable}")
|
||||||
|
print(f" [Output]: {self.settings.serverOutputAudioSampleRate} -> {outputAudioSampleRateAvailable}")
|
||||||
|
if serverMonitorAudioDevice is not None:
|
||||||
|
print(f" [Monitor]: {self.settings.serverMonitorAudioSampleRate} -> {monitorAudioSampleRateAvailable}")
|
||||||
|
|
||||||
|
if inputAudioSampleRateAvailable and outputAudioSampleRateAvailable and monitorAudioSampleRateAvailable:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print("Sample Rate is not supported by device:")
|
||||||
|
print("Checking Available Sample Rate:")
|
||||||
|
availableInputSampleRate = []
|
||||||
|
availableOutputSampleRate = []
|
||||||
|
availableMonitorSampleRate = []
|
||||||
|
for sr in SERVER_DEVICE_SAMPLE_RATES:
|
||||||
|
if checkSamplingRate(self.settings.serverInputDeviceId, sr, "input"):
|
||||||
|
availableInputSampleRate.append(sr)
|
||||||
|
if checkSamplingRate(self.settings.serverOutputDeviceId, sr, "output"):
|
||||||
|
availableOutputSampleRate.append(sr)
|
||||||
|
if serverMonitorAudioDevice is not None:
|
||||||
|
if checkSamplingRate(self.settings.serverMonitorDeviceId, sr, "output"):
|
||||||
|
availableMonitorSampleRate.append(sr)
|
||||||
|
print("Available Sample Rate:")
|
||||||
|
print(f" [Input]: {availableInputSampleRate}")
|
||||||
|
print(f" [Output]: {availableOutputSampleRate}")
|
||||||
|
if serverMonitorAudioDevice is not None:
|
||||||
|
print(f" [Monitor]: {availableMonitorSampleRate}")
|
||||||
|
|
||||||
|
print("continue... ")
|
||||||
|
time.sleep(2)
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.serverDeviceCallbacks.setInputSamplingRate(self.settings.serverInputAudioSampleRate)
|
||||||
|
self.serverDeviceCallbacks.setOutputSamplingRate(self.settings.serverOutputAudioSampleRate)
|
||||||
|
|
||||||
|
# Blockサイズを計算
|
||||||
|
currentInputChunkNum = self.settings.serverReadChunkSize
|
||||||
|
block_frame = currentInputChunkNum * 128
|
||||||
|
sd.default.blocksize = block_frame
|
||||||
|
|
||||||
|
# main loop
|
||||||
|
try:
|
||||||
|
with sd.InputStream(
|
||||||
|
callback=self.audioInput_callback,
|
||||||
|
dtype="float32",
|
||||||
|
device=self.settings.serverInputDeviceId,
|
||||||
|
blocksize=block_frame,
|
||||||
|
samplerate=self.settings.serverInputAudioSampleRate,
|
||||||
|
channels=serverInputAudioDevice.maxInputChannels,
|
||||||
|
extra_settings=inputExtraSetting
|
||||||
|
):
|
||||||
|
with sd.OutputStream(
|
||||||
|
callback=self.audioOutput_callback,
|
||||||
|
dtype="float32",
|
||||||
|
device=self.settings.serverOutputDeviceId,
|
||||||
|
blocksize=block_frame,
|
||||||
|
samplerate=self.settings.serverOutputAudioSampleRate,
|
||||||
|
channels=serverOutputAudioDevice.maxOutputChannels,
|
||||||
|
extra_settings=outputExtraSetting
|
||||||
|
):
|
||||||
|
if self.settings.serverMonitorDeviceId != -1:
|
||||||
|
with sd.OutputStream(
|
||||||
|
callback=self.audioMonitor_callback,
|
||||||
|
dtype="float32",
|
||||||
|
device=self.settings.serverMonitorDeviceId,
|
||||||
|
blocksize=block_frame,
|
||||||
|
samplerate=self.settings.serverMonitorAudioSampleRate,
|
||||||
|
channels=serverMonitorAudioDevice.maxOutputChannels,
|
||||||
|
extra_settings=monitorExtraSetting
|
||||||
|
):
|
||||||
|
while (
|
||||||
|
self.settings.serverAudioStated == 1 and
|
||||||
|
currentServerInputDeviceId == self.settings.serverInputDeviceId and
|
||||||
|
currentServerOutputDeviceId == self.settings.serverOutputDeviceId and
|
||||||
|
currentServerMonitorDeviceId == self.settings.serverMonitorDeviceId and
|
||||||
|
currentModelSamplingRate == self.serverDeviceCallbacks.get_processing_sampling_rate() and
|
||||||
|
currentInputChunkNum == self.settings.serverReadChunkSize and
|
||||||
|
currentAudioSampleRate == self.settings.serverAudioSampleRate
|
||||||
|
):
|
||||||
|
time.sleep(2)
|
||||||
|
print(f"[Voice Changer] server audio performance {self.performance}")
|
||||||
|
print(f" status: started:{self.settings.serverAudioStated}, model_sr:{currentModelSamplingRate}, chunk:{currentInputChunkNum}")
|
||||||
|
print(f" input : id:{self.settings.serverInputDeviceId}, sr:{self.settings.serverInputAudioSampleRate}, ch:{serverInputAudioDevice.maxInputChannels}")
|
||||||
|
print(f" output : id:{self.settings.serverOutputDeviceId}, sr:{self.settings.serverOutputAudioSampleRate}, ch:{serverOutputAudioDevice.maxOutputChannels}")
|
||||||
|
print(f" monitor: id:{self.settings.serverMonitorDeviceId}, sr:{self.settings.serverMonitorAudioSampleRate}, ch:{serverMonitorAudioDevice.maxOutputChannels}")
|
||||||
|
else:
|
||||||
|
while (
|
||||||
|
self.settings.serverAudioStated == 1 and
|
||||||
|
currentServerInputDeviceId == self.settings.serverInputDeviceId and
|
||||||
|
currentServerOutputDeviceId == self.settings.serverOutputDeviceId and
|
||||||
|
currentServerMonitorDeviceId == self.settings.serverMonitorDeviceId and
|
||||||
|
currentModelSamplingRate == self.serverDeviceCallbacks.get_processing_sampling_rate() and
|
||||||
|
currentInputChunkNum == self.settings.serverReadChunkSize and
|
||||||
|
currentAudioSampleRate == self.settings.serverAudioSampleRate
|
||||||
|
):
|
||||||
|
time.sleep(2)
|
||||||
|
print(f"[Voice Changer] server audio performance {self.performance}")
|
||||||
|
print(f" status: started:{self.settings.serverAudioStated}, model_sr:{currentModelSamplingRate}, chunk:{currentInputChunkNum}]")
|
||||||
|
print(f" input : id:{self.settings.serverInputDeviceId}, sr:{self.settings.serverInputAudioSampleRate}, ch:{serverInputAudioDevice.maxInputChannels}")
|
||||||
|
print(f" output : id:{self.settings.serverOutputDeviceId}, sr:{self.settings.serverOutputAudioSampleRate}, ch:{serverOutputAudioDevice.maxOutputChannels}")
|
||||||
|
except Exception as e:
|
||||||
|
print("[Voice Changer] processing, ex:", e)
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
def start2(self):
|
||||||
# currentInputDeviceId = -1
|
# currentInputDeviceId = -1
|
||||||
# currentOutputDeviceId = -1
|
# currentOutputDeviceId = -1
|
||||||
# currentInputChunkNum = -1
|
# currentInputChunkNum = -1
|
||||||
@ -140,13 +379,15 @@ class ServerDevice:
|
|||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
self.settings.serverInputAudioSampleRate = currentModelSamplingRate
|
self.settings.serverInputAudioSampleRate = currentModelSamplingRate
|
||||||
self.serverDeviceCallbacks.setSamplingRate(currentModelSamplingRate)
|
self.serverDeviceCallbacks.setInputSamplingRate(currentModelSamplingRate)
|
||||||
|
self.serverDeviceCallbacks.setOutputSamplingRate(currentModelSamplingRate)
|
||||||
print(f"[Voice Changer] sample rate {self.settings.serverInputAudioSampleRate}")
|
print(f"[Voice Changer] sample rate {self.settings.serverInputAudioSampleRate}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("[Voice Changer] ex: fallback to device default samplerate", e)
|
print("[Voice Changer] ex: fallback to device default samplerate", e)
|
||||||
print("[Voice Changer] device default samplerate", serverInputAudioDevice.default_samplerate)
|
print("[Voice Changer] device default samplerate", serverInputAudioDevice.default_samplerate)
|
||||||
self.settings.serverInputAudioSampleRate = round(serverInputAudioDevice.default_samplerate)
|
self.settings.serverInputAudioSampleRate = round(serverInputAudioDevice.default_samplerate)
|
||||||
self.serverDeviceCallbacks.setSamplingRate(round(serverInputAudioDevice.default_samplerate))
|
self.serverDeviceCallbacks.setInputSamplingRate(round(serverInputAudioDevice.default_samplerate))
|
||||||
|
self.serverDeviceCallbacks.setOutputSamplingRate(round(serverInputAudioDevice.default_samplerate))
|
||||||
|
|
||||||
sd.default.samplerate = self.settings.serverInputAudioSampleRate
|
sd.default.samplerate = self.settings.serverInputAudioSampleRate
|
||||||
sd.default.blocksize = block_frame
|
sd.default.blocksize = block_frame
|
||||||
@ -171,10 +412,15 @@ class ServerDevice:
|
|||||||
|
|
||||||
def get_info(self):
|
def get_info(self):
|
||||||
data = asdict(self.settings)
|
data = asdict(self.settings)
|
||||||
audioinput, audiooutput = list_audio_device()
|
try:
|
||||||
data["serverAudioInputDevices"] = audioinput
|
audioinput, audiooutput = list_audio_device()
|
||||||
data["serverAudioOutputDevices"] = audiooutput
|
self.serverAudioInputDevices = audioinput
|
||||||
|
self.serverAudioOutputDevices = audiooutput
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
data["serverAudioInputDevices"] = self.serverAudioInputDevices
|
||||||
|
data["serverAudioOutputDevices"] = self.serverAudioOutputDevices
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def update_settings(self, key: str, val: str | int | float):
|
def update_settings(self, key: str, val: str | int | float):
|
||||||
|
@ -77,7 +77,7 @@ class DeviceManager(object):
|
|||||||
def getDeviceMemory(self, id: int):
|
def getDeviceMemory(self, id: int):
|
||||||
try:
|
try:
|
||||||
return torch.cuda.get_device_properties(id).total_memory
|
return torch.cuda.get_device_properties(id).total_memory
|
||||||
# except Exception as e:
|
except Exception as e:
|
||||||
except:
|
# except:
|
||||||
# print(e)
|
print(e)
|
||||||
return 0
|
return 0
|
||||||
|
@ -13,7 +13,7 @@ from voice_changer.IORecorder import IORecorder
|
|||||||
from voice_changer.utils.LoadModelParams import LoadModelParams
|
from voice_changer.utils.LoadModelParams import LoadModelParams
|
||||||
|
|
||||||
from voice_changer.utils.Timer import Timer
|
from voice_changer.utils.Timer import Timer
|
||||||
from voice_changer.utils.VoiceChangerModel import AudioInOut
|
from voice_changer.utils.VoiceChangerModel import AudioInOut, VoiceChangerModel
|
||||||
from Exceptions import (
|
from Exceptions import (
|
||||||
DeviceCannotSupportHalfPrecisionException,
|
DeviceCannotSupportHalfPrecisionException,
|
||||||
DeviceChangingException,
|
DeviceChangingException,
|
||||||
@ -32,6 +32,7 @@ STREAM_OUTPUT_FILE = os.path.join(TMP_DIR, "out.wav")
|
|||||||
@dataclass
|
@dataclass
|
||||||
class VoiceChangerSettings:
|
class VoiceChangerSettings:
|
||||||
inputSampleRate: int = 48000 # 48000 or 24000
|
inputSampleRate: int = 48000 # 48000 or 24000
|
||||||
|
outputSampleRate: int = 48000 # 48000 or 24000
|
||||||
|
|
||||||
crossFadeOffsetRate: float = 0.1
|
crossFadeOffsetRate: float = 0.1
|
||||||
crossFadeEndRate: float = 0.9
|
crossFadeEndRate: float = 0.9
|
||||||
@ -71,7 +72,7 @@ class VoiceChanger:
|
|||||||
self.currentCrossFadeOverlapSize = 0 # setting
|
self.currentCrossFadeOverlapSize = 0 # setting
|
||||||
self.crossfadeSize = 0 # calculated
|
self.crossfadeSize = 0 # calculated
|
||||||
|
|
||||||
self.voiceChanger = None
|
self.voiceChanger: VoiceChangerModel | None = None
|
||||||
self.modelType: ModelType | None = None
|
self.modelType: ModelType | None = None
|
||||||
self.params = params
|
self.params = params
|
||||||
self.gpu_num = torch.cuda.device_count()
|
self.gpu_num = torch.cuda.device_count()
|
||||||
@ -115,6 +116,7 @@ class VoiceChanger:
|
|||||||
|
|
||||||
if key == "serverAudioStated" and val == 0:
|
if key == "serverAudioStated" and val == 0:
|
||||||
self.settings.inputSampleRate = 48000
|
self.settings.inputSampleRate = 48000
|
||||||
|
self.settings.outputSampleRate = 48000
|
||||||
|
|
||||||
if key in self.settings.intData:
|
if key in self.settings.intData:
|
||||||
setattr(self.settings, key, int(val))
|
setattr(self.settings, key, int(val))
|
||||||
@ -123,7 +125,7 @@ class VoiceChanger:
|
|||||||
if key == "recordIO" and val == 1:
|
if key == "recordIO" and val == 1:
|
||||||
if hasattr(self, "ioRecorder"):
|
if hasattr(self, "ioRecorder"):
|
||||||
self.ioRecorder.close()
|
self.ioRecorder.close()
|
||||||
self.ioRecorder = IORecorder(STREAM_INPUT_FILE, STREAM_OUTPUT_FILE, self.settings.inputSampleRate)
|
self.ioRecorder = IORecorder(STREAM_INPUT_FILE, STREAM_OUTPUT_FILE, self.settings.inputSampleRate, self.settings.outputSampleRate)
|
||||||
if key == "recordIO" and val == 0:
|
if key == "recordIO" and val == 0:
|
||||||
if hasattr(self, "ioRecorder"):
|
if hasattr(self, "ioRecorder"):
|
||||||
self.ioRecorder.close()
|
self.ioRecorder.close()
|
||||||
@ -268,10 +270,10 @@ class VoiceChanger:
|
|||||||
# 後処理
|
# 後処理
|
||||||
with Timer("post-process") as t:
|
with Timer("post-process") as t:
|
||||||
result = result.astype(np.int16)
|
result = result.astype(np.int16)
|
||||||
if self.settings.inputSampleRate != processing_sampling_rate:
|
if self.settings.outputSampleRate != processing_sampling_rate:
|
||||||
# print(
|
# print(
|
||||||
# "samplingrate",
|
# "output samplingrate",
|
||||||
# self.settings.inputSampleRate,
|
# self.settings.outputSampleRate,
|
||||||
# processing_sampling_rate,
|
# processing_sampling_rate,
|
||||||
# )
|
# )
|
||||||
outputData = cast(
|
outputData = cast(
|
||||||
@ -279,13 +281,13 @@ class VoiceChanger:
|
|||||||
resampy.resample(
|
resampy.resample(
|
||||||
result,
|
result,
|
||||||
processing_sampling_rate,
|
processing_sampling_rate,
|
||||||
self.settings.inputSampleRate,
|
self.settings.outputSampleRate,
|
||||||
).astype(np.int16),
|
).astype(np.int16),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
outputData = result
|
outputData = result
|
||||||
|
|
||||||
print_convert_processing(f" Output data size of {result.shape[0]}/{processing_sampling_rate}hz {outputData.shape[0]}/{self.settings.inputSampleRate}hz")
|
print_convert_processing(f" Output data size of {result.shape[0]}/{processing_sampling_rate}hz {outputData.shape[0]}/{self.settings.outputSampleRate}hz")
|
||||||
|
|
||||||
if receivedData.shape[0] != outputData.shape[0]:
|
if receivedData.shape[0] != outputData.shape[0]:
|
||||||
# print(
|
# print(
|
||||||
|
@ -50,9 +50,12 @@ class VoiceChangerManager(ServerDeviceCallbacks):
|
|||||||
def get_processing_sampling_rate(self):
|
def get_processing_sampling_rate(self):
|
||||||
return self.voiceChanger.get_processing_sampling_rate()
|
return self.voiceChanger.get_processing_sampling_rate()
|
||||||
|
|
||||||
def setSamplingRate(self, sr: int):
|
def setInputSamplingRate(self, sr: int):
|
||||||
self.voiceChanger.settings.inputSampleRate = sr
|
self.voiceChanger.settings.inputSampleRate = sr
|
||||||
|
|
||||||
|
def setOutputSamplingRate(self, sr: int):
|
||||||
|
self.voiceChanger.settings.outputSampleRate = sr
|
||||||
|
|
||||||
############################
|
############################
|
||||||
# VoiceChangerManager
|
# VoiceChangerManager
|
||||||
############################
|
############################
|
||||||
@ -78,7 +81,7 @@ class VoiceChangerManager(ServerDeviceCallbacks):
|
|||||||
self.update_settings(key, val)
|
self.update_settings(key, val)
|
||||||
|
|
||||||
def store_setting(self, key: str, val: str | int | float):
|
def store_setting(self, key: str, val: str | int | float):
|
||||||
saveItemForServerDevice = ["enableServerAudio", "serverInputDeviceId", "serverOutputDeviceId", "serverReadChunkSize", "serverInputAudioGain", "serverOutputAudioGain"]
|
saveItemForServerDevice = ["enableServerAudio", "serverAudioSampleRate", "serverInputDeviceId", "serverOutputDeviceId", "serverMonitorDeviceId", "serverReadChunkSize", "serverInputAudioGain", "serverOutputAudioGain"]
|
||||||
saveItemForVoiceChanger = ["crossFadeOffsetRate", "crossFadeEndRate", "crossFadeOverlapSize"]
|
saveItemForVoiceChanger = ["crossFadeOffsetRate", "crossFadeEndRate", "crossFadeOverlapSize"]
|
||||||
saveItemForVoiceChangerManager = ["modelSlotIndex"]
|
saveItemForVoiceChangerManager = ["modelSlotIndex"]
|
||||||
saveItemForRVC = ["extraConvertSize", "gpu", "silentThreshold"]
|
saveItemForRVC = ["extraConvertSize", "gpu", "silentThreshold"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user