129 lines
3.7 KiB
Python
129 lines
3.7 KiB
Python
|
import os
|
||
|
import threading
|
||
|
import time
|
||
|
import sounddevice as sd
|
||
|
import numpy as np
|
||
|
|
||
|
|
||
|
def beep(duration=700, freq=640):
|
||
|
# 生成蜂鸣声的时间序列
|
||
|
t = np.linspace(0, duration / 1000, int(44100 * duration / 1000), False)
|
||
|
signal = 0.5 * np.sin(2 * np.pi * freq * t)
|
||
|
# 播放蜂鸣声
|
||
|
sd.play(signal, samplerate=44100)
|
||
|
sd.wait()
|
||
|
|
||
|
|
||
|
class SpeakServer:
|
||
|
thread = None # background thread that reads frames from camera
|
||
|
engine = None
|
||
|
__flag = threading.Event() # 用于暂停线程的标识
|
||
|
__flag.clear() # 设置为True
|
||
|
__running = threading.Event() # 用于停止线程的标识
|
||
|
__running.set() # 将running设置为True
|
||
|
__had_data = threading.Event()
|
||
|
__had_data.clear()
|
||
|
speak_list = []
|
||
|
is_pause = True
|
||
|
BASE_SPEED = 50
|
||
|
MAX_SPEED = 100
|
||
|
speed = BASE_SPEED
|
||
|
speed_set = BASE_SPEED
|
||
|
speed_now = BASE_SPEED
|
||
|
volume = 100
|
||
|
pitch = 10
|
||
|
|
||
|
def __new__(cls):
|
||
|
if not cls.thread:
|
||
|
# start background frame thread
|
||
|
cls.thread = threading.Thread(target=cls._thread, daemon=True)
|
||
|
cls.thread.start()
|
||
|
return super().__new__(cls)
|
||
|
|
||
|
def start(self):
|
||
|
pass
|
||
|
|
||
|
@staticmethod
|
||
|
def add_speak(data):
|
||
|
SpeakServer.speak_list.append(data)
|
||
|
SpeakServer.__had_data.set()
|
||
|
|
||
|
@classmethod
|
||
|
def check_list(cls):
|
||
|
if not cls.speak_list:
|
||
|
return True
|
||
|
else:
|
||
|
return False
|
||
|
|
||
|
@classmethod
|
||
|
def wait_4_speak(cls):
|
||
|
while not cls.check_list():
|
||
|
time.sleep(0.1)
|
||
|
|
||
|
@staticmethod
|
||
|
def speed_control(rate):
|
||
|
SpeakServer.speed = rate
|
||
|
|
||
|
@staticmethod
|
||
|
def set_temp_speed(rate):
|
||
|
try:
|
||
|
SpeakServer.speed = rate
|
||
|
SpeakServer.speed_now = rate
|
||
|
except:
|
||
|
return
|
||
|
|
||
|
@staticmethod
|
||
|
def volume_control(volume):
|
||
|
SpeakServer.volume = volume
|
||
|
|
||
|
@classmethod
|
||
|
def _thread(cls):
|
||
|
while SpeakServer.__running.is_set():
|
||
|
SpeakServer.__had_data.wait()
|
||
|
while cls.speak_list:
|
||
|
try:
|
||
|
temp_speak = cls.speak_list[0]
|
||
|
# 语速控制
|
||
|
if len(cls.speak_list) >= 2:
|
||
|
speak_len = len("".join([str(s) for s in cls.speak_list]))
|
||
|
if speak_len > 10:
|
||
|
speak_speed = cls.BASE_SPEED + min(speak_len, 30) / 30 * (cls.MAX_SPEED - cls.BASE_SPEED)
|
||
|
cls.set_temp_speed(speak_speed)
|
||
|
else:
|
||
|
if cls.speed_now != cls.speed_set:
|
||
|
cls.speed_control(cls.speed_set)
|
||
|
else:
|
||
|
cls.speed_control(cls.speed_set)
|
||
|
os.popen(f"ekho "
|
||
|
f"-v Mandarin "
|
||
|
f"-p {SpeakServer.pitch} "
|
||
|
f"-a {SpeakServer.volume} "
|
||
|
f"-s {SpeakServer.speed} "
|
||
|
f"{temp_speak}").read()
|
||
|
cls.speak_list.pop(0)
|
||
|
except Exception as e:
|
||
|
print('speak machine error:', e)
|
||
|
time.sleep(0.1)
|
||
|
SpeakServer.__had_data.clear()
|
||
|
SpeakServer.thread = None
|
||
|
|
||
|
@classmethod
|
||
|
def wait(cls):
|
||
|
cls.__flag.wait()
|
||
|
|
||
|
@classmethod
|
||
|
def pause(cls):
|
||
|
if not cls.is_pause:
|
||
|
cls.__flag.clear() # 设置为False, 让线程阻塞
|
||
|
cls.is_pause = True
|
||
|
|
||
|
@classmethod
|
||
|
def resume(cls):
|
||
|
if cls.is_pause:
|
||
|
cls.__flag.set() # 设置为True, 让线程停止阻塞
|
||
|
cls.is_pause = False
|
||
|
|
||
|
@classmethod
|
||
|
def stop(cls):
|
||
|
return
|