WIPsilent skip

This commit is contained in:
wataru 2023-01-12 03:49:22 +09:00
parent fdb8e30382
commit ccd5111fd2
9 changed files with 94 additions and 23 deletions

File diff suppressed because one or more lines are too long

View File

@ -389,7 +389,7 @@ export const useClient = (props: UseClientProps): ClientState => {
srcId: serverInfo.srcId, srcId: serverInfo.srcId,
dstId: serverInfo.dstId, dstId: serverInfo.dstId,
framework: serverInfo.framework, framework: serverInfo.framework,
onnxExecutionProvider: serverInfo.providers.length > 0 ? serverInfo.providers[0] as OnnxExecutionProvider : "CPUExecutionProvider" onnxExecutionProvider: !!serverInfo.providers && serverInfo.providers.length > 0 ? serverInfo.providers[0] as OnnxExecutionProvider : "CPUExecutionProvider"
}) })
} else { } else {
setDisplaySettingState({ setDisplaySettingState({

View File

@ -0,0 +1,12 @@
export declare const RequestType: {
readonly voice: "voice";
readonly config: "config";
};
export type RequestType = typeof RequestType[keyof typeof RequestType];
export type VoiceChangerWorkletProcessorRequest = {
requestType: RequestType;
voice: ArrayBuffer;
numTrancateTreshold: number;
volTrancateThreshold: number;
volTrancateLength: number;
};

View File

@ -7,7 +7,7 @@ import { BufferSize, DefaultVoiceChangerOptions, Protocol, ServerSettingKey, Voi
import MicrophoneStream from "microphone-stream"; import MicrophoneStream from "microphone-stream";
import { AudioStreamer, Callbacks, AudioStreamerListeners } from "./AudioStreamer"; import { AudioStreamer, Callbacks, AudioStreamerListeners } from "./AudioStreamer";
import { ServerConfigurator } from "./ServerConfigurator"; import { ServerConfigurator } from "./ServerConfigurator";
import { VoiceChangerWorkletProcessorRequest } from "./@types/voice-changer-worklet-processor";
// オーディオデータの流れ // オーディオデータの流れ
// input node(mic or MediaStream) -> [vf node] -> microphne stream -> audio streamer -> // input node(mic or MediaStream) -> [vf node] -> microphne stream -> audio streamer ->
@ -39,7 +39,15 @@ export class VoiceChnagerClient {
onVoiceReceived: (voiceChangerMode: VoiceChangerMode, data: ArrayBuffer): void => { onVoiceReceived: (voiceChangerMode: VoiceChangerMode, data: ArrayBuffer): void => {
// console.log(voiceChangerMode, data) // console.log(voiceChangerMode, data)
if (voiceChangerMode === "realtime") { if (voiceChangerMode === "realtime") {
this.vcNode.postReceivedVoice(data) const req: VoiceChangerWorkletProcessorRequest = {
requestType: "voice",
voice: data,
numTrancateTreshold: 0,
volTrancateThreshold: 0,
volTrancateLength: 0
}
this.vcNode.postReceivedVoice(req)
return return
} }

View File

@ -1,3 +1,5 @@
import { VoiceChangerWorkletProcessorRequest } from "./@types/voice-changer-worklet-processor";
export type VolumeListener = { export type VolumeListener = {
notifyVolume: (vol: number) => void notifyVolume: (vol: number) => void
} }
@ -11,10 +13,10 @@ export class VoiceChangerWorkletNode extends AudioWorkletNode {
console.log(`[worklet_node][voice-changer-worklet-processor] created.`); console.log(`[worklet_node][voice-changer-worklet-processor] created.`);
} }
postReceivedVoice = (data: ArrayBuffer) => { postReceivedVoice = (req: VoiceChangerWorkletProcessorRequest) => {
this.port.postMessage({ this.port.postMessage({
data: data, request: req
}, [data]); }, [req.voice]);
} }
handleMessage(event: any) { handleMessage(event: any) {

View File

@ -1,7 +1,7 @@
// (★1) chunk sizeは 128サンプル, 256byte(int16)と定義。 // (★1) chunk sizeは 128サンプル, 256byte(int16)と定義。
// (★2) 256byte(最低バッファサイズ256から間引いた個数x2byte)をchunkとして管理。 // (★2) 256byte(最低バッファサイズ256から間引いた個数x2byte)をchunkとして管理。
// 24000sample -> 1sec, 128sample(1chunk) -> 5.333msec
// types // types
export type VoiceChangerRequestParamas = { export type VoiceChangerRequestParamas = {

View File

@ -29,6 +29,6 @@
"skipLibCheck": true "skipLibCheck": true
}, },
/* tsc */ /* tsc */
"include": ["src/*.ts"], "include": ["src/**/*.ts"],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }

View File

@ -2,6 +2,8 @@
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "ES2020",
"lib":["ES2020"], "lib":["ES2020"],
"outDir": "./worklet/dist",
"declaration": true,
/* */ /* */
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,

View File

@ -1,8 +1,26 @@
export const RequestType = {
"voice": "voice",
"config": "config"
} as const
export type RequestType = typeof RequestType[keyof typeof RequestType]
export type VoiceChangerWorkletProcessorRequest = {
requestType: RequestType,
voice: ArrayBuffer,
numTrancateTreshold: number
volTrancateThreshold: number
volTrancateLength: number
}
class VoiceChangerWorkletProcessor extends AudioWorkletProcessor { class VoiceChangerWorkletProcessor extends AudioWorkletProcessor {
private BLOCK_SIZE = 128 private BLOCK_SIZE = 128
private initialized = false; private initialized = false;
private volume = 0 private volume = 0
private numTrancateTreshold = 50
private volTrancateThreshold = 0.0005
private volTrancateLength = 32
private volTrancateCount = 0
playBuffer: Float32Array[] = [] playBuffer: Float32Array[] = []
/** /**
* @constructor * @constructor
@ -13,9 +31,25 @@ class VoiceChangerWorkletProcessor extends AudioWorkletProcessor {
this.port.onmessage = this.handleMessage.bind(this); 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)
}
handleMessage(event: any) { handleMessage(event: any) {
// noop const request = event.data.request as VoiceChangerWorkletProcessorRequest
const arrayBuffer = event.data.data as ArrayBuffer if (request.requestType === "config") {
this.numTrancateTreshold = request.numTrancateTreshold
this.volTrancateLength = request.volTrancateLength
this.volTrancateThreshold = request.volTrancateThreshold
console.log("[worklet] worklet configured", request)
return
}
const arrayBuffer = request.voice
// データは(int16)で受信 // データは(int16)で受信
const i16Data = new Int16Array(arrayBuffer) const i16Data = new Int16Array(arrayBuffer)
const f32Data = new Float32Array(i16Data.length) const f32Data = new Float32Array(i16Data.length)
@ -25,7 +59,7 @@ class VoiceChangerWorkletProcessor extends AudioWorkletProcessor {
f32Data[i] = float f32Data[i] = float
}) })
if (this.playBuffer.length > 50) { if (this.playBuffer.length > this.numTrancateTreshold) {
console.log("[worklet] Buffer truncated") console.log("[worklet] Buffer truncated")
while (this.playBuffer.length > 2) { while (this.playBuffer.length > 2) {
this.playBuffer.shift() this.playBuffer.shift()
@ -58,23 +92,36 @@ class VoiceChangerWorkletProcessor extends AudioWorkletProcessor {
} }
if (this.playBuffer.length === 0) { if (this.playBuffer.length === 0) {
// console.log("[worklet] no play buffer") console.log("[worklet] no play buffer")
return true return true
} }
const data = this.playBuffer.shift()! //// 一定期間無音状態が続いている場合はスキップ。
let voice: Float32Array | undefined
const sum = data.reduce((prev, cur) => { while (true) {
return prev + cur * cur voice = this.playBuffer.shift()
}, 0) if (!voice) {
const rms = Math.sqrt(sum / data.length) break
}
this.volume = Math.max(rms, this.volume * 0.95) this.volume = this.calcVol(voice, this.volume)
this.port.postMessage({ volume: this.volume }); if (this.volume < this.volTrancateThreshold) {
this.volTrancateCount += 1
} else {
this.volTrancateCount = 0
}
if (this.volTrancateCount < this.volTrancateLength) {
break
} else {
console.log("silent...skip")
}
}
outputs[0][0].set(data) if (voice) {
this.port.postMessage({ volume: this.volume });
outputs[0][0].set(voice)
}
return true; return true;
} }