PsychoPy воспроизводит звуки с нерегулярной задержкой в ​​эксперименте на ЭЭГ - PullRequest
0 голосов
/ 08 июня 2018

Я использую PsychoPy, чтобы подготовить странную парадигму, в которой я предварительно устанавливаю изображение на экране на 7 секунд, а во время представления изображения 14 последовательных звуков отображаются каждые полсекунды.Для каждого звука я посылаю триггер на параллельный порт.Затем я запустил временные тесты, чтобы увидеть, воспроизводятся ли звуки одновременно с триггерами.

В то время как триггеры кажутся в порядке и приходят каждые полсекунды, это не относится к звукам.Звуки воспроизводятся с задержкой от 100 мс до 200 мс после срабатывания триггера, и разница между включениями последовательных звуков не составляет полсекунды.Размер звукового файла не имеет значения, и задержки, похоже, имеют место как для очень коротких звуков (10 мс), так и для более длинных (250 мс).Я пытался добавить ISI в самом начале каждого испытания и загружать как картинку, так и звуки в течение этого периода, но это не помогло.

Я также пытался добавить ISI перед каждым звуком и загружать звуки во время этих коротких ISI, но это тоже не помогло.Ты хоть представляешь, как можно решить проблему?Может ли ISI помочь?Должен ли я иметь один ISI в начале испытания, чтобы загрузить все стимулы для этого испытания или несколько ISI на испытание, по одному на стимул?

Задержка визуального стимула (то есть изображения) малаи постоянная в испытаниях.

Приведенный ниже код воспроизводит только два звука, но хорошо демонстрирует проблему.

from __future__ import absolute_import, division
from psychopy import locale_setup, sound, gui, visual, core, data, event, logging, parallel
from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED,
                                STOPPED, FINISHED, PRESSED, RELEASED, FOREVER)

# Setup the Window
win = visual.Window(
    size=(1920, 1080), fullscr=True, screen=0,
    allowGUI=True, allowStencil=False,
    monitor='testMonitor', color=[-1, -1, -1], colorSpace='rgb',
    blendMode='avg', useFBO=True)
snd_2_tr = 'sound1.wav'
snd_3_tr = 'sound2.wav'
picture_tr = 'pic.jpg'
win.setRecordFrameIntervals(True)
win._refreshThreshold = 1 / 60.0 + 0.004
image_tr = visual.ImageStim(
    win=win, name='image_tr',
    image='sin', mask=None,
    ori=0, pos=(0, 0), size=None,
    color=[1,1,1], colorSpace='rgb', opacity=1,
    flipHoriz=False, flipVert=False,
    texRes=128, interpolate=True, depth=0.0)
sound_2_tr = sound.Sound('A', secs=-1)
sound_2_tr.setVolume(1)
sound_3_tr = sound.Sound('A', secs=-1)
sound_3_tr.setVolume(1)
image_port_tr = parallel.ParallelPort(address='0xD010')
sound_2_port_tr = parallel.ParallelPort(address='0xD010')
sound_3_port_tr = parallel.ParallelPort(address='0xD010')
ISI_17 = core.StaticPeriod(win=win, screenHz=60, name='ISI_17')

# ------Prepare to start Routine "main_tr"-------
main_trClock = core.Clock()
t = 0
main_trClock.reset()  # clock
frameN = -1
continueRoutine = True
# keep track of which components have finished
main_trComponents = [image_tr, sound_2_tr, sound_3_tr, image_port_tr, sound_2_port_tr, sound_3_port_tr, ISI_17]
for thisComponent in main_trComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

# -------Start Routine "main_tr"-------
while continueRoutine:
    # get current time
    t = main_trClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame

    # *image_tr* updates
    if frameN >= 60 and image_tr.status == NOT_STARTED:
        # keep track of start time/frame for later
        image_tr.tStart = t
        image_tr.frameNStart = frameN  # exact frame index
        image_tr.setAutoDraw(True)
    if image_tr.status == STARTED and frameN >= (image_tr.frameNStart + 420):
        image_tr.setAutoDraw(False)

    # start/stop sound_2_tr
    if frameN >= 90 and sound_2_tr.status == NOT_STARTED:
        # keep track of start time/frame for later
        sound_2_tr.tStart = t
        sound_2_tr.frameNStart = frameN  # exact frame index
        sound_2_tr.play()  # start the sound (it finishes automatically)
    if sound_2_tr.status == STARTED and t >= (sound_2_tr.tStart + 0.25):
        sound_2_tr.stop()  # stop the sound (if longer than duration)
    # start/stop sound_3_tr
    if frameN >= 120 and sound_3_tr.status == NOT_STARTED:
        # keep track of start time/frame for later
        sound_3_tr.tStart = t
        sound_3_tr.frameNStart = frameN  # exact frame index
        sound_3_tr.play()  # start the sound (it finishes automatically)
    if sound_3_tr.status == STARTED and t >= (sound_3_tr.tStart + 0.25):
        sound_3_tr.stop()  # stop the sound (if longer than duration)
    # *sound_1_port_tr* updates
    if frameN >= 60 and image_port_tr.status == NOT_STARTED:
        # keep track of start time/frame for later
        image_port_tr.tStart = t
        image_port_tr.frameNStart = frameN  # exact frame index
        image_port_tr.status = STARTED
        win.callOnFlip(image_port_tr.setData, int(triggers_image_tr))
    if image_port_tr.status == STARTED and frameN >= (image_port_tr.frameNStart + 15):
        image_port_tr.status = STOPPED
        win.callOnFlip(image_port_tr.setData, int(0))
    # *sound_2_port_tr* updates
    if frameN >= 90 and sound_2_port_tr.status == NOT_STARTED:
        # keep track of start time/frame for later
        sound_2_port_tr.tStart = t
        sound_2_port_tr.frameNStart = frameN  # exact frame index
        sound_2_port_tr.status = STARTED
        win.callOnFlip(sound_2_port_tr.setData, int(triggers_sound_2_tr))
    if sound_2_port_tr.status == STARTED and frameN >= (sound_2_port_tr.frameNStart + 15):
        sound_2_port_tr.status = STOPPED
        win.callOnFlip(sound_2_port_tr.setData, int(0))
    # *sound_3_port_tr* updates
    if frameN >= 120 and sound_3_port_tr.status == NOT_STARTED:
        # keep track of start time/frame for later
        sound_3_port_tr.tStart = t
        sound_3_port_tr.frameNStart = frameN  # exact frame index
        sound_3_port_tr.status = STARTED
        win.callOnFlip(sound_3_port_tr.setData, int(triggers_sound_3_tr))
    if sound_3_port_tr.status == STARTED and frameN >= (sound_3_port_tr.frameNStart + 15):
        sound_3_port_tr.status = STOPPED
        win.callOnFlip(sound_3_port_tr.setData, int(0))
    # *ISI_17* period
    if frameN >= 0 and ISI_17.status == NOT_STARTED:
        # keep track of start time/frame for later
        ISI_17.tStart = t
        ISI_17.frameNStart = frameN  # exact frame index
        ISI_17.start(60 * frameDur)
    elif ISI_17.status == STARTED:  # one frame should pass before updating params and completing
        # updating other components during *ISI_17*
        image_tr.setImage(picture_tr)
        sound_2_tr.setSound(snd_2_tr, secs=0.25)
        sound_3_tr.setSound(snd_3_tr, secs=0.25)
        # component updates done
        ISI_17.complete()  # finish the static period

    # check if all components have finished
    if not continueRoutine:  # a component has requested a forced-end of Routine
        break
    continueRoutine = False  # will revert to True if at least one component still running
    for thisComponent in main_trComponents:
        if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
            continueRoutine = True
            break  # at least one component has not yet finished

    # check for quit (the Esc key)
    if endExpNow or event.getKeys(keyList=["escape"]):
        core.quit()

    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()
...