Difficulty with running independent loops simultaneously with sound and visual stimuli

Hello!

Here’s what I’m trying to do. I am presenting two simultaneous tasks in psychopy. One of the tasks is an audio task (known as Oddball for psychology folks) that presents beeps and boops, and for the moment on a regular cadence (every 3s for 200ms), and the other is a visual task that presents a visual timer the participant responds to with a key press and the ISI for this visual task is variable, on top of the trial length being variable because it depends on the response time of the participant.

I tried to follow the solution in this post by djmannion on June 29th. I couldn’t quite get it to work as is, so what I did was create a function that checked the sound and played it if it needed to be played, and then inserted this function in every component/phase of my trial. Here’s the relevant part of the code where I initialized the sound and then the function to check the sound and play it if it’s the appropriate time to play it:

# --- Initialize components for Routine "trial" ---
sound_1 = sound.Sound('A', secs=-1, stereo=True, hamming=True,
                      name='sound_1')
sound_1.setVolume(1.0)

# update component parameters for each repeat
sound_1.setSound('A', secs=50, hamming=True)
sound_1.setVolume(1.0, log=False)

# Initialize sound parameters
# tone_playing = False
tone_duration = 0.2
tone_iti = 3.0

# Clear any existing events
event.clearEvents()

# Set the interstimulus interval range for the visual stimuli
isi_range = [2, 4]

# Set the duration of the feedback display for the visual stimuli
feedback_duration = 1.0

# Initialize the trial counter and RT list
trial_num = 1
rts = []
isi_clock = core.Clock()
response = None

# Initialize the clock
experimentClock = core.Clock()
trial_clock = core.Clock()


def check_sound():
    # start playing if it is within the initial period, and isn't already playing
    math = np.mod(experimentClock.getTime(), tone_iti)
    if math < tone_duration:
        if sound_1.status == NOT_STARTED:
            now = core.getTime()
            sound_1.play(when=now)
        else:
            now = core.getTime()
            sound_1.play(when=now)
    else:
        sound_1.stop()

while experimentClock.getTime() < 600:  # 10 minutes
    check_sound()
    # Wait for the interstimulus interval to elapse
    isi_duration = np.random.uniform(isi_range[0], isi_range[1])
    isi_clock.reset()
    while isi_clock.getTime() < isi_duration:
        check_sound()
        win.flip()

    # Start the clock for this trial
    trial_clock.reset()
    timer.setText("0")

    # Display the timer and wait for a response
    while not response:
        timer.setText("{:.0f}".format(trial_clock.getTime() * 1000))
        timer.draw()
        win.flip()
        check_sound()
        keys = event.getKeys()
        if 'escape' in keys:
            response = 'escape'
        elif 'space' in keys:
            response = trial_clock.getTime()

    # Check if the response was the 'escape' key
    if response == 'escape':
        break

    # Show the response time for 1 second
    feedback_clock = core.Clock()
    feedback_text = visual.TextStim(win, text="{:.0f}".format(response * 1000), pos=(0, 0), color="white", height=0.2)
    while feedback_clock.getTime() < 1.0:
        check_sound()
        feedback_text.draw()
        win.flip()

    # Clear the screen before the next trial
    win.flip(clearBuffer=True)

    # Get the RT and add it to the list
    rt = response * 1000
    rts.append(rt)

When I run it this way, the beeps do seem to be happening on a regular basis, but the sound is very weird/glitchy. And the following error gets thrown to me:

‘PsychPortAudio-WARNING: ‘Start’ method on audiodevice 1 called, although playback on device not yet completely stopped. Will forcefully restart with possible audible artifacts or timing glitches.’

I’m very concerned about timing glitches because the timing of this experiment needs to be very precise.
I have played around with modifying the check_sound function so that the sound didn’t keep trying to initiate if it was already playing, and that did make the warnings go away and the beep to sound great. But then the beep only played once and never played again, so now I can’t figure out what’s wrong. Here is how I modified the code:

def check_sound():
    # start playing if it is within the initial period, and isn't already playing
    math = np.mod(experimentClock.getTime(), tone_iti)
    if math < tone_duration:
        if sound_1.status == NOT_STARTED:
            now = core.getTime()
            sound_1.play(when=now)
            print('tone starting',now)
            sound_1.status == STARTED
#        else:
#            now = core.getTime()
#            sound_1.play(when=now)
    else:
        sound_1.stop()

I ALSO commented out the part of the code where the sound is being initialized to 50ms, it seemed like it made more sense to leave it initialized to -1, since my understanding is that that means the sound will keep playing until you tell it to no longer play.

#sound_1.setSound('A', secs=50, hamming=True)

If anyone has any ideas on how to troubleshoot this I would be very grateful!!