AnhP commited on
Commit
4fc8901
·
verified ·
1 Parent(s): 8385137

Update main/app/app.py

Browse files
Files changed (1) hide show
  1. main/app/app.py +519 -519
main/app/app.py CHANGED
@@ -1,520 +1,520 @@
1
- import os
2
- import io
3
- import ssl
4
- import sys
5
- import time
6
- import codecs
7
- import logging
8
- import warnings
9
-
10
- import gradio as gr
11
-
12
- sys.path.append(os.getcwd())
13
- start_time = time.time()
14
-
15
- from main.app.tabs.extra.extra import extra_tab
16
- from main.app.tabs.editing.editing import editing_tab
17
- from main.app.tabs.training.training import training_tab
18
- from main.app.tabs.downloads.downloads import download_tab
19
- from main.app.tabs.inference.inference import inference_tab
20
- from main.configs.rpc import connect_discord_ipc, send_discord_rpc
21
- from main.app.variables import logger, config, translations, theme, font, configs, language, allow_disk
22
-
23
- ssl._create_default_https_context = ssl._create_unverified_context
24
-
25
- warnings.filterwarnings("ignore")
26
- for l in ["httpx", "gradio", "uvicorn", "httpcore", "urllib3"]:
27
- logging.getLogger(l).setLevel(logging.ERROR)
28
-
29
- js_code = """
30
- () => {
31
- window._activeStream = null;
32
- window._audioCtx = null;
33
- window._workletNode = null;
34
- window._playbackNode = null;
35
- window._ws = null;
36
-
37
- function setStatus(msg, use_alert = true) {
38
- const realtimeStatus = document.querySelector("#realtime-status-info h2.output-class");
39
- if (use_alert) alert(msg);
40
-
41
- if (realtimeStatus) {
42
- realtimeStatus.innerText = msg;
43
- realtimeStatus.style.whiteSpace = "nowrap";
44
- realtimeStatus.style.textAlign = "center";
45
- }
46
- }
47
-
48
- async function addModuleFromString(ctx, codeStr) {
49
- const blob = new Blob([codeStr], {type: 'application/javascript'});
50
- const url = URL.createObjectURL(blob);
51
-
52
- await ctx.audioWorklet.addModule(url);
53
- URL.revokeObjectURL(url);
54
- };
55
-
56
- function createOutputRoute(audioCtx, playbackNode, sinkId, gainValue = 1.0) {
57
- const dest = audioCtx.createMediaStreamDestination();
58
- const gainNode = audioCtx.createGain();
59
- gainNode.gain.value = gainValue;
60
-
61
- playbackNode.connect(gainNode);
62
- gainNode.connect(dest);
63
-
64
- const el = document.createElement('audio');
65
- el.autoplay = true;
66
- el.srcObject = dest.stream;
67
- el.style.display = 'none';
68
- document.body.appendChild(el);
69
-
70
- if (el.setSinkId) el.setSinkId(sinkId).catch(err => console.error(err));
71
- return { dest, gainNode, el };
72
- }
73
-
74
- const inputWorkletSource = `
75
- class InputProcessor extends AudioWorkletProcessor {
76
- constructor() {
77
- super();
78
- this.buffer = new Float32Array(0);
79
- this.block_frame = 128;
80
- this.port.onmessage = (e) => {
81
- if (e.data && e.data.block_frame) this.block_frame = e.data.block_frame;
82
- };
83
- }
84
-
85
- process(inputs) {
86
- const input = inputs[0];
87
- if (!input || !input[0]) return true;
88
- const frame = input[0];
89
-
90
- const newBuf = new Float32Array(this.buffer.length + frame.length);
91
- newBuf.set(this.buffer, 0);
92
- newBuf.set(frame, this.buffer.length);
93
- this.buffer = newBuf;
94
-
95
- while (this.buffer.length >= this.block_frame) {
96
- const chunk = this.buffer.slice(0, this.block_frame);
97
-
98
- this.port.postMessage({chunk}, [chunk.buffer]);
99
- this.buffer = this.buffer.slice(this.block_frame);
100
- }
101
-
102
- return true;
103
- }
104
- }
105
- registerProcessor('input-processor', InputProcessor);
106
- `;
107
-
108
- const playbackWorkletSource = `
109
- class PlaybackProcessor extends AudioWorkletProcessor {
110
- constructor(options) {
111
- super(options);
112
- const bufferSize = options.processorOptions && options.processorOptions.bufferSize ? options.processorOptions.bufferSize: 98304;
113
- this.buffer = new Float32Array(bufferSize);
114
- this.bufferCapacity = bufferSize;
115
- this.writePointer = 0;
116
- this.readPointer = 0;
117
- this.availableSamples = 0;
118
- this.port.onmessage = (e) => {
119
- if (e.data && e.data.chunk) {
120
- const chunk = new Float32Array(e.data.chunk);
121
- const chunkSize = chunk.length;
122
-
123
- if (this.availableSamples + chunkSize > this.bufferCapacity) return;
124
-
125
- for (let i = 0; i < chunkSize; i++) {
126
- this.buffer[this.writePointer] = chunk[i];
127
- this.writePointer = (this.writePointer + 1) % this.bufferCapacity;
128
- }
129
-
130
- this.availableSamples += chunkSize;
131
- }
132
- };
133
- }
134
-
135
- process(inputs, outputs) {
136
- const output = outputs[0];
137
- if (!output || !output[0]) return true;
138
-
139
- const frame = output[0];
140
- const frameSize = frame.length;
141
-
142
- if (this.availableSamples >= frameSize) {
143
- for (let i = 0; i < frameSize; i++) {
144
- frame[i] = this.buffer[this.readPointer];
145
- this.readPointer = (this.readPointer + 1) % this.bufferCapacity;
146
- }
147
- this.availableSamples -= frameSize;
148
- } else {
149
- frame.fill(0);
150
- }
151
-
152
- if (output.length > 1) output[1].set(output[0]);
153
- return true;
154
- }
155
- }
156
- registerProcessor('playback-processor', PlaybackProcessor);
157
- `;
158
-
159
- window.getAudioDevices = async function() {
160
- if (!navigator.mediaDevices) {
161
- setStatus("__MEDIA_DEVICES__");
162
- return {"inputs": [], "outputs": []};
163
- }
164
-
165
- try {
166
- await navigator.mediaDevices.getUserMedia({ audio: true });
167
- } catch (err) {
168
- console.error(err);
169
- setStatus("__MIC_INACCESSIBLE__")
170
-
171
- return {"inputs": [], "outputs": []};
172
- }
173
-
174
- const devices = await navigator.mediaDevices.enumerateDevices();
175
- const inputs = [];
176
- const outputs = [];
177
-
178
- for (const device of devices) {
179
- if (device.kind === "audioinput") {
180
- inputs.push([device.label, device.deviceId])
181
- } else if (device.kind === "audiooutput") {
182
- outputs.push([device.label, device.deviceId])
183
- }
184
- }
185
-
186
- if (!inputs.length && !outputs.length) return {"inputs": [], "outputs": []};
187
- return {"inputs": inputs, "outputs": outputs};
188
- };
189
-
190
- window.StreamAudioRealtime = async function(
191
- monitor,
192
- vad_enabled,
193
- input_audio_device,
194
- output_audio_device,
195
- monitor_output_device,
196
- input_audio_gain,
197
- output_audio_gain,
198
- monitor_audio_gain,
199
- chunk_size,
200
- pitch,
201
- model_pth,
202
- model_index,
203
- index_strength,
204
- onnx_f0_mode,
205
- f0_method,
206
- hop_length,
207
- embed_mode,
208
- embedders,
209
- custom_embedders,
210
- f0_autotune,
211
- proposal_pitch,
212
- f0_autotune_strength,
213
- proposal_pitch_threshold,
214
- rms_mix_rate,
215
- protect,
216
- filter_radius,
217
- silent_threshold,
218
- extra_convert_size,
219
- cross_fade_overlap_size,
220
- vad_sensitivity,
221
- vad_frame_ms,
222
- clean_audio,
223
- clean_strength
224
- ) {
225
- const SampleRate = 48000;
226
- const ReadChunkSize = Math.round(chunk_size * SampleRate / 1000 / 128);
227
- const block_frame = parseInt(ReadChunkSize) * 128;
228
- const ButtonState = { start_button: true, stop_button: false };
229
-
230
- try {
231
-
232
- if (!input_audio_device || !output_audio_device) {
233
- setStatus("__PROVIDE_AUDIO_DEVICE__");
234
- return ButtonState;
235
- }
236
-
237
- if (monitor && !monitor_output_device) {
238
- setStatus("__PROVIDE_MONITOR_DEVICE__");
239
- return ButtonState;
240
- }
241
-
242
- if (!model_pth) {
243
- setStatus("__PROVIDE_MODEL__")
244
- return ButtonState;
245
- }
246
-
247
- setStatus("__START_REALTIME__", use_alert=false)
248
-
249
- const stream = await navigator.mediaDevices.getUserMedia({
250
- audio: {
251
- deviceId: { exact: input_audio_device },
252
- channelCount: 1,
253
- sampleRate: SampleRate,
254
- echoCancellation: false,
255
- noiseSuppression: false,
256
- autoGainControl: false
257
- }
258
- });
259
-
260
- window._activeStream = stream;
261
- window._audioCtx = new AudioContext({ sampleRate: SampleRate, latencyHint: "interactive" });
262
-
263
- await addModuleFromString(window._audioCtx, inputWorkletSource);
264
- await addModuleFromString(window._audioCtx, playbackWorkletSource);
265
-
266
- const src = window._audioCtx.createMediaStreamSource(stream);
267
- const inputNode = new AudioWorkletNode(window._audioCtx, 'input-processor');
268
- const playbackNode = new AudioWorkletNode(window._audioCtx, 'playback-processor', {
269
- processorOptions: {
270
- bufferSize: block_frame * 2
271
- }
272
- });
273
-
274
- inputNode.port.postMessage({ block_frame: block_frame });
275
- src.connect(inputNode);
276
-
277
- createOutputRoute(window._audioCtx, playbackNode, output_audio_device, output_audio_gain / 100);
278
- if (monitor && monitor_output_device) createOutputRoute(window._audioCtx, playbackNode, monitor_output_device, monitor_audio_gain / 100);
279
-
280
- const protocol = (location.protocol === "https:") ? "wss:" : "ws:";
281
- const wsUrl = protocol + '//' + location.hostname + `:${location.port}` + '/api/ws-audio';
282
- const ws = new WebSocket(wsUrl);
283
-
284
- ButtonState.start_button = false;
285
- ButtonState.stop_button = true;
286
-
287
- ws.binaryType = "arraybuffer";
288
- window._ws = ws;
289
-
290
- ws.onopen = () => {
291
- console.log("__WS_CONNECTED__")
292
-
293
- ws.send(
294
- JSON.stringify({
295
- type: 'init',
296
- chunk_size: ReadChunkSize,
297
- embedders: embedders,
298
- model_pth: model_pth,
299
- custom_embedders: custom_embedders,
300
- cross_fade_overlap_size: cross_fade_overlap_size,
301
- extra_convert_size: extra_convert_size,
302
- model_index: model_index,
303
- f0_method: f0_method,
304
- f0_onnx: onnx_f0_mode,
305
- embedders_mode: embed_mode,
306
- hop_length: hop_length,
307
- silent_threshold: silent_threshold,
308
- vad_enabled: vad_enabled,
309
- vad_sensitivity: vad_sensitivity,
310
- vad_frame_ms: vad_frame_ms,
311
- clean_audio: clean_audio,
312
- clean_strength: clean_strength,
313
- f0_up_key: pitch,
314
- index_rate: index_strength,
315
- protect: protect,
316
- filter_radius: filter_radius,
317
- rms_mix_rate: rms_mix_rate,
318
- f0_autotune: f0_autotune,
319
- f0_autotune_strength: f0_autotune_strength,
320
- proposal_pitch: proposal_pitch,
321
- proposal_pitch_threshold: proposal_pitch_threshold,
322
- input_audio_gain: input_audio_gain
323
- })
324
- );
325
- };
326
-
327
- inputNode.port.onmessage = (e) => {
328
- const chunk = e.data && e.data.chunk;
329
-
330
- if (!chunk) return;
331
- if (ws.readyState === WebSocket.OPEN) ws.send(chunk);
332
- };
333
-
334
- ws.onmessage = (ev) => {
335
- if (typeof ev.data === 'string') {
336
- const msg = JSON.parse(ev.data);
337
-
338
- if (msg.type === 'latency') setStatus(`__LATENCY__: ${msg.value.toFixed(1)} ms`, use_alert=false)
339
- if (msg.type === 'warnings') {
340
- setStatus(msg.value);
341
- StopAudioStream();
342
- }
343
-
344
- return;
345
- }
346
-
347
- const ab = ev.data;
348
- playbackNode.port.postMessage({ chunk: ab }, [ab]);
349
- };
350
-
351
- ws.onclose = () => console.log("__WS_CLOSED__");
352
- window._workletNode = inputNode;
353
- window._playbackNode = playbackNode;
354
-
355
- if (window._audioCtx.state === 'suspended') await window._audioCtx.resume();
356
-
357
- console.log("__REALTIME_STARTED__");
358
- return ButtonState;
359
- } catch (err) {
360
- console.error("__ERROR__", err);
361
- alert("__ERROR__" + err.message);
362
-
363
- return StopAudioStream();
364
- }
365
- };
366
-
367
- window.StopAudioStream = async function() {
368
- try {
369
- if (window._ws) {
370
- window._ws.close();
371
- window._ws = null;
372
- }
373
-
374
- if (window._activeStream) {
375
- window._activeStream.getTracks().forEach(t => t.stop());
376
- window._activeStream = null;
377
- }
378
-
379
- if (window._workletNode) {
380
- window._workletNode.disconnect();
381
- window._workletNode = null;
382
- }
383
-
384
- if (window._playbackNode) {
385
- window._playbackNode.disconnect();
386
- window._playbackNode = null;
387
- }
388
-
389
- if (window._audioCtx) {
390
- await window._audioCtx.close();
391
- window._audioCtx = null;
392
- }
393
-
394
- document.querySelectorAll('audio').forEach(a => a.remove());
395
- setStatus("__REALTIME_HAS_STOP__", use_alert=false);
396
-
397
- return {"start_button": true, "stop_button": false};
398
- } catch (e) {
399
- setStatus(`__ERROR__ ${e}`);
400
-
401
- return {"start_button": false, "stop_button": true}
402
- }
403
- };
404
- }
405
- """.replace(
406
- "__MEDIA_DEVICES__", translations["media_devices"]
407
- ).replace(
408
- "__MIC_INACCESSIBLE__", translations["mic_inaccessible"]
409
- ).replace(
410
- "__PROVIDE_AUDIO_DEVICE__", translations["provide_audio_device"]
411
- ).replace(
412
- "__PROVIDE_MONITOR_DEVICE__", translations["provide_monitor_device"]
413
- ).replace(
414
- "__START_REALTIME__", translations["start_realtime"]
415
- ).replace(
416
- "__LATENCY__", translations['latency']
417
- ).replace(
418
- "__WS_CONNECTED__", translations["ws_connected"]
419
- ).replace(
420
- "__WS_CLOSED__", translations["ws_closed"]
421
- ).replace(
422
- "__REALTIME_STARTED__", translations["realtime_is_ready"]
423
- ).replace(
424
- "__ERROR__", translations["error_occurred"].format(e="")
425
- ).replace(
426
- "__REALTIME_HAS_STOP__", translations["realtime_has_stop"]
427
- ).replace(
428
- "__PROVIDE_MODEL__", translations["provide_file"].format(filename=translations["model"])
429
- )
430
-
431
- client_mode = "--client" in sys.argv
432
-
433
- with gr.Blocks(
434
- title="📱 Vietnamese-RVC GUI BY ANH",
435
- js=js_code if client_mode else None,
436
- theme=theme,
437
- css="<style> @import url('{fonts}'); * {{font-family: 'Courgette', cursive !important;}} body, html {{font-family: 'Courgette', cursive !important;}} h1, h2, h3, h4, h5, h6, p, button, input, textarea, label, span, div, select {{font-family: 'Courgette', cursive !important;}} </style>".format(fonts=font or "https://fonts.googleapis.com/css2?family=Courgette&display=swap")
438
- ) as app:
439
- gr.HTML("<h1 style='text-align: center;'>🎵VIETNAMESE RVC BY ANH🎵</h1>")
440
- gr.HTML(f"<h3 style='text-align: center;'>{translations['title']}</h3>")
441
-
442
- with gr.Tabs():
443
- inference_tab()
444
- editing_tab()
445
-
446
- if client_mode:
447
- from main.app.tabs.realtime.realtime_client import realtime_client_tab
448
- realtime_client_tab()
449
- else:
450
- from main.app.tabs.realtime.realtime import realtime_tab
451
- realtime_tab()
452
-
453
- training_tab()
454
- download_tab()
455
- extra_tab(app)
456
-
457
- with gr.Row():
458
- gr.Markdown(translations["rick_roll"].format(rickroll=codecs.decode('uggcf://jjj.lbhghor.pbz/jngpu?i=qDj4j9JtKpD', 'rot13')))
459
-
460
- with gr.Row():
461
- gr.Markdown(translations["terms_of_use"])
462
-
463
- with gr.Row():
464
- gr.Markdown(translations["exemption"])
465
-
466
- if __name__ == "__main__":
467
- logger.info(config.device.replace("privateuseone", "dml"))
468
- logger.info(translations["start_app"])
469
- logger.info(translations["set_lang"].format(lang=language))
470
-
471
- port = configs.get("app_port", 7860)
472
- server_name = configs.get("server_name", "0.0.0.0")
473
- share = "--share" in sys.argv
474
-
475
- original_stdout = sys.stdout
476
- sys.stdout = io.StringIO()
477
-
478
- for i in range(configs.get("num_of_restart", 5)):
479
- try:
480
- gradio_app, _, share_url = app.queue().launch(
481
- favicon_path=configs["ico_path"],
482
- server_name=server_name,
483
- server_port=port,
484
- show_error=configs.get("app_show_error", False),
485
- inbrowser="--open" in sys.argv,
486
- share=share,
487
- allowed_paths=allow_disk,
488
- prevent_thread_lock=True,
489
- quiet=True
490
- )
491
- break
492
- except OSError:
493
- logger.debug(translations["port"].format(port=port))
494
- port -= 1
495
- except Exception as e:
496
- logger.error(translations["error_occurred"].format(e=e))
497
- sys.exit(1)
498
-
499
- if client_mode:
500
- from main.app.core.realtime_client import app as fastapi_app
501
- gradio_app.mount("/api", fastapi_app)
502
-
503
- sys.stdout = original_stdout
504
-
505
- if configs.get("discord_presence", True):
506
- pipe = connect_discord_ipc()
507
- if pipe:
508
- try:
509
- logger.info(translations["start_rpc"])
510
- send_discord_rpc(pipe)
511
- except KeyboardInterrupt:
512
- logger.info(translations["stop_rpc"])
513
- pipe.close()
514
-
515
- logger.info(f"{translations['running_local_url']}: {server_name}:{port}")
516
- if share: logger.info(f"{translations['running_share_url']}: {share_url}")
517
- logger.info(f"{translations['gradio_start']}: {(time.time() - start_time):.2f}s")
518
-
519
- while 1:
520
  time.sleep(5)
 
1
+ import os
2
+ import io
3
+ import ssl
4
+ import sys
5
+ import time
6
+ import codecs
7
+ import logging
8
+ import warnings
9
+
10
+ import gradio as gr
11
+
12
+ sys.path.append(os.getcwd())
13
+ start_time = time.time()
14
+
15
+ from main.app.tabs.extra.extra import extra_tab
16
+ from main.app.tabs.editing.editing import editing_tab
17
+ from main.app.tabs.training.training import training_tab
18
+ from main.app.tabs.downloads.downloads import download_tab
19
+ from main.app.tabs.inference.inference import inference_tab
20
+ from main.configs.rpc import connect_discord_ipc, send_discord_rpc
21
+ from main.app.variables import logger, config, translations, theme, font, configs, language, allow_disk
22
+
23
+ ssl._create_default_https_context = ssl._create_unverified_context
24
+
25
+ warnings.filterwarnings("ignore")
26
+ for l in ["httpx", "gradio", "uvicorn", "httpcore", "urllib3"]:
27
+ logging.getLogger(l).setLevel(logging.ERROR)
28
+
29
+ js_code = """
30
+ () => {
31
+ window._activeStream = null;
32
+ window._audioCtx = null;
33
+ window._workletNode = null;
34
+ window._playbackNode = null;
35
+ window._ws = null;
36
+
37
+ function setStatus(msg, use_alert = true) {
38
+ const realtimeStatus = document.querySelector("#realtime-status-info h2.output-class");
39
+ if (use_alert) alert(msg);
40
+
41
+ if (realtimeStatus) {
42
+ realtimeStatus.innerText = msg;
43
+ realtimeStatus.style.whiteSpace = "nowrap";
44
+ realtimeStatus.style.textAlign = "center";
45
+ }
46
+ }
47
+
48
+ async function addModuleFromString(ctx, codeStr) {
49
+ const blob = new Blob([codeStr], {type: 'application/javascript'});
50
+ const url = URL.createObjectURL(blob);
51
+
52
+ await ctx.audioWorklet.addModule(url);
53
+ URL.revokeObjectURL(url);
54
+ };
55
+
56
+ function createOutputRoute(audioCtx, playbackNode, sinkId, gainValue = 1.0) {
57
+ const dest = audioCtx.createMediaStreamDestination();
58
+ const gainNode = audioCtx.createGain();
59
+ gainNode.gain.value = gainValue;
60
+
61
+ playbackNode.connect(gainNode);
62
+ gainNode.connect(dest);
63
+
64
+ const el = document.createElement('audio');
65
+ el.autoplay = true;
66
+ el.srcObject = dest.stream;
67
+ el.style.display = 'none';
68
+ document.body.appendChild(el);
69
+
70
+ if (el.setSinkId) el.setSinkId(sinkId).catch(err => console.error(err));
71
+ return { dest, gainNode, el };
72
+ }
73
+
74
+ const inputWorkletSource = `
75
+ class InputProcessor extends AudioWorkletProcessor {
76
+ constructor() {
77
+ super();
78
+ this.buffer = new Float32Array(0);
79
+ this.block_frame = 128;
80
+ this.port.onmessage = (e) => {
81
+ if (e.data && e.data.block_frame) this.block_frame = e.data.block_frame;
82
+ };
83
+ }
84
+
85
+ process(inputs) {
86
+ const input = inputs[0];
87
+ if (!input || !input[0]) return true;
88
+ const frame = input[0];
89
+
90
+ const newBuf = new Float32Array(this.buffer.length + frame.length);
91
+ newBuf.set(this.buffer, 0);
92
+ newBuf.set(frame, this.buffer.length);
93
+ this.buffer = newBuf;
94
+
95
+ while (this.buffer.length >= this.block_frame) {
96
+ const chunk = this.buffer.slice(0, this.block_frame);
97
+
98
+ this.port.postMessage({chunk}, [chunk.buffer]);
99
+ this.buffer = this.buffer.slice(this.block_frame);
100
+ }
101
+
102
+ return true;
103
+ }
104
+ }
105
+ registerProcessor('input-processor', InputProcessor);
106
+ `;
107
+
108
+ const playbackWorkletSource = `
109
+ class PlaybackProcessor extends AudioWorkletProcessor {
110
+ constructor(options) {
111
+ super(options);
112
+ const bufferSize = options.processorOptions && options.processorOptions.bufferSize ? options.processorOptions.bufferSize: 98304;
113
+ this.buffer = new Float32Array(bufferSize);
114
+ this.bufferCapacity = bufferSize;
115
+ this.writePointer = 0;
116
+ this.readPointer = 0;
117
+ this.availableSamples = 0;
118
+ this.port.onmessage = (e) => {
119
+ if (e.data && e.data.chunk) {
120
+ const chunk = new Float32Array(e.data.chunk);
121
+ const chunkSize = chunk.length;
122
+
123
+ if (this.availableSamples + chunkSize > this.bufferCapacity) return;
124
+
125
+ for (let i = 0; i < chunkSize; i++) {
126
+ this.buffer[this.writePointer] = chunk[i];
127
+ this.writePointer = (this.writePointer + 1) % this.bufferCapacity;
128
+ }
129
+
130
+ this.availableSamples += chunkSize;
131
+ }
132
+ };
133
+ }
134
+
135
+ process(inputs, outputs) {
136
+ const output = outputs[0];
137
+ if (!output || !output[0]) return true;
138
+
139
+ const frame = output[0];
140
+ const frameSize = frame.length;
141
+
142
+ if (this.availableSamples >= frameSize) {
143
+ for (let i = 0; i < frameSize; i++) {
144
+ frame[i] = this.buffer[this.readPointer];
145
+ this.readPointer = (this.readPointer + 1) % this.bufferCapacity;
146
+ }
147
+ this.availableSamples -= frameSize;
148
+ } else {
149
+ frame.fill(0);
150
+ }
151
+
152
+ if (output.length > 1) output[1].set(output[0]);
153
+ return true;
154
+ }
155
+ }
156
+ registerProcessor('playback-processor', PlaybackProcessor);
157
+ `;
158
+
159
+ window.getAudioDevices = async function() {
160
+ if (!navigator.mediaDevices) {
161
+ setStatus("__MEDIA_DEVICES__");
162
+ return {"inputs": [], "outputs": []};
163
+ }
164
+
165
+ try {
166
+ await navigator.mediaDevices.getUserMedia({ audio: true });
167
+ } catch (err) {
168
+ console.error(err);
169
+ setStatus("__MIC_INACCESSIBLE__")
170
+
171
+ return {"inputs": [], "outputs": []};
172
+ }
173
+
174
+ const devices = await navigator.mediaDevices.enumerateDevices();
175
+ const inputs = [];
176
+ const outputs = [];
177
+
178
+ for (const device of devices) {
179
+ if (device.kind === "audioinput") {
180
+ inputs.push([device.label, device.deviceId])
181
+ } else if (device.kind === "audiooutput") {
182
+ outputs.push([device.label, device.deviceId])
183
+ }
184
+ }
185
+
186
+ if (!inputs.length && !outputs.length) return {"inputs": [], "outputs": []};
187
+ return {"inputs": inputs, "outputs": outputs};
188
+ };
189
+
190
+ window.StreamAudioRealtime = async function(
191
+ monitor,
192
+ vad_enabled,
193
+ input_audio_device,
194
+ output_audio_device,
195
+ monitor_output_device,
196
+ input_audio_gain,
197
+ output_audio_gain,
198
+ monitor_audio_gain,
199
+ chunk_size,
200
+ pitch,
201
+ model_pth,
202
+ model_index,
203
+ index_strength,
204
+ onnx_f0_mode,
205
+ f0_method,
206
+ hop_length,
207
+ embed_mode,
208
+ embedders,
209
+ custom_embedders,
210
+ f0_autotune,
211
+ proposal_pitch,
212
+ f0_autotune_strength,
213
+ proposal_pitch_threshold,
214
+ rms_mix_rate,
215
+ protect,
216
+ filter_radius,
217
+ silent_threshold,
218
+ extra_convert_size,
219
+ cross_fade_overlap_size,
220
+ vad_sensitivity,
221
+ vad_frame_ms,
222
+ clean_audio,
223
+ clean_strength
224
+ ) {
225
+ const SampleRate = 48000;
226
+ const ReadChunkSize = Math.round(chunk_size * SampleRate / 1000 / 128);
227
+ const block_frame = parseInt(ReadChunkSize) * 128;
228
+ const ButtonState = { start_button: true, stop_button: false };
229
+
230
+ try {
231
+
232
+ if (!input_audio_device || !output_audio_device) {
233
+ setStatus("__PROVIDE_AUDIO_DEVICE__");
234
+ return ButtonState;
235
+ }
236
+
237
+ if (monitor && !monitor_output_device) {
238
+ setStatus("__PROVIDE_MONITOR_DEVICE__");
239
+ return ButtonState;
240
+ }
241
+
242
+ if (!model_pth) {
243
+ setStatus("__PROVIDE_MODEL__")
244
+ return ButtonState;
245
+ }
246
+
247
+ setStatus("__START_REALTIME__", use_alert=false)
248
+
249
+ const stream = await navigator.mediaDevices.getUserMedia({
250
+ audio: {
251
+ deviceId: { exact: input_audio_device },
252
+ channelCount: 1,
253
+ sampleRate: SampleRate,
254
+ echoCancellation: false,
255
+ noiseSuppression: false,
256
+ autoGainControl: false
257
+ }
258
+ });
259
+
260
+ window._activeStream = stream;
261
+ window._audioCtx = new AudioContext({ sampleRate: SampleRate, latencyHint: "interactive" });
262
+
263
+ await addModuleFromString(window._audioCtx, inputWorkletSource);
264
+ await addModuleFromString(window._audioCtx, playbackWorkletSource);
265
+
266
+ const src = window._audioCtx.createMediaStreamSource(stream);
267
+ const inputNode = new AudioWorkletNode(window._audioCtx, 'input-processor');
268
+ const playbackNode = new AudioWorkletNode(window._audioCtx, 'playback-processor', {
269
+ processorOptions: {
270
+ bufferSize: block_frame * 2
271
+ }
272
+ });
273
+
274
+ inputNode.port.postMessage({ block_frame: block_frame });
275
+ src.connect(inputNode);
276
+
277
+ createOutputRoute(window._audioCtx, playbackNode, output_audio_device, output_audio_gain / 100);
278
+ if (monitor && monitor_output_device) createOutputRoute(window._audioCtx, playbackNode, monitor_output_device, monitor_audio_gain / 100);
279
+
280
+ const protocol = (location.protocol === "https:") ? "wss:" : "ws:";
281
+ const wsUrl = protocol + '//' + location.hostname + `:${location.port}` + '/api/ws-audio';
282
+ const ws = new WebSocket(wsUrl);
283
+
284
+ ButtonState.start_button = false;
285
+ ButtonState.stop_button = true;
286
+
287
+ ws.binaryType = "arraybuffer";
288
+ window._ws = ws;
289
+
290
+ ws.onopen = () => {
291
+ console.log("__WS_CONNECTED__")
292
+
293
+ ws.send(
294
+ JSON.stringify({
295
+ type: 'init',
296
+ chunk_size: ReadChunkSize,
297
+ embedders: embedders,
298
+ model_pth: model_pth,
299
+ custom_embedders: custom_embedders,
300
+ cross_fade_overlap_size: cross_fade_overlap_size,
301
+ extra_convert_size: extra_convert_size,
302
+ model_index: model_index,
303
+ f0_method: f0_method,
304
+ f0_onnx: onnx_f0_mode,
305
+ embedders_mode: embed_mode,
306
+ hop_length: hop_length,
307
+ silent_threshold: silent_threshold,
308
+ vad_enabled: vad_enabled,
309
+ vad_sensitivity: vad_sensitivity,
310
+ vad_frame_ms: vad_frame_ms,
311
+ clean_audio: clean_audio,
312
+ clean_strength: clean_strength,
313
+ f0_up_key: pitch,
314
+ index_rate: index_strength,
315
+ protect: protect,
316
+ filter_radius: filter_radius,
317
+ rms_mix_rate: rms_mix_rate,
318
+ f0_autotune: f0_autotune,
319
+ f0_autotune_strength: f0_autotune_strength,
320
+ proposal_pitch: proposal_pitch,
321
+ proposal_pitch_threshold: proposal_pitch_threshold,
322
+ input_audio_gain: input_audio_gain
323
+ })
324
+ );
325
+ };
326
+
327
+ inputNode.port.onmessage = (e) => {
328
+ const chunk = e.data && e.data.chunk;
329
+
330
+ if (!chunk) return;
331
+ if (ws.readyState === WebSocket.OPEN) ws.send(chunk);
332
+ };
333
+
334
+ ws.onmessage = (ev) => {
335
+ if (typeof ev.data === 'string') {
336
+ const msg = JSON.parse(ev.data);
337
+
338
+ if (msg.type === 'latency') setStatus(`__LATENCY__: ${msg.value.toFixed(1)} ms`, use_alert=false)
339
+ if (msg.type === 'warnings') {
340
+ setStatus(msg.value);
341
+ StopAudioStream();
342
+ }
343
+
344
+ return;
345
+ }
346
+
347
+ const ab = ev.data;
348
+ playbackNode.port.postMessage({ chunk: ab }, [ab]);
349
+ };
350
+
351
+ ws.onclose = () => console.log("__WS_CLOSED__");
352
+ window._workletNode = inputNode;
353
+ window._playbackNode = playbackNode;
354
+
355
+ if (window._audioCtx.state === 'suspended') await window._audioCtx.resume();
356
+
357
+ console.log("__REALTIME_STARTED__");
358
+ return ButtonState;
359
+ } catch (err) {
360
+ console.error("__ERROR__", err);
361
+ alert("__ERROR__" + err.message);
362
+
363
+ return StopAudioStream();
364
+ }
365
+ };
366
+
367
+ window.StopAudioStream = async function() {
368
+ try {
369
+ if (window._ws) {
370
+ window._ws.close();
371
+ window._ws = null;
372
+ }
373
+
374
+ if (window._activeStream) {
375
+ window._activeStream.getTracks().forEach(t => t.stop());
376
+ window._activeStream = null;
377
+ }
378
+
379
+ if (window._workletNode) {
380
+ window._workletNode.disconnect();
381
+ window._workletNode = null;
382
+ }
383
+
384
+ if (window._playbackNode) {
385
+ window._playbackNode.disconnect();
386
+ window._playbackNode = null;
387
+ }
388
+
389
+ if (window._audioCtx) {
390
+ await window._audioCtx.close();
391
+ window._audioCtx = null;
392
+ }
393
+
394
+ document.querySelectorAll('audio').forEach(a => a.remove());
395
+ setStatus("__REALTIME_HAS_STOP__", use_alert=false);
396
+
397
+ return {"start_button": true, "stop_button": false};
398
+ } catch (e) {
399
+ setStatus(`__ERROR__ ${e}`);
400
+
401
+ return {"start_button": false, "stop_button": true}
402
+ }
403
+ };
404
+ }
405
+ """.replace(
406
+ "__MEDIA_DEVICES__", translations["media_devices"]
407
+ ).replace(
408
+ "__MIC_INACCESSIBLE__", translations["mic_inaccessible"]
409
+ ).replace(
410
+ "__PROVIDE_AUDIO_DEVICE__", translations["provide_audio_device"]
411
+ ).replace(
412
+ "__PROVIDE_MONITOR_DEVICE__", translations["provide_monitor_device"]
413
+ ).replace(
414
+ "__START_REALTIME__", translations["start_realtime"]
415
+ ).replace(
416
+ "__LATENCY__", translations['latency']
417
+ ).replace(
418
+ "__WS_CONNECTED__", translations["ws_connected"]
419
+ ).replace(
420
+ "__WS_CLOSED__", translations["ws_closed"]
421
+ ).replace(
422
+ "__REALTIME_STARTED__", translations["realtime_is_ready"]
423
+ ).replace(
424
+ "__ERROR__", translations["error_occurred"].format(e="")
425
+ ).replace(
426
+ "__REALTIME_HAS_STOP__", translations["realtime_has_stop"]
427
+ ).replace(
428
+ "__PROVIDE_MODEL__", translations["provide_file"].format(filename=translations["model"])
429
+ )
430
+
431
+ client_mode = True # "--client" in sys.argv
432
+
433
+ with gr.Blocks(
434
+ title="📱 Vietnamese-RVC GUI BY ANH",
435
+ js=js_code if client_mode else None,
436
+ theme=theme,
437
+ css="<style> @import url('{fonts}'); * {{font-family: 'Courgette', cursive !important;}} body, html {{font-family: 'Courgette', cursive !important;}} h1, h2, h3, h4, h5, h6, p, button, input, textarea, label, span, div, select {{font-family: 'Courgette', cursive !important;}} </style>".format(fonts=font or "https://fonts.googleapis.com/css2?family=Courgette&display=swap")
438
+ ) as app:
439
+ gr.HTML("<h1 style='text-align: center;'>🎵VIETNAMESE RVC BY ANH🎵</h1>")
440
+ gr.HTML(f"<h3 style='text-align: center;'>{translations['title']}</h3>")
441
+
442
+ with gr.Tabs():
443
+ inference_tab()
444
+ editing_tab()
445
+
446
+ if client_mode:
447
+ from main.app.tabs.realtime.realtime_client import realtime_client_tab
448
+ realtime_client_tab()
449
+ else:
450
+ from main.app.tabs.realtime.realtime import realtime_tab
451
+ realtime_tab()
452
+
453
+ training_tab()
454
+ download_tab()
455
+ extra_tab(app)
456
+
457
+ with gr.Row():
458
+ gr.Markdown(translations["rick_roll"].format(rickroll=codecs.decode('uggcf://jjj.lbhghor.pbz/jngpu?i=qDj4j9JtKpD', 'rot13')))
459
+
460
+ with gr.Row():
461
+ gr.Markdown(translations["terms_of_use"])
462
+
463
+ with gr.Row():
464
+ gr.Markdown(translations["exemption"])
465
+
466
+ if __name__ == "__main__":
467
+ logger.info(config.device.replace("privateuseone", "dml"))
468
+ logger.info(translations["start_app"])
469
+ logger.info(translations["set_lang"].format(lang=language))
470
+
471
+ port = configs.get("app_port", 7860)
472
+ server_name = configs.get("server_name", "0.0.0.0")
473
+ share = "--share" in sys.argv
474
+
475
+ original_stdout = sys.stdout
476
+ sys.stdout = io.StringIO()
477
+
478
+ for i in range(configs.get("num_of_restart", 5)):
479
+ try:
480
+ gradio_app, _, share_url = app.queue().launch(
481
+ favicon_path=configs["ico_path"],
482
+ server_name=server_name,
483
+ server_port=port,
484
+ show_error=configs.get("app_show_error", False),
485
+ inbrowser="--open" in sys.argv,
486
+ share=share,
487
+ allowed_paths=allow_disk,
488
+ prevent_thread_lock=True,
489
+ quiet=True
490
+ )
491
+ break
492
+ except OSError:
493
+ logger.debug(translations["port"].format(port=port))
494
+ port -= 1
495
+ except Exception as e:
496
+ logger.error(translations["error_occurred"].format(e=e))
497
+ sys.exit(1)
498
+
499
+ if client_mode:
500
+ from main.app.core.realtime_client import app as fastapi_app
501
+ gradio_app.mount("/api", fastapi_app)
502
+
503
+ sys.stdout = original_stdout
504
+
505
+ if configs.get("discord_presence", True):
506
+ pipe = connect_discord_ipc()
507
+ if pipe:
508
+ try:
509
+ logger.info(translations["start_rpc"])
510
+ send_discord_rpc(pipe)
511
+ except KeyboardInterrupt:
512
+ logger.info(translations["stop_rpc"])
513
+ pipe.close()
514
+
515
+ logger.info(f"{translations['running_local_url']}: {server_name}:{port}")
516
+ if share: logger.info(f"{translations['running_share_url']}: {share_url}")
517
+ logger.info(f"{translations['gradio_start']}: {(time.time() - start_time):.2f}s")
518
+
519
+ while 1:
520
  time.sleep(5)