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

Psychopy中从CSV文件播放的声音叠加问题(以帧为计时单位)

解决PsychoPy中CSV播放声音叠加的问题

嘿,我之前做类似听觉实验时也踩过声音叠加的坑,结合你的实验场景(300ms/18帧的声音时序)和给出的代码片段,给你几个实用的解决方案:

1. 跟踪并控制当前播放的声音实例

最常见的问题就是前一个声音还没播放完毕,下一个就启动了。我们可以用一个变量跟踪当前正在播放的声音,每次播放新声音前做检查处理:

from psychopy import sound  # 别忘了导入sound模块

# 初始化变量跟踪当前声音
current_sound = None
win = visual.Window()  # 假设你已创建实验窗口

# 读取CSV刺激列表(替换成你的读取逻辑)
stimuli = []
with open('your_stimuli.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        stimuli.append(row)

frame_count = 0
for stim in stimuli:
    # 处理前一个声音:如果还在播放,停止它(或等待结束,依实验需求选择)
    if current_sound is not None and current_sound.isPlaying:
        current_sound.stop()
        # 若需要等前一个声音自然结束,替换为 current_sound.wait()
    
    # 加载并播放当前声音
    current_sound = sound.Sound(stim['sound_path'])  # 替换为你CSV中的声音文件列名
    current_sound.play()
    
    # 严格按帧计时,等待18帧
    for _ in range(18):
        win.flip()
        frame_count += 1

2. 用帧计数器精准控制播放间隔

如果实验依赖严格的帧同步,最好用窗口flip()来计数,避免time.sleep()这类受系统延迟影响的方法:

from psychopy import sound, visual, csv

win = visual.Window()
current_sound = None
frame_count = 0
last_play_frame = -100  # 初始值确保第一次能正常播放

# 读取CSV刺激列表
stimuli = []
with open('your_stimuli.csv', 'r') as f:
    stimuli = list(csv.DictReader(f))

while frame_count < len(stimuli)*18:
    win.flip()
    frame_count += 1
    
    # 每18帧触发一次声音播放
    if (frame_count - last_play_frame) == 18:
        # 停止前一个声音
        if current_sound is not None and current_sound.isPlaying:
            current_sound.stop()
        
        # 获取当前要播放的刺激
        stim_idx = (frame_count // 18) - 1
        if stim_idx < len(stimuli):
            current_sound = sound.Sound(stimuli[stim_idx]['sound_path'])
            current_sound.play()
            last_play_frame = frame_count

3. 利用PsychoPy内置TrialHandler管理时序

PsychoPy的TrialHandler已经封装了刺激时序和资源管理,用它能减少手动控制的出错概率:

from psychopy import sound, visual, data

win = visual.Window()
current_sound = None

# 直接从CSV导入刺激列表创建TrialHandler
trials = data.TrialHandler(
    trialList=data.importConditions('your_stimuli.csv'),
    nReps=1,
    method='sequential'  # 按CSV顺序播放
)

for trial in trials:
    # 等待前一个声音结束(确保不叠加)
    if current_sound is not None:
        current_sound.wait()
    
    # 播放当前声音
    current_sound = sound.Sound(trial['sound_path'])
    current_sound.play()
    
    # 等待18帧
    for _ in range(18):
        win.flip()
    
    # 可选:记录播放相关数据
    trials.addData('play_end_frame', win.getFutureFlipTime(clock='frame'))

额外注意点

  • 验证声音文件时长:用Audacity等工具确认你的声音文件实际是300ms,文件时长不符会直接打乱时序
  • 调整音频缓冲:如果用pyo库,偶尔会因缓冲导致延迟,可尝试调整Sound的bufferSize参数,比如sound.Sound(..., bufferSize=512)
  • 开启帧日志排查:用logging.console.setLevel(logging.DEBUG)可以查看每帧时间,帮助定位时序问题

内容的提问来源于stack exchange,提问作者looking for answers

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:30:55