class RSVPAlertToneCalibrationTask(Task):
    """RSVP Calibration Task that uses alert tones to maintain user focus.

    Calibration task performs an RSVP stimulus sequence to elicit an ERP.
    Parameters will change how many stim and for how long they present.
    Parameters also change color and text / image inputs and alert sounds.

    This task uses the 'alert_sounds_path' parameter to determine which sounds
    to play when a letter is presented to the participant. Sounds are read in
    from the configured directory and cycled through in alphabetical order.
    Sounds with the word 'blank' in the file name will not be played, allowing
    experiments to be setup in which some letters do not have alerts.

    Input:
        win (PsychoPy Display Object)
        daq (Data Acquisition Object)
        parameters (Dictionary)
        file_save (String)

    Output:
        file_save (String)
    """
    TASK_NAME = 'RSVP Alert Tone Calibration Task'

    def __init__(self, win, daq, parameters, file_save):
        super(RSVPAlertToneCalibrationTask, self).__init__()
        self._task = RSVPCalibrationTask(win, daq, parameters, file_save)

        # Delay between sound and letter presentation; default is 400 ms.
        # see: Testing the Efficiency and Independence of Attentional Networks
        # by Jin Fan, Bruce D. McCandliss, Tobias Sommer, Amir Raz, and
        # Michael I. Posner
        sound_delay = parameters.get('alert_sound_delay', 0.4)
        alerts = soundfiles(parameters['alert_sounds_path'])

        def play_sound_callback(_sti):
            sound_path = next(alerts)
            if "blank" in sound_path:
                return
            play_sound(sound_path,
                       sound_load_buffer_time=0,
                       sound_post_buffer_time=sound_delay)

        self._task.rsvp.first_stim_callback = play_sound_callback

    def execute(self):
        self.logger.debug(f'Starting {self.name()}!')
        self._task.execute()

    @classmethod
    def label(cls):
        return RSVPAlertToneCalibrationTask.TASK_NAME

    def name(self):
        return RSVPAlertToneCalibrationTask.TASK_NAME
Exemple #2
0
class RSVPTimingVerificationCalibration(Task):
    """RSVP Calibration Task that for verifying timing.

    Input:
        win (PsychoPy Display Object)
        daq (Data Acquisition Object)
        parameters (Dictionary)
        file_save (String)

    Output:
        file_save (String)
    """
    TASK_NAME = 'RSVP Timing Verification Task'

    def __init__(self, win, daq, parameters, file_save):
        super(RSVPTimingVerificationCalibration, self).__init__()
        parameters['stim_height'] = 0.8
        parameters['stim_pos_y'] = 0.2
        self._task = RSVPCalibrationTask(win, daq, parameters, file_save)
        self._task.generate_stimuli = self.generate_stimuli

    def generate_stimuli(self):
        """Generates the inquiries to be presented.
        Returns:
        --------
            tuple(
                samples[list[list[str]]]: list of inquiries
                timing(list[list[float]]): list of timings
                color(list(list[str])): list of colors)
        """
        samples, times, colors = [], [], []

        solid_box = '\u25A0'
        empty_box = '\u25A1'

        target = 'x'  # solid_box  # 'X'
        fixation = '\u25CB'  # circle

        # alternate between solid and empty boxes
        letters = cycle([solid_box, empty_box])
        time_target, time_fixation, time_stim = self._task.timing
        color_target, color_fixation, color_stim = self._task.color

        inq_len = self._task.stim_length
        inq_stim = [target, fixation, *[next(letters) for _ in range(inq_len)]]
        inq_times = [time_target, time_fixation, *[time_stim for _ in range(inq_len)]]
        inq_colors = [color_target, color_fixation, *[color_stim for _ in range(inq_len)]]

        for _ in range(self._task.stim_number):
            samples.append(inq_stim)
            times.append(inq_times)
            colors.append(inq_colors)

        return (samples, times, colors)

    def execute(self):
        self.logger.debug(f'Starting {self.name()}!')
        self._task.execute()

    @classmethod
    def label(cls):
        return RSVPTimingVerificationCalibration.TASK_NAME

    def name(self):
        return RSVPTimingVerificationCalibration.TASK_NAME