OS (Win10):
PsychoPy version (2026.2.4 Py 3.10.11):
Standard Standalone Installation? Yes
Do you want it to also run online? No
What are you trying to achieve?:
Hi! I am trying to create an experiment with auditory stimuli in Builder.
Each experimental trial is made up of 3 routines , as follows:
- audio_1_routine → fixation cross appears at 0 s and stays visible throughout routine (stop duration is left blank). Audio file starts playing at 1 s (stop duration is left blank). The end of the audio file should end the routine (handled by code component)
- audio_2_routine → at 0.5 s, both a text resource and a audio file are presented at the same time (stop duration is left blank). The end of the audio file should end the routine (handled by code component)
- question_routine → a text component with a question appears and a keyboard response is needed to end the routine.
*The issue*: The problem I am having is that the end of the first audio file (i.e. audio file that plays in the routine “audio_1_routine”) will not end the routine. The audio plays correctly but then nothing happens when it is done playing, and the fixation cross stays visible on the screen past that point, without ever progressing to the next routine (“audio_2_routine”)…
What did you try to make it work?:
I am using the code solution I found in other posts to force the end of the audio to end the routine:
if sound.status == FINISHED:# "sound" replaced by name of my relevant component
continueRoutine = False
Previously, I had also tried ticking the “Force end of Routine” box option instead to end the routine (found in the sound resource’s Properties window, in the Playback tab). But that did not work either…
Any suggestions or tips I could try would be very helpful as I am stuck - many thanks in advance!
*Edit*: I also tried fixing the duration of the non-audio components within each routine (e.g. fixation cross as text resource in “audio_1_routine”) to ensure that the issue is not because these non-audio components can run indefinitely. Even after limiting the duration of the non-audio components so that they end before the audio even starts playing, I still have the issue that I can’t progress to the next routine once the audio file stops…
PS: relevant code from exp_lastrun.py
`# — Prepare to start Routine “audio_1_routine” —
create an object to store info about Routine audio_1_routine
audio_1_routine = data.Routine(
name=‘audio_1_routine’,
components=[fixation, sound_resource_1],
)
audio_1_routine.status = NOT_STARTED
continueRoutine = True
update component parameters for each repeat
fixation.setText(‘+’)
sound_resource_1.setSound(audio_1, hamming=True)
sound_resource_1.setVolume(1.0, log=False)
sound_resource_1.seek(0)
store start times for audio_1_routine
audio_1_routine.tStartRefresh = win.getFutureFlipTime(clock=globalClock)
audio_1_routine.tStart = globalClock.getTime(format=‘float’)
audio_1_routine.status = STARTED
thisExp.addData(‘audio_1_routine.started’, audio_1_routine.tStart)
audio_1_routine.maxDuration = None
keep track of which components have finished
audio_1_routineComponents = audio_1_routine.components
for thisComponent in audio_1_routine.components:
thisComponent.tStart = None
thisComponent.tStop = None
thisComponent.tStartRefresh = None
thisComponent.tStopRefresh = None
if hasattr(thisComponent, ‘status’):
thisComponent.status = NOT_STARTED
reset timers
t = 0
_timeToFirstFrame = win.getFutureFlipTime(clock=“now”)
frameN = -1
# --- Run Routine "audio_1_routine" ---
thisExp.currentRoutine = audio_1_routine
audio_1_routine.forceEnded = routineForceEnded = not continueRoutine
while continueRoutine:
# if trial has changed, end Routine now
if hasattr(thisTrial, 'status') and thisTrial.status == STOPPING:
continueRoutine = False
# get current time
t = routineTimer.getTime()
tThisFlip = win.getFutureFlipTime(clock=routineTimer)
tThisFlipGlobal = win.getFutureFlipTime(clock=None)
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame
# *fixation* updates
# if fixation is starting this frame...
if fixation.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
# keep track of start time/frame for later
fixation.frameNStart = frameN # exact frame index
fixation.tStart = t # local t and not account for scr refresh
fixation.tStartRefresh = tThisFlipGlobal # on global time
win.timeOnFlip(fixation, 'tStartRefresh') # time at next scr refresh
# add timestamp to datafile
thisExp.timestampOnFlip(win, 'fixation.started')
# update status
fixation.status = STARTED
fixation.setAutoDraw(True)
# if fixation is active this frame...
if fixation.status == STARTED:
# update params
pass
# *sound_resource_1* updates
# if sound_resource_1 is starting this frame...
if sound_resource_1.status == NOT_STARTED and tThisFlip >= 1-frameTolerance:
# keep track of start time/frame for later
sound_resource_1.frameNStart = frameN # exact frame index
sound_resource_1.tStart = t # local t and not account for scr refresh
sound_resource_1.tStartRefresh = tThisFlipGlobal # on global time
# add timestamp to datafile
thisExp.addData('sound_resource_1.started', tThisFlipGlobal)
# update status
sound_resource_1.status = STARTED
sound_resource_1.play(when=win) # sync with win flip
# if sound_resource_1 is stopping this frame...
if sound_resource_1.status == STARTED:
if bool(False) or sound_resource_1.isFinished:
# keep track of stop time/frame for later
sound_resource_1.tStop = t # not accounting for scr refresh
sound_resource_1.tStopRefresh = tThisFlipGlobal # on global time
sound_resource_1.frameNStop = frameN # exact frame index
# add timestamp to datafile
thisExp.timestampOnFlip(win, 'sound_resource_1.stopped')
# update status
sound_resource_1.status = FINISHED
sound_resource_1.stop()
# Run 'Each Frame' code from stop_sound_resource_1
if sound_resource_1.status == FINISHED:
continueRoutine = False
# check for quit (typically the Esc key)
if defaultKeyboard.getKeys(keyList=["escape"]):
thisExp.status = FINISHED
if thisExp.status == FINISHED or endExpNow:
endExperiment(thisExp, win=win)
return
# pause experiment here if requested
if thisExp.status == PAUSED:
pauseExperiment(
thisExp=thisExp,
win=win,
timers=[routineTimer, globalClock],
currentRoutine=audio_1_routine,
)
# skip the frame we paused on
continue
# has a Component requested the Routine to end?
if not continueRoutine:
audio_1_routine.forceEnded = routineForceEnded = True
# has the Routine been forcibly ended?
if audio_1_routine.forceEnded or routineForceEnded:
break
# has every Component finished?
continueRoutine = False
for thisComponent in audio_1_routine.components:
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
continueRoutine = True
break # at least one component has not yet finished
# refresh the screen
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
win.flip()
# --- Ending Routine "audio_1_routine" ---
for thisComponent in audio_1_routine.components:
if hasattr(thisComponent, "setAutoDraw"):
thisComponent.setAutoDraw(False)
# store stop times for audio_1_routine
audio_1_routine.tStop = globalClock.getTime(format='float')
audio_1_routine.tStopRefresh = tThisFlipGlobal
thisExp.addData('audio_1_routine.stopped', audio_1_routine.tStop)
sound_resource_1.pause() # ensure sound has stopped at end of Routine
# the Routine "audio_1_routine" was not non-slip safe, so reset the non-slip timer
routineTimer.reset()`

