From 073603ed91f84a1231807b91a53776e94e79b6b3 Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Tue, 13 Jun 2023 06:25:41 +0900 Subject: [PATCH 1/9] pyaudio -> sounddevice --- VRCT.py | 3 ++- transcription.py | 47 +++++++++++++++++++++++++++++------------------ window_config.py | 4 ++-- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/VRCT.py b/VRCT.py index 5e74690b..2fbe8467 100644 --- a/VRCT.py +++ b/VRCT.py @@ -259,7 +259,8 @@ class App(customtkinter.CTk): ## set transcription instance self.vr = transcription.VoiceRecognizer() - self.CHOICE_MIC_DEVICE = self.CHOICE_MIC_DEVICE if self.CHOICE_MIC_DEVICE is not None else list(self.vr.input_device_dict.keys())[0] + self.CHOICE_MIC_DEVICE = self.CHOICE_MIC_DEVICE if self.CHOICE_MIC_DEVICE is not None else self.vr.search_default_device_index()[0]["name"] + self.CHOICE_SPEAKER_DEVICE = self.CHOICE_SPEAKER_DEVICE if self.CHOICE_SPEAKER_DEVICE is not None else self.vr.search_default_device_index()[1]["name"] ## set checkbox enable translation if self.ENABLE_TRANSLATION: diff --git a/transcription.py b/transcription.py index 7b0eee17..ceddfb5c 100644 --- a/transcription.py +++ b/transcription.py @@ -1,10 +1,9 @@ -import pyaudio +import sounddevice as sd import speech_recognition as sr # VoiceRecognizer class VoiceRecognizer(): def __init__(self): - self.input_device_dict = self.search_input_device() self.r = sr.Recognizer() self.mic = None self.languages = [ @@ -19,25 +18,37 @@ class VoiceRecognizer(): ] def search_input_device(self): - pa = pyaudio.PyAudio() - input_device_dict = {} + device_list = sd.query_devices() + input_device_list = [] - mic_cnt = 1 - for i in range(pa.get_device_count()): - device = pa.get_device_info_by_index(i) - try: - device["name"] = device["name"].encode('shift_jis').decode('utf-8') - except: - device["name"] = device["name"].encode('utf-8').decode('utf-8') - if device["maxInputChannels"] > 0: - input_device_dict[f'No.{mic_cnt}:{device["name"]}'] = device["index"] - mic_cnt += 1 - pa.terminate() - return input_device_dict + for device in device_list: + if device["max_input_channels"] > 0: + input_device_list.append({"name": device["name"], "index": device["index"]}) + + return input_device_list + + def search_output_device(self): + device_list = sd.query_devices() + output_device_list = [] + + for device in device_list: + if device["max_output_channels"] > 0: + output_device_list.append({"name": device["name"], "index": device["index"]}) + + return output_device_list + + def search_default_device_index(self): + device_list = sd.query_devices() + default_device_list = [] + for i in sd.default.device: + default_device_list.append({"name": device_list[i]["name"], "index": device_list[i]["index"]}) + return default_device_list def set_mic(self, device_name, threshold=50, is_dynamic=False): - if device_name in [v for v in self.input_device_dict.keys()]: - index = self.input_device_dict[device_name] + input_device_list = self.search_input_device() + if device_name in [input_device["name"] for input_device in input_device_list]: + index = [device["index"] for device in input_device_list if device["name"] == device_name][0] + self.mic = sr.Microphone(device_index=index) self.r.energy_threshold = threshold if is_dynamic: diff --git a/window_config.py b/window_config.py index e95b01b4..a5ef6daf 100644 --- a/window_config.py +++ b/window_config.py @@ -204,7 +204,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.label_input_mic_device.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") self.optionmenu_input_mic_device = customtkinter.CTkOptionMenu( self.tabview_config.tab("Transcription"), - values=list(self.parent.vr.input_device_dict.keys()), + values=[device["name"] for device in self.parent.vr.search_input_device()], command=self.optionmenu_input_mic_device_callback, font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), variable=customtkinter.StringVar(value=self.parent.CHOICE_MIC_DEVICE) @@ -277,7 +277,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.label_input_speaker_device.grid(row=4, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") self.optionmenu_input_speaker_device = customtkinter.CTkOptionMenu( self.tabview_config.tab("Transcription"), - values=list(self.parent.vr.input_device_dict.keys()), + values=[device["name"] for device in self.parent.vr.search_output_device()], # command=self.optionmenu_input_speaker_device_callback, font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), variable=customtkinter.StringVar(value=self.parent.CHOICE_SPEAKER_DEVICE), From 61f769ef0651777e9c5f48f3d8c23199f35f93ff Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Tue, 13 Jun 2023 13:51:31 +0900 Subject: [PATCH 2/9] update transcription mic/spk --- VRCT.py | 90 +++++++++++++++++++++++++---------- transcription.py | 121 ++++++++++++++++++++++++++++++++++++++++------- window_config.py | 2 +- 3 files changed, 171 insertions(+), 42 deletions(-) diff --git a/VRCT.py b/VRCT.py index 2fbe8467..a6a36757 100644 --- a/VRCT.py +++ b/VRCT.py @@ -259,8 +259,8 @@ class App(customtkinter.CTk): ## set transcription instance self.vr = transcription.VoiceRecognizer() - self.CHOICE_MIC_DEVICE = self.CHOICE_MIC_DEVICE if self.CHOICE_MIC_DEVICE is not None else self.vr.search_default_device_index()[0]["name"] - self.CHOICE_SPEAKER_DEVICE = self.CHOICE_SPEAKER_DEVICE if self.CHOICE_SPEAKER_DEVICE is not None else self.vr.search_default_device_index()[1]["name"] + self.CHOICE_MIC_DEVICE = self.CHOICE_MIC_DEVICE if self.CHOICE_MIC_DEVICE is not None else self.vr.search_default_device()[0] + self.CHOICE_SPEAKER_DEVICE = self.CHOICE_SPEAKER_DEVICE if self.CHOICE_SPEAKER_DEVICE is not None else self.vr.search_default_device()[1] ## set checkbox enable translation if self.ENABLE_TRANSLATION: @@ -324,33 +324,44 @@ class App(customtkinter.CTk): self.ENABLE_TRANSCRIPTION = self.checkbox_transcription.get() if self.ENABLE_TRANSCRIPTION is True: # start threading - th = threading.Thread(target = self.voice_input) - th.start() + self.vr.set_mic(self.CHOICE_MIC_DEVICE) + self.vr.init_mic(threshold=self.MIC_THRESHOLD, is_dynamic=self.ENABLE_MIC_IS_DYNAMIC) + th_vr_listen_mic = threading.Thread(target = self.vr_listen_mic) + th_vr_recognize_mic = threading.Thread(target = self.vr_recognize_mic) + th_vr_listen_mic.start() + th_vr_recognize_mic.start() + + self.vr.set_spk(self.CHOICE_SPEAKER_DEVICE) + self.vr.init_spk() + th_vr_listen_spk = threading.Thread(target = self.vr_listen_spk) + th_vr_recognize_spk = threading.Thread(target = self.vr_recognize_spk) + th_vr_listen_spk.start() + th_vr_recognize_spk.start() + utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION", self.ENABLE_TRANSCRIPTION) - def voice_input(self): - self.vr.set_mic(self.CHOICE_MIC_DEVICE) - self.vr.init_mic(threshold=self.MIC_THRESHOLD, is_dynamic=self.ENABLE_MIC_IS_DYNAMIC) + def vr_listen_mic(self): + while self.checkbox_transcription.get() is True: + self.vr.listen_mic() - # start voice_input - if self.checkbox_transcription.get() is True: - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[INFO] start transcription\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + def vr_recognize_mic(self): + self.textbox_message_log.configure(state='normal') + self.textbox_message_log.insert("end", f"[INFO] start transcription\n") + self.textbox_message_log.configure(state='disabled') + self.textbox_message_log.see("end") while self.checkbox_transcription.get() is True: - message = self.vr.listen_voice(language=self.INPUT_MIC_VOICE_LANGUAGE) + message = self.vr.recognize_mic(language=self.INPUT_MIC_VOICE_LANGUAGE) if len(message) > 0: # translate if self.checkbox_translation.get() is False: - chat_message = f"{message}" - elif (self.translator.translator_status[self.CHOICE_TRANSLATOR] is False) or (self.INPUT_SOURCE_LANG == "None") or (self.INPUT_TARGET_LANG == "None"): + voice_message = f"{message}" + elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: self.textbox_message_log.configure(state='normal') self.textbox_message_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") self.textbox_message_log.configure(state='disabled') self.textbox_message_log.see("end") - chat_message = f"{message}" + voice_message = f"{message}" else: result = self.translator.translate( translator_name=self.CHOICE_TRANSLATOR, @@ -358,20 +369,51 @@ class App(customtkinter.CTk): target_language=self.INPUT_TARGET_LANG, message=message ) - chat_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) + voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) # send OSC message - osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT) + osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message log self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[VOICE] {chat_message}\n") + self.textbox_message_log.insert("end", f"[VOICE] {voice_message}\n") + self.textbox_message_log.configure(state='disabled') + self.textbox_message_log.see("end") + + def vr_listen_spk(self): + while self.checkbox_transcription.get() is True: + self.vr.listen_spk() + + def vr_recognize_spk(self): + while self.checkbox_transcription.get() is True: + message = self.vr.recognize_spk(language=self.INPUT_SPEAKER_VOICE_LANGUAGE) + if len(message) > 0: + # translate + if self.checkbox_translation.get() is False: + voice_message = f"{message}" + elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: + self.textbox_message_log.configure(state='normal') + self.textbox_message_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") + self.textbox_message_log.configure(state='disabled') + self.textbox_message_log.see("end") + voice_message = f"{message}" + else: + result = self.translator.translate( + translator_name=self.CHOICE_TRANSLATOR, + source_language=self.INPUT_SOURCE_LANG, + target_language=self.INPUT_TARGET_LANG, + message=message + ) + voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) + + # send OSC message + osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) + + # update textbox message log + self.textbox_message_log.configure(state='normal') + self.textbox_message_log.insert("end", f"[VOICE] {voice_message}\n") self.textbox_message_log.configure(state='disabled') self.textbox_message_log.see("end") - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[INFO] stop transcription\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") def checkbox_foreground_callback(self): self.ENABLE_FOREGROUND = self.checkbox_foreground.get() diff --git a/transcription.py b/transcription.py index ceddfb5c..ba358d08 100644 --- a/transcription.py +++ b/transcription.py @@ -1,3 +1,8 @@ +import io +import queue +import numpy as np +import soundcard as sc +import soundfile as sf import sounddevice as sd import speech_recognition as sr @@ -5,7 +10,6 @@ import speech_recognition as sr class VoiceRecognizer(): def __init__(self): self.r = sr.Recognizer() - self.mic = None self.languages = [ "ja-JP","en-US","en-GB","af-ZA","ar-DZ","ar-BH","ar-EG","ar-IL","ar-IQ","ar-JO","ar-KW","ar-LB","ar-MA", "ar-OM","ar-PS","ar-QA","ar-SA","ar-TN","ar-AE","eu-ES","bg-BG","ca-ES","cmn-Hans-CN","cmn-Hans-HK", @@ -16,6 +20,18 @@ class VoiceRecognizer(): "es-NI","es-PA","es-PY","es-PE","es-PR","es-ES","es-UY","es-US","es-VE","sv-SE","th-TH","tr-TR","uk-UA", "vi-VN","zu-ZA" ] + self.mic = None + self.enable_mic_recognize = False + self.queue_mic = queue.Queue() + + self.spk_device_name = None + self.spk_sample_rate = 16000 + self.spk_interval = 3 + self.spk_buffer_size = 4096 + self.spk_language = "en-US" + self.spk_audio = np.empty(self.spk_sample_rate * self.spk_interval + self.spk_buffer_size, dtype=np.float32) + self.n = 0 + self.queue_spk = queue.Queue() def search_input_device(self): device_list = sd.query_devices() @@ -28,21 +44,20 @@ class VoiceRecognizer(): return input_device_list def search_output_device(self): - device_list = sd.query_devices() + device_list = sc.all_speakers() output_device_list = [] for device in device_list: - if device["max_output_channels"] > 0: - output_device_list.append({"name": device["name"], "index": device["index"]}) + output_device_list.append(str(device.name)) return output_device_list - def search_default_device_index(self): + def search_default_device(self): device_list = sd.query_devices() - default_device_list = [] - for i in sd.default.device: - default_device_list.append({"name": device_list[i]["name"], "index": device_list[i]["index"]}) - return default_device_list + mic_index = sd.default.device[0] + name_mic = device_list[mic_index]["name"] + name_spk = str(sc.default_speaker().name) + return name_mic, name_spk def set_mic(self, device_name, threshold=50, is_dynamic=False): input_device_list = self.search_input_device() @@ -68,14 +83,86 @@ class VoiceRecognizer(): else: return False - def listen_voice(self, language): + def listen_mic(self): if self.mic != None: with self.mic as source: audio = self.r.listen(source) - try: - text = self.r.recognize_google(audio, language=language) - return text - except: - return "" - else: - return False \ No newline at end of file + self.queue_mic.put(audio) + + def recognize_mic(self, language): + try: + audio = self.queue_mic.get() + text = self.r.recognize_google(audio, language=language) + except: + text = "" + return text + + def set_spk(self, device_name=str(sc.default_speaker().name), sample_rate=16000, interval=3, buffer_size=4096, language="en-US"): + self.spk_device_name = device_name + self.spk_sample_rate = sample_rate + self.spk_interval = interval + self.spk_buffer_size = buffer_size + self.spk_language = language + + def init_spk(self): + self.spk_audio = np.empty(self.spk_sample_rate * self.spk_interval + self.spk_buffer_size, dtype=np.float32) + self.n = 0 + + def listen_spk(self): + audio = self.spk_audio + n = self.n + with sc.get_microphone(id=self.spk_device_name, include_loopback=True).recorder(samplerate=self.spk_sample_rate, channels=1) as source: + while n < self.spk_sample_rate * self.spk_interval: + data = source.record(self.spk_buffer_size) + audio[n:n+len(data)] = data.reshape(-1) + n += len(data) + m = n * 4 // 5 + vol = np.convolve(audio[m:n] ** 2, np.ones(100) / 100, 'same') + m += vol.argmin() + audio_prev = audio.copy() + self.queue_spk.put(audio[:m]) + audio = np.empty(self.spk_sample_rate * self.spk_interval + self.spk_buffer_size, dtype=np.float32) + audio[:n-m] = audio_prev[m:n] + n = n-m + self.spk_audio = audio + self.n = n + + def recognize_spk(self): + try: + audio = self.queue_spk.get() + with io.BytesIO() as memory_file: + sf.write(file=memory_file, data=audio, format="WAV", samplerate=self.spk_sample_rate) + memory_file.seek(0) + with sr.AudioFile(memory_file) as source: + audio = self.r.record(source) + text = self.r.recognize_google(audio, language=self.spk_language) + except Exception as e: + text = "" + return text + +if __name__ == "__main__": + import time + import threading + + vr = VoiceRecognizer() + mic_name, spk_name = vr.search_default_device() + vr.spk_enable_recognize = True + vr.set_spk(language="ja-JP") + vr.init_spk() + + def vr_listen_spk(): + while True: + vr.listen_spk() + + def vr_recognize_spk(): + while True: + text = vr.recognize_spk() + print(text) + + th_vr_listen_spk = threading.Thread(target=vr_listen_spk) + th_vr_recognize_spk = threading.Thread(target=vr_recognize_spk) + th_vr_listen_spk.start() + th_vr_recognize_spk.start() + + while True: + time.sleep(60) \ No newline at end of file diff --git a/window_config.py b/window_config.py index a5ef6daf..6930db1a 100644 --- a/window_config.py +++ b/window_config.py @@ -277,7 +277,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.label_input_speaker_device.grid(row=4, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") self.optionmenu_input_speaker_device = customtkinter.CTkOptionMenu( self.tabview_config.tab("Transcription"), - values=[device["name"] for device in self.parent.vr.search_output_device()], + values=self.parent.vr.search_output_device(), # command=self.optionmenu_input_speaker_device_callback, font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), variable=customtkinter.StringVar(value=self.parent.CHOICE_SPEAKER_DEVICE), From dbc322ac15052a93e37efa80f397335c6a86ac3e Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Tue, 13 Jun 2023 18:04:29 +0900 Subject: [PATCH 3/9] update transcription UI --- VRCT.py | 159 +++++++++++++++++++++++++++-------------------- transcription.py | 60 +++++++----------- window_config.py | 132 ++++++++++++++++++++++----------------- 3 files changed, 189 insertions(+), 162 deletions(-) diff --git a/VRCT.py b/VRCT.py index a6a36757..016053ed 100644 --- a/VRCT.py +++ b/VRCT.py @@ -35,12 +35,14 @@ class App(customtkinter.CTk): ## Transcription self.CHOICE_MIC_DEVICE = None self.INPUT_MIC_VOICE_LANGUAGE = "ja-JP" - self.ENABLE_MIC_IS_DYNAMIC = False - self.MIC_THRESHOLD = 300 + self.INPUT_MIC_IS_DYNAMIC = False + self.INPUT_MIC_THRESHOLD = 300 self.CHOICE_SPEAKER_DEVICE = None self.INPUT_SPEAKER_VOICE_LANGUAGE = "ja-JP" - self.ENABLE_SPEAKER_IS_DYNAMIC = False - self.SPEAKER_THRESHOLD = 300 + self.INPUT_SPEAKER_SAMPLING_RATE = 16000 + self.INPUT_SPEAKER_INTERVAL = 3 + self.INPUT_SPEAKER_BUFFER_SIZE = 4096 + ## Parameter self.OSC_IP_ADDRESS = "127.0.0.1" self.OSC_PORT = 9000 @@ -91,18 +93,20 @@ class App(customtkinter.CTk): self.CHOICE_MIC_DEVICE = config["CHOICE_MIC_DEVICE"] if "INPUT_MIC_VOICE_LANGUAGE" in config.keys(): self.INPUT_MIC_VOICE_LANGUAGE = config["INPUT_MIC_VOICE_LANGUAGE"] - if "ENABLE_MIC_IS_DYNAMIC" in config.keys(): - self.ENABLE_MIC_IS_DYNAMIC = config["ENABLE_MIC_IS_DYNAMIC"] - if "MIC_THRESHOLD" in config.keys(): - self.MIC_THRESHOLD = config["MIC_THRESHOLD"] + if "INPUT_MIC_IS_DYNAMIC" in config.keys(): + self.INPUT_MIC_IS_DYNAMIC = config["INPUT_MIC_IS_DYNAMIC"] + if "INPUT_MIC_THRESHOLD" in config.keys(): + self.INPUT_MIC_THRESHOLD = config["INPUT_MIC_THRESHOLD"] if "CHOICE_SPEAKER_DEVICE" in config.keys(): self.CHOICE_SPEAKER_DEVICE = config["CHOICE_SPEAKER_DEVICE"] if "INPUT_SPEAKER_VOICE_LANGUAGE" in config.keys(): self.INPUT_SPEAKER_VOICE_LANGUAGE = config["INPUT_SPEAKER_VOICE_LANGUAGE"] - if "ENABLE_SPEAKER_IS_DYNAMIC" in config.keys(): - self.ENABLE_SPEAKER_IS_DYNAMIC = config["ENABLE_SPEAKER_IS_DYNAMIC"] - if "SPEAKER_THRESHOLD" in config.keys(): - self.SPEAKER_THRESHOLD = config["SPEAKER_THRESHOLD"] + if "INPUT_SPEAKER_SAMPLING_RATE" in config.keys(): + self.INPUT_SPEAKER_SAMPLING_RATE = config["INPUT_SPEAKER_SAMPLING_RATE"] + if "INPUT_SPEAKER_INTERVAL" in config.keys(): + self.INPUT_SPEAKER_INTERVAL = config["INPUT_SPEAKER_INTERVAL"] + if "INPUT_SPEAKER_BUFFER_SIZE" in config.keys(): + self.INPUT_SPEAKER_BUFFER_SIZE = config["INPUT_SPEAKER_BUFFER_SIZE"] # Parameter if "OSC_IP_ADDRESS" in config.keys(): @@ -130,12 +134,13 @@ class App(customtkinter.CTk): "OUTPUT_TARGET_LANG": self.OUTPUT_TARGET_LANG, "CHOICE_MIC_DEVICE": self.CHOICE_MIC_DEVICE, "INPUT_MIC_VOICE_LANGUAGE": self.INPUT_MIC_VOICE_LANGUAGE, - "ENABLE_MIC_IS_DYNAMIC": self.ENABLE_MIC_IS_DYNAMIC, - "MIC_THRESHOLD": self.MIC_THRESHOLD, + "INPUT_MIC_IS_DYNAMIC": self.INPUT_MIC_IS_DYNAMIC, + "INPUT_MIC_THRESHOLD": self.INPUT_MIC_THRESHOLD, "CHOICE_SPEAKER_DEVICE": self.CHOICE_SPEAKER_DEVICE, "INPUT_SPEAKER_VOICE_LANGUAGE": self.INPUT_SPEAKER_VOICE_LANGUAGE, - "ENABLE_SPEAKER_IS_DYNAMIC": self.ENABLE_SPEAKER_IS_DYNAMIC, - "SPEAKER_THRESHOLD": self.SPEAKER_THRESHOLD, + "INPUT_SPEAKER_SAMPLING_RATE": self.INPUT_SPEAKER_SAMPLING_RATE, + "INPUT_SPEAKER_INTERVAL": self.INPUT_SPEAKER_INTERVAL, + "INPUT_SPEAKER_BUFFER_SIZE": self.INPUT_SPEAKER_BUFFER_SIZE, "OSC_IP_ADDRESS": self.OSC_IP_ADDRESS, "OSC_PORT": self.OSC_PORT, "AUTH_KEYS": self.AUTH_KEYS, @@ -215,29 +220,40 @@ class App(customtkinter.CTk): self.tabview_logs = customtkinter.CTkTabview(master=self) self.tabview_logs.add("send") self.tabview_logs.add("receive") + self.tabview_logs.add("system") self.tabview_logs.grid(row=0, column=1, padx=5, pady=0, sticky="nsew") self.tabview_logs._segmented_button.grid(sticky="W") self.tabview_logs.tab("send").grid_rowconfigure(0, weight=1) self.tabview_logs.tab("send").grid_columnconfigure(0, weight=1) self.tabview_logs.tab("receive").grid_rowconfigure(0, weight=1) self.tabview_logs.tab("receive").grid_columnconfigure(0, weight=1) - self.tabview_logs.configure(state='disabled') + self.tabview_logs.tab("system").grid_rowconfigure(0, weight=1) + self.tabview_logs.tab("system").grid_columnconfigure(0, weight=1) + # self.tabview_logs.configure(state='disabled') - # add textbox message log - self.textbox_message_log = customtkinter.CTkTextbox( + # add textbox message send log + self.textbox_message_send_log = customtkinter.CTkTextbox( self.tabview_logs.tab("send"), font=customtkinter.CTkFont(family=self.FONT_FAMILY) ) - self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - self.textbox_message_log.configure(state='disabled') + self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") + self.textbox_message_send_log.configure(state='disabled') - # add textbox message log + # add textbox message receive log self.textbox_message_receive_log = customtkinter.CTkTextbox( self.tabview_logs.tab("receive"), font=customtkinter.CTkFont(family=self.FONT_FAMILY) ) self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - self.textbox_message_receive_log.configure(state='disabled') + # self.textbox_message_receive_log.configure(state='disabled') + + # add textbox message system log + self.textbox_message_system_log = customtkinter.CTkTextbox( + self.tabview_logs.tab("system"), + font=customtkinter.CTkFont(family=self.FONT_FAMILY) + ) + self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") + # self.textbox_message_system_log.configure(state='disabled') # add entry message box self.entry_message_box = customtkinter.CTkEntry( @@ -252,10 +268,10 @@ class App(customtkinter.CTk): self.translator = translation.Translator() if self.translator.authentication(self.CHOICE_TRANSLATOR, self.AUTH_KEYS[self.CHOICE_TRANSLATOR]) is False: # error update Auth key - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[ERROR] Auth Keyを設定してないか間違っています\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_system_log.configure(state='normal') + self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyを設定してないか間違っています\n") + self.textbox_message_system_log.configure(state='disabled') + self.textbox_message_system_log.see("end") ## set transcription instance self.vr = transcription.VoiceRecognizer() @@ -301,7 +317,10 @@ class App(customtkinter.CTk): def button_config_callback(self): if self.config_window is None or not self.config_window.winfo_exists(): - self.config_window = window_config.ToplevelWindowConfig(self) + try: + self.config_window = window_config.ToplevelWindowConfig(self) + except Exception as e: + print(e) self.config_window.focus() def button_information_callback(self): @@ -311,30 +330,32 @@ class App(customtkinter.CTk): def checkbox_translation_callback(self): self.ENABLE_TRANSLATION = self.checkbox_translation.get() - self.textbox_message_log.configure(state='normal') + self.textbox_message_system_log.configure(state='normal') if self.ENABLE_TRANSLATION: - self.textbox_message_log.insert("end", f"[INFO] start translation\n") + self.textbox_message_system_log.insert("end", f"[INFO] start translation\n") else: - self.textbox_message_log.insert("end", f"[INFO] stop translation\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_system_log.insert("end", f"[INFO] stop translation\n") + self.textbox_message_system_log.configure(state='disabled') + self.textbox_message_system_log.see("end") utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSLATION", self.ENABLE_TRANSLATION) def checkbox_transcription_callback(self): self.ENABLE_TRANSCRIPTION = self.checkbox_transcription.get() if self.ENABLE_TRANSCRIPTION is True: # start threading - self.vr.set_mic(self.CHOICE_MIC_DEVICE) - self.vr.init_mic(threshold=self.MIC_THRESHOLD, is_dynamic=self.ENABLE_MIC_IS_DYNAMIC) - th_vr_listen_mic = threading.Thread(target = self.vr_listen_mic) - th_vr_recognize_mic = threading.Thread(target = self.vr_recognize_mic) - th_vr_listen_mic.start() - th_vr_recognize_mic.start() + self.vr.set_mic(self.CHOICE_MIC_DEVICE, threshold=self.INPUT_MIC_THRESHOLD, is_dynamic=self.INPUT_MIC_IS_DYNAMIC) + self.vr.init_mic() self.vr.set_spk(self.CHOICE_SPEAKER_DEVICE) self.vr.init_spk() + + th_vr_listen_mic = threading.Thread(target = self.vr_listen_mic) + th_vr_recognize_mic = threading.Thread(target = self.vr_recognize_mic) th_vr_listen_spk = threading.Thread(target = self.vr_listen_spk) th_vr_recognize_spk = threading.Thread(target = self.vr_recognize_spk) + + th_vr_listen_mic.start() + th_vr_recognize_mic.start() th_vr_listen_spk.start() th_vr_recognize_spk.start() @@ -345,10 +366,10 @@ class App(customtkinter.CTk): self.vr.listen_mic() def vr_recognize_mic(self): - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[INFO] start transcription\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_system_log.configure(state='normal') + self.textbox_message_system_log.insert("end", f"[INFO] start transcription\n") + self.textbox_message_system_log.configure(state='disabled') + self.textbox_message_system_log.see("end") while self.checkbox_transcription.get() is True: message = self.vr.recognize_mic(language=self.INPUT_MIC_VOICE_LANGUAGE) @@ -357,10 +378,10 @@ class App(customtkinter.CTk): if self.checkbox_translation.get() is False: voice_message = f"{message}" elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_system_log.configure(state='normal') + self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") + self.textbox_message_system_log.configure(state='disabled') + self.textbox_message_system_log.see("end") voice_message = f"{message}" else: result = self.translator.translate( @@ -375,10 +396,10 @@ class App(customtkinter.CTk): osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message log - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[VOICE] {voice_message}\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_send_log.configure(state='normal') + self.textbox_message_send_log.insert("end", f"[VOICE] {voice_message}\n") + self.textbox_message_send_log.configure(state='disabled') + self.textbox_message_send_log.see("end") def vr_listen_spk(self): while self.checkbox_transcription.get() is True: @@ -392,10 +413,10 @@ class App(customtkinter.CTk): if self.checkbox_translation.get() is False: voice_message = f"{message}" elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_system_log.configure(state='normal') + self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") + self.textbox_message_system_log.configure(state='disabled') + self.textbox_message_system_log.see("end") voice_message = f"{message}" else: result = self.translator.translate( @@ -409,11 +430,11 @@ class App(customtkinter.CTk): # send OSC message osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) - # update textbox message log - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[VOICE] {voice_message}\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + # update textbox message receive log + self.textbox_message_receive_log.configure(state='normal') + self.textbox_message_receive_log.insert("end", f"[VOICE] {voice_message}\n") + self.textbox_message_receive_log.configure(state='disabled') + self.textbox_message_receive_log.see("end") def checkbox_foreground_callback(self): self.ENABLE_FOREGROUND = self.checkbox_foreground.get() @@ -436,10 +457,10 @@ class App(customtkinter.CTk): if self.checkbox_translation.get() is False: chat_message = f"{message}" elif (self.translator.translator_status[self.CHOICE_TRANSLATOR] is False) or (self.INPUT_SOURCE_LANG == "None") or (self.INPUT_TARGET_LANG == "None"): - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_system_log.configure(state='normal') + self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") + self.textbox_message_system_log.configure(state='disabled') + self.textbox_message_system_log.see("end") chat_message = f"{message}" else: result = self.translator.translate( @@ -451,13 +472,13 @@ class App(customtkinter.CTk): chat_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) # send OSC message - osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT) + # osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message log - self.textbox_message_log.configure(state='normal') - self.textbox_message_log.insert("end", f"[CHAT] {chat_message}\n") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_log.see("end") + self.textbox_message_receive_log.configure(state='normal') + self.textbox_message_receive_log.insert("end", f"[CHAT] {chat_message}\n") + self.textbox_message_receive_log.configure(state='disabled') + self.textbox_message_receive_log.see("end") # delete message in entry message box # self.entry_message_box.delete(0, customtkinter.END) diff --git a/transcription.py b/transcription.py index ba358d08..07c8f9ce 100644 --- a/transcription.py +++ b/transcription.py @@ -20,18 +20,18 @@ class VoiceRecognizer(): "es-NI","es-PA","es-PY","es-PE","es-PR","es-ES","es-UY","es-US","es-VE","sv-SE","th-TH","tr-TR","uk-UA", "vi-VN","zu-ZA" ] - self.mic = None - self.enable_mic_recognize = False - self.queue_mic = queue.Queue() + self.mic_device_name = None + self.mic_threshold = 50 + self.mic_is_dynamic = False + self.mic_queue = queue.Queue() self.spk_device_name = None self.spk_sample_rate = 16000 self.spk_interval = 3 self.spk_buffer_size = 4096 - self.spk_language = "en-US" self.spk_audio = np.empty(self.spk_sample_rate * self.spk_interval + self.spk_buffer_size, dtype=np.float32) self.n = 0 - self.queue_spk = queue.Queue() + self.spk_queue = queue.Queue() def search_input_device(self): device_list = sd.query_devices() @@ -61,48 +61,34 @@ class VoiceRecognizer(): def set_mic(self, device_name, threshold=50, is_dynamic=False): input_device_list = self.search_input_device() - if device_name in [input_device["name"] for input_device in input_device_list]: - index = [device["index"] for device in input_device_list if device["name"] == device_name][0] + self.mic_device_name = [device["index"] for device in input_device_list if device["name"] == device_name][0] + self.mic_threshold = threshold + self.mic_is_dynamic = is_dynamic - self.mic = sr.Microphone(device_index=index) - self.r.energy_threshold = threshold - if is_dynamic: - with self.mic as source: - self.r.adjust_for_ambient_noise(source, 3.0) - return True - else: - return False - - def init_mic(self, threshold=50, is_dynamic=False): - if isinstance(self.mic, sr.Microphone): - self.r.energy_threshold = threshold - if is_dynamic: - with self.mic as source: - self.r.adjust_for_ambient_noise(source, 3.0) - return True - else: - return False + def init_mic(self): + self.r.energy_threshold = self.mic_threshold + if self.mic_is_dynamic: + with self.mic as source: + self.r.adjust_for_ambient_noise(source, 3.0) def listen_mic(self): - if self.mic != None: - with self.mic as source: - audio = self.r.listen(source) - self.queue_mic.put(audio) + with sr.Microphone(device_index=self.mic_device_name) as source: + audio = self.r.listen(source) + self.mic_queue.put(audio) def recognize_mic(self, language): try: - audio = self.queue_mic.get() + audio = self.mic_queue.get() text = self.r.recognize_google(audio, language=language) except: text = "" return text - def set_spk(self, device_name=str(sc.default_speaker().name), sample_rate=16000, interval=3, buffer_size=4096, language="en-US"): + def set_spk(self, device_name=str(sc.default_speaker().name), sample_rate=16000, interval=3, buffer_size=4096): self.spk_device_name = device_name self.spk_sample_rate = sample_rate self.spk_interval = interval self.spk_buffer_size = buffer_size - self.spk_language = language def init_spk(self): self.spk_audio = np.empty(self.spk_sample_rate * self.spk_interval + self.spk_buffer_size, dtype=np.float32) @@ -120,23 +106,23 @@ class VoiceRecognizer(): vol = np.convolve(audio[m:n] ** 2, np.ones(100) / 100, 'same') m += vol.argmin() audio_prev = audio.copy() - self.queue_spk.put(audio[:m]) + self.spk_queue.put(audio[:m]) audio = np.empty(self.spk_sample_rate * self.spk_interval + self.spk_buffer_size, dtype=np.float32) audio[:n-m] = audio_prev[m:n] n = n-m self.spk_audio = audio self.n = n - def recognize_spk(self): + def recognize_spk(self, language): try: - audio = self.queue_spk.get() + audio = self.spk_queue.get() with io.BytesIO() as memory_file: sf.write(file=memory_file, data=audio, format="WAV", samplerate=self.spk_sample_rate) memory_file.seek(0) with sr.AudioFile(memory_file) as source: audio = self.r.record(source) - text = self.r.recognize_google(audio, language=self.spk_language) - except Exception as e: + text = self.r.recognize_google(audio, language=language) + except: text = "" return text diff --git a/window_config.py b/window_config.py index 6930db1a..db17e496 100644 --- a/window_config.py +++ b/window_config.py @@ -245,7 +245,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) self.checkbox_input_mic_is_dynamic.grid(row=2, column=1, columnspan=3 ,padx=5, pady=5, sticky="nsew") - if self.parent.ENABLE_MIC_IS_DYNAMIC is True: + if self.parent.INPUT_MIC_IS_DYNAMIC is True: self.checkbox_input_mic_is_dynamic.select() else: self.checkbox_input_mic_is_dynamic.deselect() @@ -263,7 +263,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): from_=0, to=300, command=self.slider_input_mic_threshold_callback, - variable=tk.DoubleVar(value=self.parent.MIC_THRESHOLD), + variable=tk.DoubleVar(value=self.parent.INPUT_MIC_THRESHOLD), ) self.slider_input_mic_threshold.grid(row=3, column=1, columnspan=3 ,padx=5, pady=10, sticky="nsew") @@ -272,16 +272,15 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.tabview_config.tab("Transcription"), text="Input Speaker Device:", fg_color="transparent", - font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY, overstrike=True) + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) self.label_input_speaker_device.grid(row=4, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") self.optionmenu_input_speaker_device = customtkinter.CTkOptionMenu( self.tabview_config.tab("Transcription"), values=self.parent.vr.search_output_device(), - # command=self.optionmenu_input_speaker_device_callback, + command=self.optionmenu_input_speaker_device_callback, font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), variable=customtkinter.StringVar(value=self.parent.CHOICE_SPEAKER_DEVICE), - state="disabled" ) self.optionmenu_input_speaker_device.grid(row=4, column=1, columnspan=3 ,padx=5, pady=5, sticky="nsew") @@ -290,59 +289,65 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.tabview_config.tab("Transcription"), text="Input Speaker Voice Language:", fg_color="transparent", - font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY, overstrike=True) + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) self.label_input_speaker_voice_language.grid(row=5, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") self.optionmenu_input_speaker_voice_language = customtkinter.CTkOptionMenu( self.tabview_config.tab("Transcription"), values=list(self.parent.vr.languages), - # command=self.optionmenu_input_speaker_voice_language_callback, + command=self.optionmenu_input_speaker_voice_language_callback, font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), variable=customtkinter.StringVar(value=self.parent.INPUT_SPEAKER_VOICE_LANGUAGE), - state="disabled" ) self.optionmenu_input_speaker_voice_language.grid(row=5, column=1, columnspan=3 ,padx=5, pady=5, sticky="nsew") - ## checkbox input speaker in dynamic - self.label_input_speaker_is_dynamic = customtkinter.CTkLabel( + ## entry input speaker sampling rate + self.label_input_speaker_sampling_rate = customtkinter.CTkLabel( self.tabview_config.tab("Transcription"), - text="Input Speaker IsDynamic:", + text="Input Speaker SamplingRate:", fg_color="transparent", - font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY, overstrike=True) + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) - self.label_input_speaker_is_dynamic.grid(row=6, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") - self.checkbox_input_speaker_is_dynamic = customtkinter.CTkCheckBox( + self.label_input_speaker_sampling_rate.grid(row=6, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") + self.entry_input_speaker_sampling_rate = customtkinter.CTkEntry( self.tabview_config.tab("Transcription"), - text="", - onvalue=True, - offvalue=False, - # command=self.checkbox_input_speaker_is_dynamic_callback, - font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), - state="disabled" + textvariable=customtkinter.StringVar(value=self.parent.INPUT_SPEAKER_SAMPLING_RATE), + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) - self.checkbox_input_speaker_is_dynamic.grid(row=6, column=1, columnspan=3 ,padx=5, pady=5, sticky="nsew") - if self.parent.ENABLE_SPEAKER_IS_DYNAMIC is True: - self.checkbox_input_speaker_is_dynamic.select() - else: - self.checkbox_input_speaker_is_dynamic.deselect() + self.entry_input_speaker_sampling_rate.grid(row=6, column=1, columnspan=3 ,padx=5, pady=5, sticky="nsew") + self.entry_input_speaker_sampling_rate.bind("", self.entry_input_speaker_sampling_rate_callback) - ## slider input speaker threshold - self.label_input_speaker_threshold = customtkinter.CTkLabel( + ## entry input speaker interval + self.label_input_speaker_interval = customtkinter.CTkLabel( self.tabview_config.tab("Transcription"), - text="Input Speaker Threshold:", + text="Input Speaker Interval:", fg_color="transparent", - font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY, overstrike=True) + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) - self.label_input_speaker_threshold.grid(row=7, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") - self.slider_input_speaker_threshold = customtkinter.CTkSlider( + self.label_input_speaker_interval.grid(row=7, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") + self.entry_input_speaker_interval = customtkinter.CTkEntry( self.tabview_config.tab("Transcription"), - from_=0, - to=300, - # command=self.slider_input_speaker_threshold_callback, - variable=tk.DoubleVar(value=self.parent.SPEAKER_THRESHOLD), - state="disabled" + textvariable=customtkinter.StringVar(value=self.parent.INPUT_SPEAKER_INTERVAL), + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) - self.slider_input_speaker_threshold.grid(row=7, column=1, columnspan=3 ,padx=5, pady=10, sticky="nsew") + self.entry_input_speaker_interval.grid(row=7, column=1, columnspan=3 ,padx=5, pady=5, sticky="nsew") + self.entry_input_speaker_interval.bind("", self.entry_input_speaker_interval_callback) + + ## entry input speaker buffer size + self.label_input_speaker_buffer_size = customtkinter.CTkLabel( + self.tabview_config.tab("Transcription"), + text="Input Speaker BufferSize:", + fg_color="transparent", + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) + ) + self.label_input_speaker_buffer_size.grid(row=8, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") + self.entry_input_speaker_buffer_size = customtkinter.CTkEntry( + self.tabview_config.tab("Transcription"), + textvariable=customtkinter.StringVar(value=self.parent.INPUT_SPEAKER_BUFFER_SIZE), + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) + ) + self.entry_input_speaker_buffer_size.grid(row=8, column=1, columnspan=3 ,padx=5, pady=5, sticky="nsew") + self.entry_input_speaker_buffer_size.bind("", self.entry_input_speaker_buffer_size_callback) # tab Parameter ## entry ip address @@ -522,10 +527,10 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): def optionmenu_translation_translator_callback(self, choice): if self.parent.translator.authentication(choice, self.parent.AUTH_KEYS[choice]) is False: - self.parent.textbox_message_log.configure(state='normal') - self.parent.textbox_message_log.insert("end", f"[ERROR]Auth Keyを設定してないか間違っています\n") - self.parent.textbox_message_log.configure(state='disabled') - self.parent.textbox_message_log.see("end") + self.parent.textbox_message_system_log.configure(state='normal') + self.parent.textbox_message_system_log.insert("end", f"[ERROR]Auth Keyを設定してないか間違っています\n") + self.parent.textbox_message_system_log.configure(state='disabled') + self.parent.textbox_message_system_log.see("end") else: self.optionmenu_translation_input_source_language.configure( values=self.parent.translator.languages[choice], @@ -559,14 +564,34 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): def checkbox_input_mic_is_dynamic_callback(self): value = self.checkbox_input_mic_is_dynamic.get() - self.parent.ENABLE_MIC_IS_DYNAMIC = value - utils.save_json(self.parent.PATH_CONFIG, "ENABLE_MIC_IS_DYNAMIC", self.parent.ENABLE_MIC_IS_DYNAMIC) - self.parent.vr.init_mic(threshold=self.parent.MIC_THRESHOLD, is_dynamic=self.parent.ENABLE_MIC_IS_DYNAMIC) + self.parent.INPUT_MIC_IS_DYNAMIC = value + utils.save_json(self.parent.PATH_CONFIG, "INPUT_MIC_IS_DYNAMIC", self.parent.INPUT_MIC_IS_DYNAMIC) + self.parent.vr.set_mic(self.parent.CHOICE_MIC_DEVICE, threshold=self.parent.INPUT_MIC_THRESHOLD, is_dynamic=self.parent.INPUT_MIC_IS_DYNAMIC) def slider_input_mic_threshold_callback(self, value): - self.parent.MIC_THRESHOLD = value - utils.save_json(self.parent.PATH_CONFIG, "MIC_THRESHOLD", self.parent.MIC_THRESHOLD) - self.parent.vr.init_mic(threshold=self.parent.MIC_THRESHOLD, is_dynamic=self.parent.ENABLE_MIC_IS_DYNAMIC) + self.parent.INPUT_MIC_THRESHOLD = value + utils.save_json(self.parent.PATH_CONFIG, "INPUT_MIC_THRESHOLD", self.parent.INPUT_MIC_THRESHOLD) + self.parent.vr.set_mic(self.parent.CHOICE_MIC_DEVICE, threshold=self.parent.INPUT_MIC_THRESHOLD, is_dynamic=self.parent.INPUT_MIC_IS_DYNAMIC) + + def optionmenu_input_speaker_device_callback(self, choice): + self.parent.CHOICE_SPEAKER_DEVICE = choice + utils.save_json(self.parent.PATH_CONFIG, "CHOICE_SPEAKER_DEVICE", self.parent.CHOICE_SPEAKER_DEVICE) + + def optionmenu_input_speaker_voice_language_callback(self, choice): + self.parent.INPUT_SPEAKER_VOICE_LANGUAGE = choice + utils.save_json(self.parent.PATH_CONFIG, "INPUT_SPEAKER_VOICE_LANGUAGE", self.parent.INPUT_SPEAKER_VOICE_LANGUAGE) + + def entry_input_speaker_sampling_rate_callback(self, event): + self.parent.INPUT_SPEAKER_SAMPLING_RATE = int(self.entry_input_speaker_sampling_rate.get()) + utils.save_json(self.parent.PATH_CONFIG, "INPUT_SPEAKER_SAMPLING_RATE", self.parent.INPUT_SPEAKER_SAMPLING_RATE) + + def entry_input_speaker_interval_callback(self, event): + self.parent.INPUT_SPEAKER_INTERVAL = int(self.entry_input_speaker_interval.get()) + utils.save_json(self.parent.PATH_CONFIG, "INPUT_SPEAKER_INTERVAL", self.parent.INPUT_SPEAKER_INTERVAL) + + def entry_input_speaker_buffer_size_callback(self, event): + self.parent.INPUT_SPEAKER_BUFFER_SIZE = int(self.entry_input_speaker_buffer_size.get()) + utils.save_json(self.parent.PATH_CONFIG, "INPUT_SPEAKER_BUFFER_SIZE", self.parent.INPUT_SPEAKER_BUFFER_SIZE) def update_ip_address(self): value = self.entry_ip_address.get() @@ -583,19 +608,14 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): def update_authkey(self): value = self.entry_authkey.get() if len(value) > 0: - self.parent.textbox_message_log.configure(state='normal') - self.parent.textbox_message_log.delete("0.0", "end") - self.parent.textbox_message_log.configure(state='disabled') - self.parent.textbox_message_log.see("end") - if self.parent.translator.authentication(self.parent.CHOICE_TRANSLATOR, self.parent.AUTH_KEYS[self.parent.CHOICE_TRANSLATOR]) is True: self.parent.AUTH_KEYS["DeepL(auth)"] = value utils.save_json(self.parent.PATH_CONFIG, "AUTH_KEYS", self.parent.AUTH_KEYS) else: - self.parent.textbox_message_log.configure(state='normal') - self.parent.textbox_message_log.insert("end", f"[ERROR]Auth Keyを設定してないか間違っています\n") - self.parent.textbox_message_log.configure(state='disabled') - self.parent.textbox_message_log.see("end") + self.parent.textbox_message_system_log.configure(state='normal') + self.parent.textbox_message_system_log.insert("end", f"[ERROR]Auth Keyを設定してないか間違っています\n") + self.parent.textbox_message_system_log.configure(state='disabled') + self.parent.textbox_message_system_log.see("end") def update_message_format(self): value = self.entry_message_format.get() From 115d3a75c6d837f1ae77c5f5e31e1230ed9168cc Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Tue, 13 Jun 2023 18:39:18 +0900 Subject: [PATCH 4/9] add output language optionmenu --- VRCT.py | 14 ++++++------- window_config.py | 54 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/VRCT.py b/VRCT.py index 016053ed..94c38452 100644 --- a/VRCT.py +++ b/VRCT.py @@ -30,15 +30,15 @@ class App(customtkinter.CTk): self.CHOICE_TRANSLATOR = "DeepL(web)" self.INPUT_SOURCE_LANG = "JA" self.INPUT_TARGET_LANG = "EN" - self.OUTPUT_SOURCE_LANG = "JA" - self.OUTPUT_TARGET_LANG = "EN" + self.OUTPUT_SOURCE_LANG = "EN" + self.OUTPUT_TARGET_LANG = "JA" ## Transcription self.CHOICE_MIC_DEVICE = None self.INPUT_MIC_VOICE_LANGUAGE = "ja-JP" self.INPUT_MIC_IS_DYNAMIC = False self.INPUT_MIC_THRESHOLD = 300 self.CHOICE_SPEAKER_DEVICE = None - self.INPUT_SPEAKER_VOICE_LANGUAGE = "ja-JP" + self.INPUT_SPEAKER_VOICE_LANGUAGE = "en-US" self.INPUT_SPEAKER_SAMPLING_RATE = 16000 self.INPUT_SPEAKER_INTERVAL = 3 self.INPUT_SPEAKER_BUFFER_SIZE = 4096 @@ -421,14 +421,14 @@ class App(customtkinter.CTk): else: result = self.translator.translate( translator_name=self.CHOICE_TRANSLATOR, - source_language=self.INPUT_SOURCE_LANG, - target_language=self.INPUT_TARGET_LANG, + source_language=self.OUTPUT_SOURCE_LANG, + target_language=self.OUTPUT_TARGET_LANG, message=message ) voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) # send OSC message - osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) + # osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message receive log self.textbox_message_receive_log.configure(state='normal') @@ -472,7 +472,7 @@ class App(customtkinter.CTk): chat_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) # send OSC message - # osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT) + osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message log self.textbox_message_receive_log.configure(state='normal') diff --git a/window_config.py b/window_config.py index db17e496..eb451b97 100644 --- a/window_config.py +++ b/window_config.py @@ -158,18 +158,17 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.tabview_config.tab("Translation"), text="Output Language:", fg_color="transparent", - font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY, overstrike=True) + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) self.label_translation_output_language.grid(row=2, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") ## select translation output source language self.optionmenu_translation_output_source_language = customtkinter.CTkOptionMenu( self.tabview_config.tab("Translation"), - # command=self.optionmenu_translation_output_source_language_callback, + command=self.optionmenu_translation_output_source_language_callback, font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), values=self.parent.translator.languages[self.parent.CHOICE_TRANSLATOR], variable=customtkinter.StringVar(value=self.parent.OUTPUT_SOURCE_LANG), - state="disabled", ) self.optionmenu_translation_output_source_language.grid(row=2, column=1, columnspan=1, padx=5, pady=5, sticky="nsew") @@ -185,11 +184,10 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): ## select translation output target language self.optionmenu_translation_output_target_language = customtkinter.CTkOptionMenu( self.tabview_config.tab("Translation"), - # command=self.optionmenu_translation_output_target_language_callback, + command=self.optionmenu_translation_output_target_language_callback, font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY), values=self.parent.translator.languages[self.parent.CHOICE_TRANSLATOR], variable=customtkinter.StringVar(value=self.parent.OUTPUT_TARGET_LANG), - state="disabled", ) self.optionmenu_translation_output_target_language.grid(row=2, column=3, columnspan=1, padx=5, pady=5, sticky="nsew") @@ -250,7 +248,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): else: self.checkbox_input_mic_is_dynamic.deselect() - ## slider input mic threshold + ## entry input mic threshold self.label_input_mic_threshold = customtkinter.CTkLabel( self.tabview_config.tab("Transcription"), text="Input Mic Threshold:", @@ -258,14 +256,13 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) self.label_input_mic_threshold.grid(row=3, column=0, columnspan=1, padx=5, pady=5, sticky="nsw") - self.slider_input_mic_threshold = customtkinter.CTkSlider( + self.entry_input_mic_threshold = customtkinter.CTkEntry( self.tabview_config.tab("Transcription"), - from_=0, - to=300, - command=self.slider_input_mic_threshold_callback, - variable=tk.DoubleVar(value=self.parent.INPUT_MIC_THRESHOLD), + textvariable=customtkinter.StringVar(value=self.parent.INPUT_MIC_THRESHOLD), + font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY) ) - self.slider_input_mic_threshold.grid(row=3, column=1, columnspan=3 ,padx=5, pady=10, sticky="nsew") + self.entry_input_mic_threshold.grid(row=3, column=1, columnspan=3 ,padx=5, pady=10, sticky="nsew") + self.entry_input_mic_threshold.bind("", self.entry_input_mic_threshold_callback) ## optionmenu input speaker device self.label_input_speaker_device = customtkinter.CTkLabel( @@ -495,8 +492,13 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.optionmenu_input_speaker_device.configure(font=customtkinter.CTkFont(family=choice)) self.label_input_speaker_voice_language.configure(font=customtkinter.CTkFont(family=choice)) self.optionmenu_input_speaker_voice_language.configure(font=customtkinter.CTkFont(family=choice)) - self.label_input_speaker_is_dynamic.configure(font=customtkinter.CTkFont(family=choice)) - self.label_input_speaker_threshold.configure(font=customtkinter.CTkFont(family=choice)) + self.label_input_speaker_sampling_rate.configure(font=customtkinter.CTkFont(family=choice)) + self.entry_input_speaker_sampling_rate.configure(font=customtkinter.CTkFont(family=choice)) + self.label_input_speaker_interval.configure(font=customtkinter.CTkFont(family=choice)) + self.entry_input_speaker_interval.configure(font=customtkinter.CTkFont(family=choice)) + self.label_input_speaker_buffer_size.configure(font=customtkinter.CTkFont(family=choice)) + self.entry_input_speaker_buffer_size.configure(font=customtkinter.CTkFont(family=choice)) + # tab Parameter self.label_ip_address.configure(font=customtkinter.CTkFont(family=choice)) @@ -538,13 +540,23 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.optionmenu_translation_input_target_language.configure( values=self.parent.translator.languages[choice], variable=customtkinter.StringVar(value=self.parent.translator.languages[choice][1])) + self.optionmenu_translation_output_source_language.configure( + values=self.parent.translator.languages[choice], + variable=customtkinter.StringVar(value=self.parent.translator.languages[choice][1])) + self.optionmenu_translation_output_target_language.configure( + values=self.parent.translator.languages[choice], + variable=customtkinter.StringVar(value=self.parent.translator.languages[choice][0])) self.parent.CHOICE_TRANSLATOR = choice self.parent.INPUT_SOURCE_LANG = self.parent.translator.languages[choice][0] self.parent.INPUT_TARGET_LANG = self.parent.translator.languages[choice][1] + self.parent.OUTPUT_SOURCE_LANG = self.parent.translator.languages[choice][1] + self.parent.OUTPUT_TARGET_LANG = self.parent.translator.languages[choice][0] utils.save_json(self.parent.PATH_CONFIG, "CHOICE_TRANSLATOR", self.parent.CHOICE_TRANSLATOR) utils.save_json(self.parent.PATH_CONFIG, "INPUT_SOURCE_LANG", self.parent.INPUT_SOURCE_LANG) utils.save_json(self.parent.PATH_CONFIG, "INPUT_TARGET_LANG", self.parent.INPUT_TARGET_LANG) + utils.save_json(self.parent.PATH_CONFIG, "OUTPUT_SOURCE_LANG", self.parent.OUTPUT_SOURCE_LANG) + utils.save_json(self.parent.PATH_CONFIG, "OUTPUT_TARGET_LANG", self.parent.OUTPUT_TARGET_LANG) def optionmenu_translation_input_source_language_callback(self, choice): self.parent.INPUT_SOURCE_LANG = choice @@ -554,6 +566,14 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.parent.INPUT_TARGET_LANG = choice utils.save_json(self.parent.PATH_CONFIG, "INPUT_TARGET_LANG", self.parent.INPUT_TARGET_LANG) + def optionmenu_translation_output_source_language_callback(self, choice): + self.parent.OUTPUT_SOURCE_LANG = choice + utils.save_json(self.parent.PATH_CONFIG, "OUTPUT_SOURCE_LANG", self.parent.OUTPUT_SOURCE_LANG) + + def optionmenu_translation_output_target_language_callback(self, choice): + self.parent.OUTPUT_TARGET_LANG = choice + utils.save_json(self.parent.PATH_CONFIG, "OUTPUT_TARGET_LANG", self.parent.OUTPUT_TARGET_LANG) + def optionmenu_input_mic_device_callback(self, choice): self.parent.CHOICE_MIC_DEVICE = choice utils.save_json(self.parent.PATH_CONFIG, "CHOICE_MIC_DEVICE", self.parent.CHOICE_MIC_DEVICE) @@ -566,12 +586,10 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): value = self.checkbox_input_mic_is_dynamic.get() self.parent.INPUT_MIC_IS_DYNAMIC = value utils.save_json(self.parent.PATH_CONFIG, "INPUT_MIC_IS_DYNAMIC", self.parent.INPUT_MIC_IS_DYNAMIC) - self.parent.vr.set_mic(self.parent.CHOICE_MIC_DEVICE, threshold=self.parent.INPUT_MIC_THRESHOLD, is_dynamic=self.parent.INPUT_MIC_IS_DYNAMIC) - def slider_input_mic_threshold_callback(self, value): - self.parent.INPUT_MIC_THRESHOLD = value + def entry_input_mic_threshold_callback(self, event): + self.parent.INPUT_MIC_THRESHOLD = int(self.entry_input_mic_threshold.get()) utils.save_json(self.parent.PATH_CONFIG, "INPUT_MIC_THRESHOLD", self.parent.INPUT_MIC_THRESHOLD) - self.parent.vr.set_mic(self.parent.CHOICE_MIC_DEVICE, threshold=self.parent.INPUT_MIC_THRESHOLD, is_dynamic=self.parent.INPUT_MIC_IS_DYNAMIC) def optionmenu_input_speaker_device_callback(self, choice): self.parent.CHOICE_SPEAKER_DEVICE = choice From 96472dfc81d55c475207518ca39d5b2f18e7635d Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Tue, 13 Jun 2023 19:17:30 +0900 Subject: [PATCH 5/9] add translation send/receive checkbox --- VRCT.py | 100 +++++++++++++++++++++++++++++------------------ window_config.py | 3 +- 2 files changed, 65 insertions(+), 38 deletions(-) diff --git a/VRCT.py b/VRCT.py index 94c38452..e3b12206 100644 --- a/VRCT.py +++ b/VRCT.py @@ -19,7 +19,8 @@ class App(customtkinter.CTk): self.PATH_CONFIG = "./config.json" ## main window self.ENABLE_TRANSLATION = False - self.ENABLE_TRANSCRIPTION = False + self.ENABLE_TRANSCRIPTION_SEND = False + self.ENABLE_TRANSCRIPTION_RECEIVE = False self.ENABLE_FOREGROUND = False ## UI self.TRANSPARENCY = 100 @@ -61,8 +62,10 @@ class App(customtkinter.CTk): # main window if "ENABLE_TRANSLATION" in config.keys(): self.ENABLE_TRANSLATION = config["ENABLE_TRANSLATION"] - if "ENABLE_TRANSCRIPTION" in config.keys(): - self.ENABLE_TRANSCRIPTION = config["ENABLE_TRANSCRIPTION"] + if "ENABLE_TRANSCRIPTION_SEND" in config.keys(): + self.ENABLE_TRANSCRIPTION_SEND = config["ENABLE_TRANSCRIPTION_SEND"] + if "ENABLE_TRANSCRIPTION_RECEIVE" in config.keys(): + self.ENABLE_TRANSCRIPTION_RECEIVE = config["ENABLE_TRANSCRIPTION_RECEIVE"] if "ENABLE_FOREGROUND" in config.keys(): self.ENABLE_FOREGROUND = config["ENABLE_FOREGROUND"] @@ -121,7 +124,8 @@ class App(customtkinter.CTk): with open(self.PATH_CONFIG, 'w') as fp: config = { "ENABLE_TRANSLATION": self.ENABLE_TRANSLATION, - "ENABLE_TRANSCRIPTION": self.ENABLE_TRANSCRIPTION, + "ENABLE_TRANSCRIPTION_SEND": self.ENABLE_TRANSCRIPTION_SEND, + "ENABLE_TRANSCRIPTION_RECEIVE": self.ENABLE_TRANSCRIPTION_RECEIVE, "ENABLE_FOREGROUND": self.ENABLE_FOREGROUND, "TRANSPARENCY": self.TRANSPARENCY, "APPEARANCE_THEME": self.APPEARANCE_THEME, @@ -172,16 +176,27 @@ class App(customtkinter.CTk): ) self.checkbox_translation.grid(row=0, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we") - # add checkbox transcription - self.checkbox_transcription = customtkinter.CTkCheckBox( + # add checkbox transcription send + self.checkbox_transcription_send = customtkinter.CTkCheckBox( self.sidebar_frame, - text="Transcription", + text="TranscriptionSend", onvalue=True, offvalue=False, - command=self.checkbox_transcription_callback, + command=self.checkbox_transcription_send_callback, font=customtkinter.CTkFont(family=self.FONT_FAMILY) ) - self.checkbox_transcription.grid(row=1, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we") + self.checkbox_transcription_send.grid(row=1, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we") + + # add checkbox transcription receive + self.checkbox_transcription_receive = customtkinter.CTkCheckBox( + self.sidebar_frame, + text="TranscriptionReceive", + onvalue=True, + offvalue=False, + command=self.checkbox_transcription_receive_callback, + font=customtkinter.CTkFont(family=self.FONT_FAMILY) + ) + self.checkbox_transcription_receive.grid(row=2, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we") # add checkbox foreground self.checkbox_foreground = customtkinter.CTkCheckBox( @@ -192,7 +207,7 @@ class App(customtkinter.CTk): command=self.checkbox_foreground_callback, font=customtkinter.CTkFont(family=self.FONT_FAMILY) ) - self.checkbox_foreground.grid(row=2, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we") + self.checkbox_foreground.grid(row=3, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we") # add button information self.button_information = customtkinter.CTkButton( @@ -245,7 +260,7 @@ class App(customtkinter.CTk): font=customtkinter.CTkFont(family=self.FONT_FAMILY) ) self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - # self.textbox_message_receive_log.configure(state='disabled') + self.textbox_message_receive_log.configure(state='disabled') # add textbox message system log self.textbox_message_system_log = customtkinter.CTkTextbox( @@ -253,7 +268,7 @@ class App(customtkinter.CTk): font=customtkinter.CTkFont(family=self.FONT_FAMILY) ) self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - # self.textbox_message_system_log.configure(state='disabled') + self.textbox_message_system_log.configure(state='disabled') # add entry message box self.entry_message_box = customtkinter.CTkEntry( @@ -285,12 +300,19 @@ class App(customtkinter.CTk): else: self.checkbox_translation.deselect() - ## set checkbox enable transcription - if self.ENABLE_TRANSCRIPTION: - self.checkbox_transcription.select() + ## set checkbox enable transcription send + if self.ENABLE_TRANSCRIPTION_SEND: + self.checkbox_transcription_send.select() else: - self.checkbox_transcription.deselect() - self.checkbox_transcription_callback() + self.checkbox_transcription_send.deselect() + self.checkbox_transcription_send_callback() + + ## set checkbox enable transcription receive + if self.ENABLE_TRANSCRIPTION_RECEIVE: + self.checkbox_transcription_receive.select() + else: + self.checkbox_transcription_receive.deselect() + self.checkbox_transcription_receive_callback() ## set set checkbox enable foreground if self.ENABLE_FOREGROUND: @@ -317,10 +339,7 @@ class App(customtkinter.CTk): def button_config_callback(self): if self.config_window is None or not self.config_window.winfo_exists(): - try: - self.config_window = window_config.ToplevelWindowConfig(self) - except Exception as e: - print(e) + self.config_window = window_config.ToplevelWindowConfig(self) self.config_window.focus() def button_information_callback(self): @@ -339,30 +358,37 @@ class App(customtkinter.CTk): self.textbox_message_system_log.see("end") utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSLATION", self.ENABLE_TRANSLATION) - def checkbox_transcription_callback(self): - self.ENABLE_TRANSCRIPTION = self.checkbox_transcription.get() - if self.ENABLE_TRANSCRIPTION is True: + def checkbox_transcription_send_callback(self): + self.ENABLE_TRANSCRIPTION_SEND = self.checkbox_transcription_send.get() + if self.ENABLE_TRANSCRIPTION_SEND is True: # start threading self.vr.set_mic(self.CHOICE_MIC_DEVICE, threshold=self.INPUT_MIC_THRESHOLD, is_dynamic=self.INPUT_MIC_IS_DYNAMIC) self.vr.init_mic() - - self.vr.set_spk(self.CHOICE_SPEAKER_DEVICE) - self.vr.init_spk() - th_vr_listen_mic = threading.Thread(target = self.vr_listen_mic) th_vr_recognize_mic = threading.Thread(target = self.vr_recognize_mic) - th_vr_listen_spk = threading.Thread(target = self.vr_listen_spk) - th_vr_recognize_spk = threading.Thread(target = self.vr_recognize_spk) - th_vr_listen_mic.start() th_vr_recognize_mic.start() + utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_SEND", self.ENABLE_TRANSCRIPTION_SEND) + + def checkbox_transcription_receive_callback(self): + self.ENABLE_TRANSCRIPTION_RECEIVE = self.checkbox_transcription_receive.get() + if self.ENABLE_TRANSCRIPTION_RECEIVE is True: + # start threading + self.vr.set_spk( + self.CHOICE_SPEAKER_DEVICE, + # int(self.INPUT_SPEAKER_SAMPLING_RATE), + # int(self.INPUT_SPEAKER_INTERVAL), + # int(self.INPUT_SPEAKER_BUFFER_SIZE), + ) + self.vr.init_spk() + th_vr_listen_spk = threading.Thread(target = self.vr_listen_spk) + th_vr_recognize_spk = threading.Thread(target = self.vr_recognize_spk) th_vr_listen_spk.start() th_vr_recognize_spk.start() - - utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION", self.ENABLE_TRANSCRIPTION) + utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_RECEIVE", self.ENABLE_TRANSCRIPTION_RECEIVE) def vr_listen_mic(self): - while self.checkbox_transcription.get() is True: + while self.checkbox_transcription_send.get() is True: self.vr.listen_mic() def vr_recognize_mic(self): @@ -371,7 +397,7 @@ class App(customtkinter.CTk): self.textbox_message_system_log.configure(state='disabled') self.textbox_message_system_log.see("end") - while self.checkbox_transcription.get() is True: + while self.checkbox_transcription_send.get() is True: message = self.vr.recognize_mic(language=self.INPUT_MIC_VOICE_LANGUAGE) if len(message) > 0: # translate @@ -402,11 +428,11 @@ class App(customtkinter.CTk): self.textbox_message_send_log.see("end") def vr_listen_spk(self): - while self.checkbox_transcription.get() is True: + while self.checkbox_transcription_receive.get() is True: self.vr.listen_spk() def vr_recognize_spk(self): - while self.checkbox_transcription.get() is True: + while self.checkbox_transcription_receive.get() is True: message = self.vr.recognize_spk(language=self.INPUT_SPEAKER_VOICE_LANGUAGE) if len(message) > 0: # translate diff --git a/window_config.py b/window_config.py index eb451b97..2ccc623d 100644 --- a/window_config.py +++ b/window_config.py @@ -512,7 +512,8 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): # main window self.parent.checkbox_translation.configure(font=customtkinter.CTkFont(family=choice)) - self.parent.checkbox_transcription.configure(font=customtkinter.CTkFont(family=choice)) + self.parent.checkbox_transcription_send.configure(font=customtkinter.CTkFont(family=choice)) + self.parent.checkbox_transcription_receive.configure(font=customtkinter.CTkFont(family=choice)) self.parent.checkbox_foreground.configure(font=customtkinter.CTkFont(family=choice)) self.parent.textbox_message_log.configure(font=customtkinter.CTkFont(family=choice)) self.parent.entry_message_box.configure(font=customtkinter.CTkFont(family=choice)) From 0f4b63e67b312c783f091fc7dfd59da9653eaf71 Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Wed, 14 Jun 2023 09:03:22 +0900 Subject: [PATCH 6/9] update func change font --- window_config.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/window_config.py b/window_config.py index 2ccc623d..5606183c 100644 --- a/window_config.py +++ b/window_config.py @@ -515,7 +515,9 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.parent.checkbox_transcription_send.configure(font=customtkinter.CTkFont(family=choice)) self.parent.checkbox_transcription_receive.configure(font=customtkinter.CTkFont(family=choice)) self.parent.checkbox_foreground.configure(font=customtkinter.CTkFont(family=choice)) - self.parent.textbox_message_log.configure(font=customtkinter.CTkFont(family=choice)) + self.parent.textbox_message_send_log.configure(font=customtkinter.CTkFont(family=choice)) + self.parent.textbox_message_receive_log.configure(font=customtkinter.CTkFont(family=choice)) + self.parent.textbox_message_system_log.configure(font=customtkinter.CTkFont(family=choice)) self.parent.entry_message_box.configure(font=customtkinter.CTkFont(family=choice)) self.parent.tabview_logs._segmented_button.configure(font=customtkinter.CTkFont(family=choice)) From 35cba754ccb84e049e4f5fdb2aaccb9d37ee08ec Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Wed, 14 Jun 2023 22:37:43 +0900 Subject: [PATCH 7/9] bugfix --- VRCT.py | 28 ++++++++++++++++------------ window_config.py | 1 - 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/VRCT.py b/VRCT.py index e3b12206..de0c0c81 100644 --- a/VRCT.py +++ b/VRCT.py @@ -155,8 +155,8 @@ class App(customtkinter.CTk): # init main window self.iconbitmap(os.path.join(os.path.dirname(__file__), "img", "app.ico")) self.title("VRCT") - self.geometry(f"{400}x{140}") - self.minsize(400, 140) + self.geometry(f"{400}x{170}") + self.minsize(400, 170) self.grid_columnconfigure(1, weight=1) self.grid_rowconfigure(0, weight=1) @@ -362,7 +362,11 @@ class App(customtkinter.CTk): self.ENABLE_TRANSCRIPTION_SEND = self.checkbox_transcription_send.get() if self.ENABLE_TRANSCRIPTION_SEND is True: # start threading - self.vr.set_mic(self.CHOICE_MIC_DEVICE, threshold=self.INPUT_MIC_THRESHOLD, is_dynamic=self.INPUT_MIC_IS_DYNAMIC) + self.vr.set_mic( + device_name=self.CHOICE_MIC_DEVICE, + threshold=int(self.INPUT_MIC_THRESHOLD), + is_dynamic=self.INPUT_MIC_IS_DYNAMIC, + ) self.vr.init_mic() th_vr_listen_mic = threading.Thread(target = self.vr_listen_mic) th_vr_recognize_mic = threading.Thread(target = self.vr_recognize_mic) @@ -375,10 +379,10 @@ class App(customtkinter.CTk): if self.ENABLE_TRANSCRIPTION_RECEIVE is True: # start threading self.vr.set_spk( - self.CHOICE_SPEAKER_DEVICE, - # int(self.INPUT_SPEAKER_SAMPLING_RATE), - # int(self.INPUT_SPEAKER_INTERVAL), - # int(self.INPUT_SPEAKER_BUFFER_SIZE), + device_name=self.CHOICE_SPEAKER_DEVICE, + sample_rate=int(self.INPUT_SPEAKER_SAMPLING_RATE), + interval=int(self.INPUT_SPEAKER_INTERVAL), + buffer_size=int(self.INPUT_SPEAKER_BUFFER_SIZE), ) self.vr.init_spk() th_vr_listen_spk = threading.Thread(target = self.vr_listen_spk) @@ -482,7 +486,7 @@ class App(customtkinter.CTk): # translate if self.checkbox_translation.get() is False: chat_message = f"{message}" - elif (self.translator.translator_status[self.CHOICE_TRANSLATOR] is False) or (self.INPUT_SOURCE_LANG == "None") or (self.INPUT_TARGET_LANG == "None"): + elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: self.textbox_message_system_log.configure(state='normal') self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") self.textbox_message_system_log.configure(state='disabled') @@ -501,10 +505,10 @@ class App(customtkinter.CTk): osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message log - self.textbox_message_receive_log.configure(state='normal') - self.textbox_message_receive_log.insert("end", f"[CHAT] {chat_message}\n") - self.textbox_message_receive_log.configure(state='disabled') - self.textbox_message_receive_log.see("end") + self.textbox_message_send_log.configure(state='normal') + self.textbox_message_send_log.insert("end", f"[CHAT] {chat_message}\n") + self.textbox_message_send_log.configure(state='disabled') + self.textbox_message_send_log.see("end") # delete message in entry message box # self.entry_message_box.delete(0, customtkinter.END) diff --git a/window_config.py b/window_config.py index 5606183c..c1cf3fd4 100644 --- a/window_config.py +++ b/window_config.py @@ -499,7 +499,6 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.label_input_speaker_buffer_size.configure(font=customtkinter.CTkFont(family=choice)) self.entry_input_speaker_buffer_size.configure(font=customtkinter.CTkFont(family=choice)) - # tab Parameter self.label_ip_address.configure(font=customtkinter.CTkFont(family=choice)) self.entry_ip_address.configure(font=customtkinter.CTkFont(family=choice)) From cb5b4f4e499ded53bcd890f327c248ebf59cc065 Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Thu, 15 Jun 2023 01:03:36 +0900 Subject: [PATCH 8/9] update textbox print message --- VRCT.py | 72 ++++++++++++++++++++++-------------------------- utils.py | 11 +++++++- window_config.py | 10 ++----- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/VRCT.py b/VRCT.py index de0c0c81..b2975b76 100644 --- a/VRCT.py +++ b/VRCT.py @@ -244,7 +244,6 @@ class App(customtkinter.CTk): self.tabview_logs.tab("receive").grid_columnconfigure(0, weight=1) self.tabview_logs.tab("system").grid_rowconfigure(0, weight=1) self.tabview_logs.tab("system").grid_columnconfigure(0, weight=1) - # self.tabview_logs.configure(state='disabled') # add textbox message send log self.textbox_message_send_log = customtkinter.CTkTextbox( @@ -283,10 +282,7 @@ class App(customtkinter.CTk): self.translator = translation.Translator() if self.translator.authentication(self.CHOICE_TRANSLATOR, self.AUTH_KEYS[self.CHOICE_TRANSLATOR]) is False: # error update Auth key - self.textbox_message_system_log.configure(state='normal') - self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyを設定してないか間違っています\n") - self.textbox_message_system_log.configure(state='disabled') - self.textbox_message_system_log.see("end") + utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") ## set transcription instance self.vr = transcription.VoiceRecognizer() @@ -307,6 +303,9 @@ class App(customtkinter.CTk): self.checkbox_transcription_send.deselect() self.checkbox_transcription_send_callback() + ## init threads send + self.threads_send = [] + ## set checkbox enable transcription receive if self.ENABLE_TRANSCRIPTION_RECEIVE: self.checkbox_transcription_receive.select() @@ -314,6 +313,9 @@ class App(customtkinter.CTk): self.checkbox_transcription_receive.deselect() self.checkbox_transcription_receive_callback() + ## init threads receive + self.threads_receive = [] + ## set set checkbox enable foreground if self.ENABLE_FOREGROUND: self.checkbox_foreground.select() @@ -337,6 +339,9 @@ class App(customtkinter.CTk): customtkinter.set_appearance_mode(self.APPEARANCE_THEME) customtkinter.set_default_color_theme("blue") + # delete window + self.protocol("WM_DELETE_WINDOW", self.delete_window) + def button_config_callback(self): if self.config_window is None or not self.config_window.winfo_exists(): self.config_window = window_config.ToplevelWindowConfig(self) @@ -349,13 +354,10 @@ class App(customtkinter.CTk): def checkbox_translation_callback(self): self.ENABLE_TRANSLATION = self.checkbox_translation.get() - self.textbox_message_system_log.configure(state='normal') if self.ENABLE_TRANSLATION: - self.textbox_message_system_log.insert("end", f"[INFO] start translation\n") + utils.print_textbox(self.textbox_message_system_log, "[info] Start translation") else: - self.textbox_message_system_log.insert("end", f"[INFO] stop translation\n") - self.textbox_message_system_log.configure(state='disabled') - self.textbox_message_system_log.see("end") + utils.print_textbox(self.textbox_message_system_log, "[info] Stop translation") utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSLATION", self.ENABLE_TRANSLATION) def checkbox_transcription_send_callback(self): @@ -372,6 +374,8 @@ class App(customtkinter.CTk): th_vr_recognize_mic = threading.Thread(target = self.vr_recognize_mic) th_vr_listen_mic.start() th_vr_recognize_mic.start() + self.threads_send.append(th_vr_listen_mic) + self.threads_send.append(th_vr_recognize_mic) utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_SEND", self.ENABLE_TRANSCRIPTION_SEND) def checkbox_transcription_receive_callback(self): @@ -389,6 +393,8 @@ class App(customtkinter.CTk): th_vr_recognize_spk = threading.Thread(target = self.vr_recognize_spk) th_vr_listen_spk.start() th_vr_recognize_spk.start() + self.threads_receive.append(th_vr_listen_spk) + self.threads_receive.append(th_vr_recognize_spk) utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_RECEIVE", self.ENABLE_TRANSCRIPTION_RECEIVE) def vr_listen_mic(self): @@ -396,11 +402,7 @@ class App(customtkinter.CTk): self.vr.listen_mic() def vr_recognize_mic(self): - self.textbox_message_system_log.configure(state='normal') - self.textbox_message_system_log.insert("end", f"[INFO] start transcription\n") - self.textbox_message_system_log.configure(state='disabled') - self.textbox_message_system_log.see("end") - + utils.print_textbox(self.textbox_message_system_log, "[info] Start sending transcription from your voice") while self.checkbox_transcription_send.get() is True: message = self.vr.recognize_mic(language=self.INPUT_MIC_VOICE_LANGUAGE) if len(message) > 0: @@ -408,10 +410,7 @@ class App(customtkinter.CTk): if self.checkbox_translation.get() is False: voice_message = f"{message}" elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: - self.textbox_message_system_log.configure(state='normal') - self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") - self.textbox_message_system_log.configure(state='disabled') - self.textbox_message_system_log.see("end") + utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") voice_message = f"{message}" else: result = self.translator.translate( @@ -426,16 +425,17 @@ class App(customtkinter.CTk): osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message log - self.textbox_message_send_log.configure(state='normal') - self.textbox_message_send_log.insert("end", f"[VOICE] {voice_message}\n") - self.textbox_message_send_log.configure(state='disabled') - self.textbox_message_send_log.see("end") + utils.print_textbox(self.textbox_message_send_log, f"[voice] {voice_message}") + utils.print_textbox(self.textbox_message_system_log, "[info] Stop sending transcription from your voice") + for t in self.threads_send: + t.join() def vr_listen_spk(self): while self.checkbox_transcription_receive.get() is True: self.vr.listen_spk() def vr_recognize_spk(self): + utils.print_textbox(self.textbox_message_system_log, "[info] Start transcription of speaker's voice") while self.checkbox_transcription_receive.get() is True: message = self.vr.recognize_spk(language=self.INPUT_SPEAKER_VOICE_LANGUAGE) if len(message) > 0: @@ -443,10 +443,7 @@ class App(customtkinter.CTk): if self.checkbox_translation.get() is False: voice_message = f"{message}" elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: - self.textbox_message_system_log.configure(state='normal') - self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") - self.textbox_message_system_log.configure(state='disabled') - self.textbox_message_system_log.see("end") + utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") voice_message = f"{message}" else: result = self.translator.translate( @@ -461,10 +458,10 @@ class App(customtkinter.CTk): # osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message receive log - self.textbox_message_receive_log.configure(state='normal') - self.textbox_message_receive_log.insert("end", f"[VOICE] {voice_message}\n") - self.textbox_message_receive_log.configure(state='disabled') - self.textbox_message_receive_log.see("end") + utils.print_textbox(self.textbox_message_receive_log, f"[voice] {voice_message}") + utils.print_textbox(self.textbox_message_system_log, "[info] Stop transcription of speaker's voice") + for t in self.threads_receive: + t.join() def checkbox_foreground_callback(self): self.ENABLE_FOREGROUND = self.checkbox_foreground.get() @@ -487,10 +484,7 @@ class App(customtkinter.CTk): if self.checkbox_translation.get() is False: chat_message = f"{message}" elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: - self.textbox_message_system_log.configure(state='normal') - self.textbox_message_system_log.insert("end", f"[ERROR] Auth Keyもしくは言語の設定が間違っています\n") - self.textbox_message_system_log.configure(state='disabled') - self.textbox_message_system_log.see("end") + utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") chat_message = f"{message}" else: result = self.translator.translate( @@ -505,10 +499,7 @@ class App(customtkinter.CTk): osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT) # update textbox message log - self.textbox_message_send_log.configure(state='normal') - self.textbox_message_send_log.insert("end", f"[CHAT] {chat_message}\n") - self.textbox_message_send_log.configure(state='disabled') - self.textbox_message_send_log.see("end") + utils.print_textbox(self.textbox_message_send_log, f"[chat] {chat_message}") # delete message in entry message box # self.entry_message_box.delete(0, customtkinter.END) @@ -525,6 +516,9 @@ class App(customtkinter.CTk): if self.ENABLE_FOREGROUND: self.attributes("-topmost", True) + def delete_window(self): + self.destroy() + if __name__ == "__main__": app = App() app.mainloop() \ No newline at end of file diff --git a/utils.py b/utils.py index f1937616..cb107d32 100644 --- a/utils.py +++ b/utils.py @@ -1,8 +1,17 @@ import json +import datetime def save_json(path, key, value): with open(path, "r") as fp: json_data = json.load(fp) json_data[key] = value with open(path, "w") as fp: - json.dump(json_data, fp, indent=4) \ No newline at end of file + json.dump(json_data, fp, indent=4) + +def print_textbox(textbox, message): + now = datetime.datetime.now() + now = now.strftime('%H:%M:%S') + textbox.configure(state='normal') + textbox.insert("end", f"[{now}]{message}\n") + textbox.configure(state='disabled') + textbox.see("end") \ No newline at end of file diff --git a/window_config.py b/window_config.py index c1cf3fd4..03d222eb 100644 --- a/window_config.py +++ b/window_config.py @@ -531,10 +531,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): def optionmenu_translation_translator_callback(self, choice): if self.parent.translator.authentication(choice, self.parent.AUTH_KEYS[choice]) is False: - self.parent.textbox_message_system_log.configure(state='normal') - self.parent.textbox_message_system_log.insert("end", f"[ERROR]Auth Keyを設定してないか間違っています\n") - self.parent.textbox_message_system_log.configure(state='disabled') - self.parent.textbox_message_system_log.see("end") + utils.print_textbox(self.parent.textbox_message_system_log, f"[error] Auth Key or language setting is incorrect") else: self.optionmenu_translation_input_source_language.configure( values=self.parent.translator.languages[choice], @@ -632,10 +629,7 @@ class ToplevelWindowConfig(customtkinter.CTkToplevel): self.parent.AUTH_KEYS["DeepL(auth)"] = value utils.save_json(self.parent.PATH_CONFIG, "AUTH_KEYS", self.parent.AUTH_KEYS) else: - self.parent.textbox_message_system_log.configure(state='normal') - self.parent.textbox_message_system_log.insert("end", f"[ERROR]Auth Keyを設定してないか間違っています\n") - self.parent.textbox_message_system_log.configure(state='disabled') - self.parent.textbox_message_system_log.see("end") + utils.print_textbox(self.parent.textbox_message_system_log, f"[error] Auth Key or language setting is incorrect") def update_message_format(self): value = self.entry_message_format.get() From edefa119e97385a6abcd735acb3311ab3ab4dbc0 Mon Sep 17 00:00:00 2001 From: misyaguziya Date: Thu, 15 Jun 2023 03:18:05 +0900 Subject: [PATCH 9/9] bugfix Thread close process --- VRCT.py | 156 +++++++++++++++++++++++++++---------------------------- utils.py | 18 ++++++- 2 files changed, 94 insertions(+), 80 deletions(-) diff --git a/VRCT.py b/VRCT.py index b2975b76..501ebe3b 100644 --- a/VRCT.py +++ b/VRCT.py @@ -297,31 +297,29 @@ class App(customtkinter.CTk): self.checkbox_translation.deselect() ## set checkbox enable transcription send + self.th_vr_listen_mic = None + self.th_vr_recognize_mic = None if self.ENABLE_TRANSCRIPTION_SEND: self.checkbox_transcription_send.select() + self.checkbox_transcription_send_callback() else: self.checkbox_transcription_send.deselect() - self.checkbox_transcription_send_callback() - - ## init threads send - self.threads_send = [] ## set checkbox enable transcription receive + self.th_vr_listen_spk = None + self.th_vr_recognize_spk = None if self.ENABLE_TRANSCRIPTION_RECEIVE: self.checkbox_transcription_receive.select() + self.checkbox_transcription_receive_callback() else: self.checkbox_transcription_receive.deselect() - self.checkbox_transcription_receive_callback() - - ## init threads receive - self.threads_receive = [] ## set set checkbox enable foreground if self.ENABLE_FOREGROUND: self.checkbox_foreground.select() + self.checkbox_foreground_callback() else: self.checkbox_foreground.deselect() - self.checkbox_foreground_callback() ## set bind entry message box self.entry_message_box.bind("", self.entry_message_box_press_key_enter) @@ -363,6 +361,7 @@ class App(customtkinter.CTk): def checkbox_transcription_send_callback(self): self.ENABLE_TRANSCRIPTION_SEND = self.checkbox_transcription_send.get() if self.ENABLE_TRANSCRIPTION_SEND is True: + utils.print_textbox(self.textbox_message_system_log, "[info] Start sending transcription from your voice") # start threading self.vr.set_mic( device_name=self.CHOICE_MIC_DEVICE, @@ -370,17 +369,23 @@ class App(customtkinter.CTk): is_dynamic=self.INPUT_MIC_IS_DYNAMIC, ) self.vr.init_mic() - th_vr_listen_mic = threading.Thread(target = self.vr_listen_mic) - th_vr_recognize_mic = threading.Thread(target = self.vr_recognize_mic) - th_vr_listen_mic.start() - th_vr_recognize_mic.start() - self.threads_send.append(th_vr_listen_mic) - self.threads_send.append(th_vr_recognize_mic) + self.th_vr_listen_mic = utils.thread_fnc(self.vr_listen_mic) + self.th_vr_recognize_mic = utils.thread_fnc(self.vr_recognize_mic) + self.th_vr_listen_mic.start() + self.th_vr_recognize_mic.start() + else: + if isinstance(self.th_vr_listen_mic, utils.thread_fnc): + self.th_vr_listen_mic.stop() + if isinstance(self.th_vr_recognize_mic, utils.thread_fnc): + self.th_vr_recognize_mic.stop() + + utils.print_textbox(self.textbox_message_system_log, "[info] Stop sending transcription from your voice") utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_SEND", self.ENABLE_TRANSCRIPTION_SEND) def checkbox_transcription_receive_callback(self): self.ENABLE_TRANSCRIPTION_RECEIVE = self.checkbox_transcription_receive.get() if self.ENABLE_TRANSCRIPTION_RECEIVE is True: + utils.print_textbox(self.textbox_message_system_log, "[info] Start transcription of speaker's voice") # start threading self.vr.set_spk( device_name=self.CHOICE_SPEAKER_DEVICE, @@ -389,79 +394,68 @@ class App(customtkinter.CTk): buffer_size=int(self.INPUT_SPEAKER_BUFFER_SIZE), ) self.vr.init_spk() - th_vr_listen_spk = threading.Thread(target = self.vr_listen_spk) - th_vr_recognize_spk = threading.Thread(target = self.vr_recognize_spk) - th_vr_listen_spk.start() - th_vr_recognize_spk.start() - self.threads_receive.append(th_vr_listen_spk) - self.threads_receive.append(th_vr_recognize_spk) + self.th_vr_listen_spk = utils.thread_fnc(self.vr_listen_spk) + self.th_vr_recognize_spk = utils.thread_fnc(self.vr_recognize_spk) + self.th_vr_listen_spk.start() + self.th_vr_recognize_spk.start() + else: + if isinstance(self.th_vr_listen_spk, utils.thread_fnc): + self.th_vr_listen_spk.stop() + if isinstance(self.th_vr_recognize_spk, utils.thread_fnc): + self.th_vr_recognize_spk.stop() + + utils.print_textbox(self.textbox_message_system_log, "[info] Stop transcription of speaker's voice") utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_RECEIVE", self.ENABLE_TRANSCRIPTION_RECEIVE) def vr_listen_mic(self): - while self.checkbox_transcription_send.get() is True: - self.vr.listen_mic() + self.vr.listen_mic() def vr_recognize_mic(self): - utils.print_textbox(self.textbox_message_system_log, "[info] Start sending transcription from your voice") - while self.checkbox_transcription_send.get() is True: - message = self.vr.recognize_mic(language=self.INPUT_MIC_VOICE_LANGUAGE) - if len(message) > 0: - # translate - if self.checkbox_translation.get() is False: - voice_message = f"{message}" - elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: - utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") - voice_message = f"{message}" - else: - result = self.translator.translate( - translator_name=self.CHOICE_TRANSLATOR, - source_language=self.INPUT_SOURCE_LANG, - target_language=self.INPUT_TARGET_LANG, - message=message - ) - voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) - - # send OSC message - osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) - - # update textbox message log - utils.print_textbox(self.textbox_message_send_log, f"[voice] {voice_message}") - utils.print_textbox(self.textbox_message_system_log, "[info] Stop sending transcription from your voice") - for t in self.threads_send: - t.join() + message = self.vr.recognize_mic(language=self.INPUT_MIC_VOICE_LANGUAGE) + if len(message) > 0: + # translate + if self.checkbox_translation.get() is False: + voice_message = f"{message}" + elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: + utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") + voice_message = f"{message}" + else: + result = self.translator.translate( + translator_name=self.CHOICE_TRANSLATOR, + source_language=self.INPUT_SOURCE_LANG, + target_language=self.INPUT_TARGET_LANG, + message=message + ) + voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) + # send OSC message + osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) + # update textbox message log + utils.print_textbox(self.textbox_message_send_log, f"[voice] {voice_message}") def vr_listen_spk(self): - while self.checkbox_transcription_receive.get() is True: - self.vr.listen_spk() + self.vr.listen_spk() def vr_recognize_spk(self): - utils.print_textbox(self.textbox_message_system_log, "[info] Start transcription of speaker's voice") - while self.checkbox_transcription_receive.get() is True: - message = self.vr.recognize_spk(language=self.INPUT_SPEAKER_VOICE_LANGUAGE) - if len(message) > 0: - # translate - if self.checkbox_translation.get() is False: - voice_message = f"{message}" - elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: - utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") - voice_message = f"{message}" - else: - result = self.translator.translate( - translator_name=self.CHOICE_TRANSLATOR, - source_language=self.OUTPUT_SOURCE_LANG, - target_language=self.OUTPUT_TARGET_LANG, - message=message - ) - voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) - - # send OSC message - # osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) - - # update textbox message receive log - utils.print_textbox(self.textbox_message_receive_log, f"[voice] {voice_message}") - utils.print_textbox(self.textbox_message_system_log, "[info] Stop transcription of speaker's voice") - for t in self.threads_receive: - t.join() + message = self.vr.recognize_spk(language=self.INPUT_SPEAKER_VOICE_LANGUAGE) + if len(message) > 0: + # translate + if self.checkbox_translation.get() is False: + voice_message = f"{message}" + elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False: + utils.print_textbox(self.textbox_message_system_log, "[error] Auth Key or language setting is incorrect") + voice_message = f"{message}" + else: + result = self.translator.translate( + translator_name=self.CHOICE_TRANSLATOR, + source_language=self.OUTPUT_SOURCE_LANG, + target_language=self.OUTPUT_TARGET_LANG, + message=message + ) + voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result) + # send OSC message + # osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT) + # update textbox message receive log + utils.print_textbox(self.textbox_message_receive_log, f"[voice] {voice_message}") def checkbox_foreground_callback(self): self.ENABLE_FOREGROUND = self.checkbox_foreground.get() @@ -517,6 +511,10 @@ class App(customtkinter.CTk): self.attributes("-topmost", True) def delete_window(self): + thread_list = threading.enumerate() + thread_list.remove(threading.main_thread()) + for thread in thread_list: + thread.stop() self.destroy() if __name__ == "__main__": diff --git a/utils.py b/utils.py index cb107d32..132dd03a 100644 --- a/utils.py +++ b/utils.py @@ -1,5 +1,6 @@ import json import datetime +import threading def save_json(path, key, value): with open(path, "r") as fp: @@ -14,4 +15,19 @@ def print_textbox(textbox, message): textbox.configure(state='normal') textbox.insert("end", f"[{now}]{message}\n") textbox.configure(state='disabled') - textbox.see("end") \ No newline at end of file + textbox.see("end") + +class thread_fnc(threading.Thread): + def __init__(self, fnc, *args, **kwargs): + super(thread_fnc, self).__init__(*args, **kwargs) + self.fnc = fnc + self._stop = threading.Event() + def stop(self): + self._stop.set() + def stopped(self): + return self._stop.isSet() + def run(self): + while True: + if self.stopped(): + return + self.fnc() \ No newline at end of file