麦克风静音监测应用问题:检测到声音时无法重置计时器
问题分析与代码修复
原代码存在的问题
- 冗余的声音检测逻辑:两个独立的声音判断条件导致部分场景下(如声音强度在100-150之间),仅重置计时器但未更新最后发声时间,后续仍会错误递增计时。
- 计时逻辑不精准:依赖
time.sleep(1)固定递增1秒,循环执行时间偏差会导致计时不准。 - Tkinter线程安全风险:后台线程直接修改UI变量,可能引发未知异常。
- 未满足需求:警告触发时间设置为25秒,与要求的30秒不符。
修复方案
- 统一声音检测阈值,移除冗余判断,确保检测到声音时同步更新最后发声时间与计时器。
- 通过计算最后发声时间与当前时间的差值更新计时器,提升计时准确性。
- 使用
root.after()将所有UI操作切换到主线程执行,规避线程安全问题。 - 调整警告触发时间为30秒,更新弹窗提示文本。
修正后的完整代码
import pyaudio import numpy as np import time import threading import tkinter as tk def ses_alma(root, sessizlik_suresi): CHUNK = 1024 FORMAT = pyaudio.paInt16 CHANNELS = 1 RATE = 44100 SOUND_THRESHOLD = 100 # 统一声音检测阈值 p = pyaudio.PyAudio() stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK) print("开始监听声音...") last_sound_time = time.time() try: while True: data = stream.read(CHUNK) audio_data = np.frombuffer(data, dtype=np.int16) audio_max = np.max(np.abs(audio_data)) if audio_max >= SOUND_THRESHOLD: # 检测到声音,重置计时 last_sound_time = time.time() root.after(0, lambda: sessizlik_suresi.set(0)) else: # 计算静音时长并更新计时器 elapsed = int(time.time() - last_sound_time) root.after(0, lambda: sessizlik_suresi.set(elapsed)) # 短暂睡眠降低CPU占用 time.sleep(0.1) finally: # 确保资源正确释放 stream.stop_stream() stream.close() p.terminate() def uyarı_ver(root, sessizlik_suresi): while True: current_time = sessizlik_suresi.get() if current_time >= 30: # 调整为30秒触发警告 root.after(0, show_popup) root.after(0, lambda: sessizlik_suresi.set(0)) time.sleep(1) def show_popup(): popup = tk.Toplevel() popup.geometry("200x100") popup.title("警告") message = tk.Label(popup, text="静音超过30秒!") message.pack() popup.after(5000, popup.destroy) # 5秒后关闭警告窗口 if __name__ == "__main__": root = tk.Tk() root.geometry("300x100") root.title("静音警告") root.configure(bg="black") sessizlik_suresi = tk.IntVar() sessizlik_suresi.set(0) time_label = tk.Label(root, textvariable=sessizlik_suresi, font=("Arial Bold", 36), bg="black", fg="white") time_label.pack() # 传递root和变量到线程函数 ses_alma_thread = threading.Thread(target=ses_alma, args=(root, sessizlik_suresi), daemon=True) uyarı_thread = threading.Thread(target=uyarı_ver, args=(root, sessizlik_suresi), daemon=True) ses_alma_thread.start() uyarı_thread.start() root.mainloop()
内容的提问来源于stack exchange,提问作者Mugi
相关产品推荐
相关产品推荐

