You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python音频刺激呈现脚本出现不可预期异常的原因排查求助

问题诊断与修复方案

首先,你的随机无限循环/声音持续播放问题,核心原因在于手动用while循环轮询时间来控制音频播放的方式不可靠,再加上反复调用p.Play()可能导致audiomath.Player的内部状态混乱。下面分点说明问题和修复方法:

1. 核心问题分析

  • 你在short_blink和long_blink里用while time.time() < init + duration来维持播放,但Python的线程调度、系统时间精度限制,或者audiomath.Player的Play()方法重复调用(每次循环都调用一次),可能导致循环无法及时退出,甚至让Player进入异常状态,持续播放无法停止。
  • time.time()的精度虽然足够,但轮询式的控制不是音频播放的正确姿势——audiomath本身提供了更可靠的播放时长控制能力。

2. 具体修复代码

修复exp_funcs.py中的播放函数

替换原来的short_blink和long_blink函数,利用audiomath.Player的内置功能来控制播放时长,同时更准确地记录时间:

def short_blink(sound, duration):
    p = am.Player(sound)
    init = time.perf_counter()  # 用高精度计时器替代time.time()
    # 用Play的duration参数直接控制播放时长,不需要手动循环
    p.Play(duration=duration)
    # 等待播放结束(确保Player完成播放)
    p.WaitUntilDone()
    end = time.perf_counter()
    actual_duration = end - init
    print(f'start {init} end {end} duration {actual_duration:.3f}')
    return (init, end, actual_duration)

def long_blink(sound, duration, cue_duration, spacing):
    p = am.Player(sound)
    # 播放第一个低音(cue)
    cue_start = time.perf_counter()
    p.Play(duration=cue_duration)
    p.WaitUntilDone()
    
    # 等待间隔时间
    time.sleep(spacing)
    
    # 播放第二个可变时长的低音
    init = time.perf_counter()
    p.Play(duration=duration)
    p.WaitUntilDone()
    end = time.perf_counter()
    actual_duration = end - init
    print(f'start {init} end {end} duration {actual_duration:.3f}')
    return (init, end, actual_duration)

额外优化点

  • 动态导入source文件:你当前用source = __import__('source'),如果修改了source.py后重新运行实验,Python可能会使用缓存的模块,不会加载最新内容。可以改成动态导入并强制刷新:
# 在experiment.py的main函数里替换原来的source导入部分
import importlib
source = importlib.import_module(source_file)
importlib.reload(source)  # 强制重新加载,确保使用最新的参数
  • 超时防护:极端情况下如果播放器卡住,可以给WaitUntilDone()加超时参数,避免无限等待:
# 比如在short_blink里:
p.WaitUntilDone(timeout=duration + 0.1)  # 超时时间比播放时长多100ms,符合你的误差容忍度

3. 为什么这样能解决问题

  • audiomath.Player.Play(duration=...)会内部管理播放的起止,比手动轮询更可靠,不会出现循环卡住的情况。
  • WaitUntilDone()确保播放器完成播放后再继续执行后续代码,避免时间记录和播放状态不同步。
  • 避免了反复调用p.Play()导致的Player状态异常——原来的循环里每次都调用p.Play(),可能让Player不断重启播放,最终进入无法停止的状态。
  • time.perf_counter()提供了更高精度的计时,更适合测量短时间间隔,符合你的实验需求。

4. 测试建议

  1. 先单独运行exp_funcs.py中的short_blink和long_blink函数,测试单个试次的播放是否正常,时间记录是否准确。
  2. 再运行完整实验脚本,观察是否还会出现无限循环的情况。
  3. 如果还有零星异常,可以在主循环里加试次级别的异常捕获,避免单个试次崩溃导致整个实验终止:
# 在experiment.py的循环里:
for ttype, sound, duration, cue_duration, spacing, iti in shuffle_param:
    try:
        time.sleep(iti)
        df = run_trial(ttype, sound, duration, cue_duration, spacing)
        dfs.append(df)
    except Exception as e:
        print(f"Trial failed: {e}")
        # 可以在这里添加异常日志,或者跳过该试次

内容的提问来源于stack exchange,提问作者fednem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 02:22:35