Preloading images on Builder?

OK, so it seems that this is an RSVP paradigm so the images flow on consecutively from each other. That means we can’t use the trick of pre-loading during a fixation point, as that would only work for the first image in the queue. In this case, I’d suggest that you insert a second image stimulus, say RSVPStream_2 into this routine. What we’ll do is alternate which one gets displayed on each iteration of the loop. While one is being displayed, the other gets updated. Because reading in the file for the next trial might take more than one screen refresh period, you should specify the duration here in time (i.e. seconds) rather than frames. That way, the overall duration should be constant for each stimulus, even if a frame gets dropped due to importing the next image.

  • So for each of the two stimuli, specify a fixed image file to use, and set the image field to be “constant” rather than to update on every repeat (because you will need to handle the updating yourself in code, and you don’t want any conflicts).
  • The tricky thing with doing RSVP in Builder is that you don’t know what the first image will be until the loop starts, so that makes it difficult to pre-load the very first image. So you need to do something tricky: shift the routine containing the fixation target inside imageLoop so that we can set the very first image before the images actually start being shown, so it is ready in time. But we don’t want that fixation target to be shown again inside that loop, so insert a code component on that routine and put this in its “Begin routine” tab so that this routine will only appear once:
# run this routine only before the very first image:
if not imageLoop.thisN == 0:
    continueRoutine = False
else:
    # set the first image:
    RSVPStream.image = your_image_name_variable

So that should mean the first image is cued up, before it is scheduled to be shown.

Now you need to insert a code component in the images routine, so that we can get the alternating images specified. Make sure the code component goes above the image components.

Put this in the “begin routine” tab:

next_image_loaded = False

# do different things on even and odd numbered trials:
    if imageLoop.thisN % 2 == 0:
        RSVPStream.opacity = 1    # show this one
        RSVPStream_2.opacity = 0  # hide this one
    else:
        RSVPStream.opacity = 0 
        RSVPStream_2.opacity = 1

Put this in the “every frame” tab, so this code will only run after the first frame has been shown (so that there is no delay in having the images switch over):

# only do this once, after the images switch, and not on the last trial:
if not next_image_loaded and frameN > 1 and imageLoop.thisN < 8:

    # find out the next image:
    next_trial = imageLoop.getFutureTrial()
    upcoming_image = next_trial['your_image_name_variable']

    # do different things on even and odd numbered trials:
    if imageLoop.thisN % 2 == 0:
        RSVPStream_2.image = upcoming_image
    else:
        RSVPStream.image = upcoming_image
    next_image_loaded = True

% is the modulo operator. It returns the remainder of dividing two numbers. So when dividing some number modulo 2, the remainder is 0 for even numbers, and 1 for odd numbers. This is very useful for code that needs to alternate across trials.

None of this is tested, so come back to us when you find the inevitable bug.

1 Like