欧文用と和文用アプリを一つのアプリに統合しました。
このcodeをPython にコピペすれば、働くはずです。
これがmain windowでこれにsub windowの欧文アプリと和文アプリを合体させました。
## モールス受信アプリ ver 7.0.py 10/17/2024 chatGPT_6
import PySimpleGUI as sg
import subprocess
import os
import sys
sg.theme('NeutralBlue')
# Windows の場合、CREATE_NO_WINDOW フラグを設定
if sys.platform == 'win32':
import subprocess
CREATE_NO_WINDOW = 0x08000000
else:
CREATE_NO_WINDOW = 0
# アプリ実行中のプロセスを管理する変数
proc_obun = None
proc_wabun = None
# アプリ起動時に欧文アプリを自動的に開く関数
def open_obun_app():
global proc_obun
app_path = os.path.expanduser('~/Desktop/モールス発生器 ver 7.0/欧文モールス受信アプリ e7.0.py')
if proc_obun and proc_obun.poll() is None:
proc_obun.terminate() # 既存のプロセスを終了
proc_obun = subprocess.Popen(['python', app_path], creationflags=CREATE_NO_WINDOW)
# アプリ起動時に和文アプリを自動的に開く関数
def open_wabun_app():
global proc_wabun
app_path = os.path.expanduser('~/Desktop/モールス発生器 ver 7.0/和文モールス受信アプリ j7.0.py')
if proc_wabun and proc_wabun.poll() is None:
proc_wabun.terminate() # 既存のプロセスを終了
proc_wabun = subprocess.Popen(['python', app_path], creationflags=CREATE_NO_WINDOW)
# メインウィンドウのレイアウト
layout = [
[sg.Text('', size=(10,6))], # ボタン類を一列下げるダミー
[sg.Button('欧文', size=(10, 2), key='欧文')],
[sg.Button('和文', size=(10, 2), key='和文')],
[sg.Text('', size=(10,3))],
[sg.Button('End', size=(10, 2), button_color=('blue','pink'))],
[sg.Text('', key='status')] # ここでstatusを追加
]
# ウインドウ位置, サイズ
win_location = (1000, 300)
win_size = (480, 600)
# メインウィンドウの作成
window = sg.Window("ver 7.0", layout, size=win_size, location=win_location, no_titlebar=True, grab_anywhere=True )
# イベントループ
while True:
event, values = window.read(timeout=100) # 0.1秒ごとにポーリング
# 初回起動時に欧文アプリを起動
if proc_obun is None:
open_obun_app()
# ウィンドウが閉じられた場合
if event == sg.WIN_CLOSED:
# 終了時に実行中のサブプロセスがあれば終了
if proc_obun and proc_obun.poll() is None:
proc_obun.terminate()
if proc_wabun and proc_wabun.poll() is None:
proc_wabun.terminate()
break
# End ボタンの処理
if event == 'End':
if sg.popup_yes_no('終了しますか?') == 'Yes': # 確認ポップアップ
if proc_obun and proc_obun.poll() is None:
proc_obun.terminate()
if proc_wabun and proc_wabun.poll() is None:
proc_wabun.terminate()
break
# 欧文アプリを表示
if event == "欧文":
if proc_wabun and proc_wabun.poll() is None:
proc_wabun.terminate() # 和文アプリが動作していたら終了
open_obun_app()
# 和文アプリを表示
if event == "和文":
if proc_obun and proc_obun.poll() is None:
proc_obun.terminate() # 欧文アプリが動作していたら終了
open_wabun_app()
# サブプロセスが終了している場合、再度 欧文アプリを表示
if proc_obun and proc_obun.poll() is not None:
open_obun_app()
# ウィンドウを閉じる
window.close()
---------------------------------
こちらが欧文用アプリ
# 欧文モールス受信アプリ ver e7.0.py 10/16/2024
# windowサイズ、ロケーションをmasterに合わせた
# 'あいうえお'を全て大文字で表示させるために変換必要 10/15/2024
# 何かの拍子にsubがmainの裏側に来ることがある。
import PySimpleGUI as sg
import numpy as np
import pyaudio
import time
import threading
import random
import pygame
# 初期設定
sg.theme('NeutralBlue')
p = pyaudio.PyAudio()
VOLUME = 1
SAMPLE_RATE = 44100
# pygameの初期化
pygame.mixer.init(frequency=SAMPLE_RATE)
is_playing = False
playback_thread = None # スレッドを格納する変数を追加
# 欧文モールス信号辞書
E_MORSE_CODE_DICT = {
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
'Y': '-.--', 'Z': '--..',
'0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',
'?': '..--..', ',': '--..--', '.': '.-.-.-', '/': '-..-.', '@': '.--.-.',
'-': '-....-', '(': '-.--.', ')': '-.--.-' }
# 欧文単語リスト
E_word_list = [
"kind", "surround", "university", "break", "it", "speech", "parachute",
"change", "command", "refugee", "hurt", "power", "minister", "riot",
"recover", "male", "funeral", "stop", "define", "transport", "realistic",
"mass", "universe", "street", "he", "square", "deaf", "stretch", "organize",
"neutral", "concern", "emotion", "corruption", "particle", "area", "station",
"through", "get", "inform", "tell", "transportation", "fit", "limit", "tissue",
"genocide", "old", "repeat", "dismiss", "today", "baby", "near", "television",
"fetus", "memorial", "tube", "self", "minor", "secret", "anniversary", "spring",
"earth", "class", "exercise", "desert", "modern", "ask", "where", "wave", "once",
"search", "provide", "half", "grass", "organ", "fat", "but", "supervise", "morning",
"sympathy", "with", "incite", "flower", "execute", "remove", "poverty", "year",
"industry", "close", "rebel", "drink", "liquid", "probably", "balloon", "genes",
"glass", "plot", "trick", "fly", "fine", "general", "wild", "adult", "sugar",
"victim", "so", "turn", "ice", "false", "crush", "expert", "available", "ceasefire",
"most", "when", "exchange", "overthrow", "Congress", "holy", "stone", "describe",
"torture", "tradition", "destroy", "react", "affect", "develop", "seize", "few",
"mother", "degree", "family", "holiday", "atmosphere", "by", "pipe", "aggression",
"hurry", "missing", "line", "evaporate", "resolution", "local", "nerve", "temperature",
"substance", "include", "knife", "truce", "raise", "vote", "yet", "research", "chromosome",
"help", "surprise", "ever", "discuss", "revolt", "intervene", "on", "soon", "fact",
"sheep", "skill", "shape", "play", "invite", "soil", "attention", "new", "happy",
"ecology", "announce", "voice", "possible", "awake", "money", "burn", "place",
"examine", "come", "resist", "purchase", "huge", "apologize", "insane", "struggle",
"long", "parliament", "list", "here", "south", "summer", "tie", "partner", "brief",
"store", "mental", "find", "thick"
]
def generate_tone(frequency, duration):
sample_rate = 44100
t = np.linspace(0, duration, int(sample_rate * duration), False)
tone = 32767 * np.sin(2 * np.pi * frequency * t)
fade_in_out_duration = int(sample_rate * 0.01)
fade_in = np.linspace(0, 1, fade_in_out_duration)
fade_out = np.linspace(1, 0, fade_in_out_duration)
tone[:fade_in_out_duration] *= fade_in
tone[-fade_in_out_duration:] *= fade_out
sound_array = tone.astype(np.int16)
sound_array_stereo = np.column_stack((sound_array, sound_array))
return pygame.sndarray.make_sound(sound_array_stereo)
def play_dot(frequency):
dot_sound = generate_tone(frequency, DOT_DURATION)
dot_sound.play()
time.sleep(DOT_DURATION)
def play_dash(frequency):
dash_sound = generate_tone(frequency, DASH_DURATION)
dash_sound.play()
time.sleep(DASH_DURATION)
def calculate_timings(wpm):
unit_time = 1.2 / wpm
dot_duration = unit_time
dash_duration = 3 * unit_time
symbol_space_duration = unit_time
letter_space_duration = 3 * unit_time
word_space_duration = 7 * unit_time
return dot_duration, dash_duration, symbol_space_duration, letter_space_duration, word_space_duration
def play_morse_code_for_letter(letter, frequency):
morse_code = E_MORSE_CODE_DICT.get(letter.upper(), '')
for symbol in morse_code:
if not is_playing:
break
if symbol == '.':
play_dot(frequency)
elif symbol == '-':
play_dash(frequency)
time.sleep(SYMBOL_SPACE_DURATION)
time.sleep(LETTER_SPACE_DURATION)
def play_morse_code_for_word(word, frequency):
global is_playing
for letter in word:
if not is_playing:
break
play_morse_code_for_letter(letter, frequency)
time.sleep(WORD_SPACE_DURATION)
def play_morse_code(word_sample, frequency):
global is_playing
is_playing = True
for word in word_sample:
if not is_playing:
break
play_morse_code_for_word(word, frequency)
is_playing = False
window.write_event_value('-FINISHED-', None) # 発声完了時にイベント送信
def start_playback(word_sample, frequency):
time.sleep(1) # 表示の1秒後に再生を開始
play_morse_code(word_sample, frequency)
layout = [
[sg.Text('')],
[sg.Text('欧文モールス信号', text_color='red', background_color='White', font=('Arial',18))],
[sg.Radio('欧文Auto', group_id=1, key='E_AUTO', text_color='red', default=True),
sg.Radio('欧文KB', group_id=1, key='E_KB', text_color='red')],
[sg.Text('発声単語:')],
[sg.Multiline(size=(40, 10), text_color='Blue', font=('Arial', 16, 'bold'), key='INPUT')],
[sg.Text('単語数:'), sg.Slider(range=(10, 100), default_value=40, resolution=10, orientation='h', key='NBR')],
[sg.Text('速度(Word/m):'), sg.Slider(range=(4, 20), default_value=10, resolution=1, orientation='h', key='WPM')],
[sg.Text('周波数(Hz):'), sg.Slider(range=(300, 1000), default_value=700, resolution=100, orientation='h', key='FREQ')],
[sg.Text('')],
[sg.Button('Start', size=(10, 2), key='Start', disabled=False),
sg.Button('End', size=(10, 2), key='End', disabled=False), sg.Push(),
sg.Push(), sg.Text('JA1FML ver e7.0', text_color='LightBlue')]
]
win_location = (1100, 300)
win_size = (380, 600)
window = sg.Window('欧文モールス受信 ver e7.0', layout, size = win_size, location = win_location, no_titlebar=True, grab_anywhere=True, finalize=True)
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED or event == 'End':
if is_playing:
sg.popup("発声中は「End」を押すことができません。")
else:
confirm_exit = sg.popup_yes_no('アプリを終了しますか?')
if confirm_exit == 'Yes':
break
elif event == 'Start':
if not is_playing: # 発声中でないことを確認
window['End'].update(disabled=True) # 発声開始時にEndボタンを無効にする
window['Start'].update(disabled=True) # Startボタンを無効にする
wpm = int(values['WPM'])
frequency = int(values['FREQ'])
DOT_DURATION, DASH_DURATION, SYMBOL_SPACE_DURATION, LETTER_SPACE_DURATION, WORD_SPACE_DURATION = calculate_timings(wpm)
if values['E_AUTO']:
nbr = int(values['NBR'])
word_sample = random.sample(E_word_list, nbr)
input_words = ' '.join(word_sample)
window['INPUT'].update(input_words) # 単語を入力欄に表示
playback_thread = threading.Thread(target=start_playback, args=(word_sample, frequency), daemon=True)
playback_thread.start()
elif values['E_KB']:
input_text = window['INPUT'].get().strip()
if input_text:
word_sample = input_text.split()
playback_thread = threading.Thread(target=start_playback, args=(word_sample, frequency), daemon=True)
playback_thread.start()
else:
sg.popup('発声単語を入力してください。')
elif event == '-FINISHED-': # 発声が完了したときの処理
window['End'].update(disabled=False)
window['Start'].update(disabled=False)
window.close()
------------------------------------
こちらが和文用アプリ
# 和文モールス受信window j6.0.py 10/15/2024
# windowサイズ、ロケーションをmasterに合わせた
# 'あいうえお'を全て大文字で表示させるために変換必要 10/15/2024
# 何かの拍子にsubがmainの裏側に来ることがある。
import PySimpleGUI as sg
import numpy as np
import pyaudio
import time
import threading
import random
import pygame
# 初期設定
sg.theme('NeutralBlue')
p = pyaudio.PyAudio()
VOLUME = 1
SAMPLE_RATE = 44100
# pygameの初期化
pygame.mixer.init(frequency=SAMPLE_RATE)
is_playing = False
playback_thread = None # スレッドを格納する変数を追加
# 和文モールス信号辞書作成必要
J_MORSE_CODE_DICT = {
'ア': '--.--', 'イ': '.-', 'ウ': '..-', 'エ': '-.---', 'オ': '.-...',
'あ': '--.--', 'い': '.-', 'う': '..-', 'え': '-.---', 'お': '.-...',
'カ': '.-..', 'キ': '-.-..', 'ク': '...-', 'ケ': '-.--', 'コ': '----',
'か': '.-..', 'き': '-.-..', 'く': '...-', 'け': '-.--', 'こ': '----',
'ガ': '.-.. ..', 'ギ': '-.-.. ..', 'グ': '...- ..', 'ゲ': '-.-- ..', 'ゴ': '---- ..',
'が': '.-.. ..', 'ぎ': '-.-.. ..', 'ぐ': '...- ..', 'げ': '-.-- ..', 'ご': '---- ..',
'サ': '-.-.-', 'シ': '--.-.', 'ス': '---.-', 'セ': '.---.', 'ソ': '---.',
'ザ': '-.-.- ..', 'ジ': '--.-. ..', 'ズ': '---.- ..', 'デ': '.-.-- ..', 'ゾ': '---. ..',
'さ': '-.-.-', 'し': '--.-.', 'す': '---.-', 'せ': '.---.', 'そ': '---.',
'ざ': '-.-.- ..', 'じ': '--.-. ..', 'ず': '---.- ..', 'で': '.-.-- ..', 'ぞ': '---. ..',
'タ': '-.', 'チ': '..-.', 'ツ': '.--.', 'テ': '.-.--', 'ト': '..-..',
'ダ': '-. ..', 'ヂ': '..-. ..', 'ヅ': '.--. ..', 'デ': '.-.-- ..', 'ド': '..-.. ..',
'た': '-.', 'ち': '..-.', 'つ': '.--.', 'て': '.-.--', 'と': '..-..',
'ナ': '.-.', 'ニ': '-.-.', 'ヌ': '....','ネ': '--.-', 'ノ': '..--',
'な': '.-.', 'に': '-.-.', 'ぬ': '....','ね': '--.-', 'の': '..--',
'ハ': '-...', 'ヒ': '--..-', 'フ': '--..', 'へ': '.', 'ホ': '-..',
'バ': '-... ..', 'ビ': '--..- ..', 'ブ': '--.. ..', 'べ': '. ..', 'ボ': '-.. ..',
'パ': '-... ..--.', 'ピ': '--..- ..--.', 'プ': '--.. ..--.', 'ペ': '. ..--.', 'ポ': '-.. ..--.',
'は': '-...', 'ひ': '--..-', 'ふ': '--..', 'へ': '.', 'ほ': '-..',
'ば': '-... ..', 'び': '--..- ..', 'ぶ': '--.. ..', 'べ': '. ..', 'ぼ': '-.. ..',
'ぱ': '-... ..--.', 'ぴ': '--..- ..--.', 'ぷ': '--.. ..--.', 'ぺ': '. ..--.', 'ぽ': '-.. ..--.',
'マ': '-..-', 'ミ': '..-.-', 'ム': '-', 'メ': '-...-', 'モ': '-..-.',
'ま': '-..-', 'み': '..-.-', 'む': '-', 'め': '-...-', 'も': '-..-.',
'ヤ': '.--', 'ユ': '-..--', 'ヨ': '--',
'ャ': '.--', 'ュ': '-..--', 'ょ': '--',
'や': '.--', 'ゆ': '-..--', 'よ': '--',
'ゃ': '.--', 'ゅ': '-..--', 'ョ': '--',
'ラ': '...', 'リ': '--.', 'ル': '-.--.', 'レ': '---', 'ロ': '.-.-',
'ら': '...', 'り': '--.', 'る': '-.--.', 'れ': '---', 'ろ': '.-.-',
'ワ': '-.-', 'ヲ': '.---', 'ン': '.-.-.',
'わ': '-.-', 'を': '.---', 'ん': '.-.-.',
'0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',
'?': '..--..', '(': '.-..-.', ')': '.-..-.', 'ー': '.--.-', '-': '.--.-'}
# 和文単語リスト
J_word_list = [
"ハジメマシテ", "コンニチハ","ナマエ","シバラクデス","サヨーナラ", "ロールコール",
"アマチュア", "ハム", "タダイマカラ","ジューショ", "アシタ", "リグ", "タナカ" ,
"カナガワ", "アツギ", "イセハラ", "オーブン" ,"デンシン", "デンワ", "サンポ", "サンカ",
"ハム", "タダイマカラ","トーキヨウ", "マチダ", "サガミハラ", "599" ,"コーシン",
"アリガトウゴザイマシタ", "マタオネガイシマス", "ワブン" ,"キハラ", "ナカムラ", "デンパ",
"シンゴー","73","コンバンハ","オヤスミナサイ","ナントカ","パワー","テレビ","ヒトリ","デワマタ"
]
def generate_tone(frequency, duration):
sample_rate = 44100
t = np.linspace(0, duration, int(sample_rate * duration), False)
tone = 32767 * np.sin(2 * np.pi * frequency * t)
fade_in_out_duration = int(sample_rate * 0.01)
fade_in = np.linspace(0, 1, fade_in_out_duration)
fade_out = np.linspace(1, 0, fade_in_out_duration)
tone[:fade_in_out_duration] *= fade_in
tone[-fade_in_out_duration:] *= fade_out
sound_array = tone.astype(np.int16)
sound_array_stereo = np.column_stack((sound_array, sound_array))
return pygame.sndarray.make_sound(sound_array_stereo)
def play_dot(frequency):
dot_sound = generate_tone(frequency, DOT_DURATION)
dot_sound.play()
time.sleep(DOT_DURATION)
def play_dash(frequency):
dash_sound = generate_tone(frequency, DASH_DURATION)
dash_sound.play()
time.sleep(DASH_DURATION)
def calculate_timings(wpm):
unit_time = 1.2 / wpm
dot_duration = unit_time
dash_duration = 3 * unit_time
symbol_space_duration = unit_time
letter_space_duration = 3 * unit_time
word_space_duration = 7 * unit_time
return dot_duration, dash_duration, symbol_space_duration, letter_space_duration, word_space_duration
def play_morse_code_for_letter(letter, frequency):
morse_code = J_MORSE_CODE_DICT.get(letter.upper(), '')
for symbol in morse_code:
if not is_playing:
break
if symbol == '.':
play_dot(frequency)
elif symbol == '-':
play_dash(frequency)
time.sleep(SYMBOL_SPACE_DURATION)
time.sleep(LETTER_SPACE_DURATION)
def play_morse_code_for_word(word, frequency):
global is_playing
for letter in word:
if not is_playing:
break
play_morse_code_for_letter(letter, frequency)
time.sleep(WORD_SPACE_DURATION)
def play_morse_code(word_sample, frequency):
global is_playing
is_playing = True
for word in word_sample:
if not is_playing:
break
play_morse_code_for_word(word, frequency)
is_playing = False
window.write_event_value('-FINISHED-', None) # 発声完了時にイベント送信
def start_playback(word_sample, frequency):
time.sleep(1) # 表示の1秒後に再生を開始
play_morse_code(word_sample, frequency)
layout = [
[sg.Text('')],
[sg.Text('和文モールス信号', text_color='blue', background_color='White', font=('Arial',18))],
[sg.Radio('和文Auto', group_id=1, key='J_AUTO', text_color='blue', default=True),
sg.Radio('和文KB', group_id=1, key='J_KB', text_color='blue')],
[sg.Text('発声単語:')],
[sg.Multiline(size=(40, 10), text_color='Blue', font=('Arial', 16, 'bold'), key='INPUT')],
[sg.Text('単語数:'), sg.Slider(range=(10, 100), default_value=40, resolution=10, orientation='h', key='NBR')],
[sg.Text('速度(Word/m):'), sg.Slider(range=(4, 20), default_value=14, resolution=1, orientation='h', key='WPM')],
[sg.Text('周波数(Hz):'), sg.Slider(range=(300, 1000), default_value=700, resolution=100, orientation='h', key='FREQ')],
[sg.Text('')],
[sg.Button('Start', size=(10, 2), key='Start', disabled=False),
sg.Button('End', size=(10, 2), key='End', disabled=False), sg.Push(),
sg.Push(), sg.Text('JA1FML ver j7.0', text_color='LightBlue')]
]
win_location = (1100, 300)
win_size = (380, 600)
window = sg.Window('和文モールス受信 ver j7.0', layout, size = win_size, location = win_location, no_titlebar=True, grab_anywhere=True, finalize=True)
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED or event == 'End':
if is_playing:
sg.popup("発声中は「End」を押すことができません。")
else:
confirm_exit = sg.popup_yes_no('アプリを終了しますか?')
if confirm_exit == 'Yes':
break
elif event == 'Start':
if not is_playing: # 発声中でないことを確認
window['End'].update(disabled=True) # 発声開始時にEndボタンを無効にする
window['Start'].update(disabled=True) # Startボタンを無効にする
wpm = int(values['WPM'])
frequency = int(values['FREQ'])
DOT_DURATION, DASH_DURATION, SYMBOL_SPACE_DURATION, LETTER_SPACE_DURATION, WORD_SPACE_DURATION = calculate_timings(wpm)
if values['J_AUTO']:
nbr = int(values['NBR'])
word_sample = random.sample(J_word_list, nbr)
input_words = ' '.join(word_sample)
window['INPUT'].update(input_words) # 単語を入力欄に表示
playback_thread = threading.Thread(target=start_playback, args=(word_sample, frequency), daemon=True)
playback_thread.start()
elif values['J_KB']:
input_text = window['INPUT'].get().strip()
if input_text:
word_sample = input_text.split()
playback_thread = threading.Thread(target=start_playback, args=(word_sample, frequency), daemon=True)
playback_thread.start()
else:
sg.popup('発声単語を入力してください。')
elif event == '-FINISHED-': # 発声が完了したときの処理
window['End'].update(disabled=False)
window['Start'].update(disabled=False)
window.close()