Confusion on how to specfiy a stimulus length using frames

Hello all,
Let’s say I have a list of stimuli, streams, that represent a series of letters to be displayed on the screen. The amount of streams is somewhat variable, but never exceeds 6 streams at a time. Let’s also say I have a three dimensional list of streams, trial.stream, with an associated flag (which is not important for the question) that gets looped through to assign each stimulus with the appropriate letter to display on the screen. So, for example, trial.stream may look like [[['X, 'A'], True], [['T', 'B'], True]] (this is only two elements long, trial.stream is always 25 elements long).

Each letter in each stream needs to be displayed for 400ms (with a 60Hz monitor, that’s 24 frames), then undrawn and the next letter goes up, with each letter in the same sublist being displayed concurrently (in the earlier example, 'X' and 'A' should be on the screen at the same time, then 'T' and 'B').

Initially, I tried displaying the stimuli according to time, but found some posts on the forum that made it seem like timing by frames was the better approach. To that end, I’ve written this code to do that with trial.stream and streams (sorry for the bad indentation but I can’t be bothered to fix it as the code’s still readable):

# Generate trial
trial = rsvp.generate_phase1_trial(trial_id, level)
# Decide the correct position for each stimulus
streams = rsvp.positioning(streams, level) 
            # Iterate through stream, discarding the flag
            for letters, _ in trial.stream:
                # Is a target in the stream?
                T_in_stream = "T" in letters
                for j in range(len(letters)):
                    # Get key responses for the letter 't'
                    t_press = stimuli_key_resp.getKeys(['t'], waitRelease = False)
                    #Update frame data
                    frameN += 1
                    stream = streams[j]
                    stream.text = letters[j]

                    # Has the stream been started?  If not, start it
                    if stream.status == NOT_STARTED:
                        stream.status = STARTED
                        stream.frameNStart = frameN
                        stream.setAutoDraw(True)
                    if stream.status == STARTED and frameN >= stream.frameNStart + 24: # 24 frames = 400 ms
                        stream.status = FINISHED
                        stream.frameNStop = frameN
                        stream.setAutoDraw(False)
 
                    if T_in_stream and 't' in t_press:
                        print("Hit", t_press, trial.hit)
                        trial.hit += 1
                    elif 't' in t_press and not T_in_stream:
                        print("False alarm", t_press, trial.false_alarm)
                        trial.false_alarm += 1
                    win.flip()

            trials.append(trial)
            trial_id += 1

I have two questions relating to this code and what I’m trying to do:

  1. Is it appropriate to loop through the list of stimuli like that and set them all to draw/undraw at a specified relative frame? My concern is that the if is only checked when the for loop is iterated over, which may not be happening by the time the stimulus is ready to be redrawn with a new letter.

  2. Rather than each letter in each stream being displayed at 400ms intervals, this code displays letters as fast as the loop can iterate and stops drawing any letters 24 frames after the first letter is drawn. I’m not sure what in the code is causing this behavior.

I can give more information as needed, just not sure what else is needed. Thanks in advance!