def __init__(self, experiment, tracker): """ Constructor Arguments: experiment -- opensesame experiment tracker -- an eyelink instance """ pylink.EyeLinkCustomDisplay.__init__(self) self.experiment = experiment self.my_canvas = canvas(self.experiment) self.my_keyboard = keyboard(self.experiment, timeout=0) self.my_mouse = mouse(self.experiment) self.__target_beep__ = synth(self.experiment, length = 50) self.__target_beep__done__ = synth(self.experiment, freq = 880, length = 200) self.__target_beep__error__ = synth(self.experiment, freq = 220, length = 200) self.state = None self.imagebuffer = array.array('l') self.pal = None self.size = (0,0) self.tmp_file = os.path.join(tempfile.gettempdir(), '__eyelink__.jpg') self.set_tracker(tracker) self.last_mouse_state = -1 self.experiment.eyelink_esc_pressed = False
def drift_correction(self, pos = None, fix_triggered = False): """Dummy drift correction""" if fix_triggered: return self.fix_triggered_drift_correction(pos) self.simulator.set_visible(visible=True) my_keyboard = keyboard(self.experiment, keylist=["space"], timeout=0) errorbeep = synth(self.experiment, freq=220, length=200) if pos == None: pos = self.resolution[0] / 2, self.resolution[1] / 2 errdist = 60 # pixels (on a 1024x768px and 39.9x29.9cm monitor at 67 cm, this is about 2 degrees of visual angle) pressed = None while not pressed: pressed, presstime = my_keyboard.get_key() if pressed: gazepos = self.sample() if ((gazepos[0]-pos[0])**2 + (gazepos[1]-pos[1])**2)**0.5 < errdist: self.simulator.set_visible(visible=False) return True errorbeep.play() self.simulator.set_visible(visible=False) return False
def run(self): """The run phase of the plug-in goes here.""" if hasattr(self.experiment, u'pygaze_eyetracker'): raise osexception( \ u'You should have only one instance of `pygaze_init` in your experiment') self.set_item_onset() # Determine the tracker type and perform certain tracker-specific # operations. if self.tracker_type == u'Simple dummy': tracker_type = u'dumbdummy' elif self.tracker_type == u'Advanced dummy (mouse simulation)': tracker_type = u'dummy' elif self.tracker_type == u'EyeLink': tracker_type = u'eyelink' if self.get(u'eyelink_calbeep'): from openexp.synth import synth self.beep = synth(self.experiment) elif self.tracker_type == u'Tobii': tracker_type = u'tobii' elif self.tracker_type == u'SMI': tracker_type = u'smi' else: raise osexception(u'Unknown tracker type: %s' % self.tracker_type) # Determine logfile if self.get(u'_logfile') == u'automatic': logfile = os.path.splitext(self.get(u'logfile'))[0] if tracker_type == u'eyelink': logfile = logfile + u'.edf' else: logfile = self.get(u'_logfile') # Determine event detection if tracker_type == u'eyelink': event_detection = u'native' else: event_detection = u'pygaze' # Initialize pygaze and the eye-tracker object self.experiment.pygaze_display = Display(u'opensesame') self.experiment.pygaze_eyetracker = EyeTracker( \ self.experiment.pygaze_display, trackertype=tracker_type, \ data_file=logfile, eventdetection=event_detection, \ saccade_velocity_threshold=self.get(u'sacc_vel_thr'), \ saccade_acceleration_threshold=self.get(u'sacc_acc_thr'), \ ip=self.get(u'smi_ip'), sendport=self.get(u'smi_send_port'), \ receiveport=self.get(u'smi_recv_port'), logfile=logfile, eyelink_force_drift_correct= \ self.get(u'eyelink_force_drift_correct')) self.experiment.pygaze_eyetracker.set_draw_calibration_target_func( \ self.draw_calibration_canvas) self.experiment.cleanup_functions.append(self.close) if self.calibrate == u'yes': self.experiment.pygaze_eyetracker.calibrate()
def __init__(self, experiment, port='COM1', baudrate=115200, sound=True): """<DOC> Initializes the SMI tracker class Keyword arguments: port -- the name of the serial port to which the tracker is attached (default = 'COM1') baudrate -- the baudrate of the serial port communications (default = 115200) sound -- indicates if sounds should be played to inidicate success or failure </DOC>""" self.experiment = experiment self.tracker = serial.Serial(port=port, baudrate=baudrate, timeout=0.5) self.my_keyboard = keyboard(experiment) self.my_canvas = canvas(experiment) self.streaming = False self.sound = sound if self.sound: self.beep1 = synth(self.experiment, freq=220) self.beep1.volume(0.5) self.beep2 = synth(self.experiment, freq=440, length=200) self.beep2.volume(0.5) self.stop_recording()
def synth(osc="sine", freq=440, length=100, attack=0, decay=5): """ desc: Synthesizes a sound and returns it as a `sampler` object. keywords: osc: desc: Oscillator, can be "sine", "saw", "square" or "white_noise". type: [str, unicode] freq: desc: Frequency, either an integer value (value in hertz) or a string ("A1", "eb2", etc.). type: [str, unicode, int, float] length: desc: The length of the sound in milliseconds. type: [int, float] attack: desc: The attack (fade-in) time in milliseconds. type: [int, float] decay: desc: The decay (fade-out) time in milliseconds. type: [int, float] returns: desc: A SAMPLER object. type: sampler example: | my_sampler = synth(freq=u'b2', length=500) """ from openexp.synth import synth return synth(experiment, osc=osc, freq=freq, length=length, attack=attack, decay=decay)
def synth(osc="sine", freq=440, length=100, attack=0, decay=5): """ desc: Synthesizes a sound and returns it as a `sampler` object. keywords: osc: desc: Oscillator, can be "sine", "saw", "square" or "white_noise". type: [str, unicode] freq: desc: Frequency, either an integer value (value in hertz) or a string ("A1", "eb2", etc.). type: [str, unicode, int, float] length: desc: The length of the sound in milliseconds. type: [int, float] attack: desc: The attack (fade-in) time in milliseconds. type: [int, float] decay: desc: The decay (fade-out) time in milliseconds. type: [int, float] returns: desc: A `sampler` object. type: sampler example: | my_sampler = synth(freq=u'b2', length=500) """ from openexp.synth import synth return synth(experiment, osc=osc, freq=freq, length=length, attack=attack, decay=decay)
def run(self): """ desc: The run phase of the plug-in goes here. """ if hasattr(self.experiment, u'pygaze_eyetracker'): raise osexception( u'You should have only one instance of `pygaze_init` in your experiment') self.set_item_onset() # Determine the tracker type and perform certain tracker-specific # operations. kwdict = {} if self.var.tracker_type == u'Simple dummy': tracker_type = u'dumbdummy' elif self.var.tracker_type == u'Advanced dummy (mouse simulation)': tracker_type = u'dummy' elif self.var.tracker_type == u'EyeLink': tracker_type = u'eyelink' elif self.var.tracker_type == u'Tobii': tracker_type = u'tobii' kwdict[u'eyelink_force_drift_correct'] = \ self.var.eyelink_force_drift_correct == u'yes' kwdict[u'pupil_size_mode'] = self.var.eyelink_pupil_size_mode elif self.var.tracker_type == u'SMI': tracker_type = u'smi' kwdict[u'ip'] = self.var.smi_ip kwdict[u'sendport'] = self.var.smi_send_port kwdict[u'receiveport'] = self.var.smi_recv_port elif self.var.tracker_type == u'EyeTribe': tracker_type = u'eyetribe' else: raise osexception( u'Unknown tracker type: %s' % self.var.tracker_type) # Determine logfile if self.var._logfile == u'automatic': logfile = os.path.splitext(self.var.logfile)[0] if tracker_type == u'eyelink': # Automatically shorten filenames like 'subject-0', because # these are too long. This avoids having to rename logfiles # all the time. basename = os.path.basename(logfile) dirname = os.path.dirname(logfile) if len(basename) > 8 and basename.startswith(u'subject-'): basename = u'sub_' + basename[8:] logfile = os.path.join(dirname, basename) print(u'Attention: EyeLink logfile renamed to %s.edf' \ % logfile) elif basename == u'defaultlog': logfile = u'default' print(u'Attention: EyeLink logfile renamed to %s.edf' \ % logfile) logfile = logfile + u'.edf' kwdict[u'data_file'] = logfile else: logfile = self.var._logfile # Determine event detection. Currently, only the EyeLink has native # event detection. if tracker_type == u'eyelink': event_detection = u'native' else: event_detection = u'pygaze' # Initialize pygaze and the eye-tracker object self.experiment.pygaze_display = Display(u'opensesame') self.experiment.pygaze_eyetracker = EyeTracker( self.experiment.pygaze_display, trackertype=tracker_type, eventdetection=event_detection, saccade_velocity_threshold=self.var.sacc_vel_thr, saccade_acceleration_threshold=self.var.sacc_acc_thr, logfile=logfile, **kwdict) if self.var.calbeep == u'yes': from openexp.synth import synth self.beep = synth(self.experiment) self.experiment.pygaze_eyetracker.set_draw_calibration_target_func( self.draw_calibration_canvas) self.experiment.pygaze_eyetracker.set_draw_drift_correction_target_func( self.draw_calibration_canvas) self.experiment.cleanup_functions.append(self.close) if self.var.calibrate == u'yes': self.experiment.pygaze_eyetracker.calibrate() self.python_workspace[u'eyetracker'] = self.experiment.pygaze_eyetracker
def run(self): """ desc: The run phase of the plug-in goes here. """ if hasattr(self.experiment, u'pygaze_eyetracker'): raise osexception( u'You should have only one instance of `pygaze_init` in your experiment' ) self.set_item_onset() # Determine the tracker type and perform certain tracker-specific # operations. kwdict = {} if self.var.tracker_type == u'Simple dummy': tracker_type = u'dumbdummy' elif self.var.tracker_type == u'Advanced dummy (mouse simulation)': tracker_type = u'dummy' elif self.var.tracker_type == u'EyeLink': tracker_type = u'eyelink' kwdict[u'eyelink_force_drift_correct'] = \ self.var.eyelink_force_drift_correct == u'yes' kwdict[u'pupil_size_mode'] = self.var.eyelink_pupil_size_mode elif self.var.tracker_type == u'SMI': tracker_type = u'smi' kwdict[u'ip'] = self.var.smi_ip kwdict[u'sendport'] = self.var.smi_send_port kwdict[u'receiveport'] = self.var.smi_recv_port elif self.var.tracker_type == u'EyeTribe': tracker_type = u'eyetribe' elif self.var.tracker_type == u'OpenGaze': tracker_type = u'opengaze' elif self.var.tracker_type == u'Alea': tracker_type = u'alea' kwdict[u'alea_key'] = self.var.alea_api_key kwdict[u'animated_calibration'] = \ self.var.alea_animated_calibration == u'yes' elif self.var.tracker_type == u'Tobii': tracker_type = u'tobii' elif self.var.tracker_type == u'Tobii-legacy': tracker_type = u'tobii-legacy' elif self.var.tracker_type == u'Tobii Pro Glasses 2': tracker_type = u'tobiiglasses' kwdict[u'address'] = self.var.tobiiglasses_address kwdict[u'udpport'] = self.var.tobiiglasses_udpport else: raise osexception(u'Unknown tracker type: %s' % self.var.tracker_type) # Determine logfile if self.var._logfile == u'automatic': logfile = os.path.splitext(self.var.logfile)[0] if tracker_type == u'eyelink': # Automatically shorten filenames like 'subject-0', because # these are too long. This avoids having to rename logfiles # all the time. basename = os.path.basename(logfile) dirname = os.path.dirname(logfile) if len(basename) > 8 and basename.startswith(u'subject-'): basename = u'sub_' + basename[8:] logfile = os.path.join(dirname, basename) print(u'Attention: EyeLink logfile renamed to %s.edf' \ % logfile) elif basename == u'defaultlog': logfile = u'default' print(u'Attention: EyeLink logfile renamed to %s.edf' \ % logfile) logfile = logfile + u'.edf' kwdict[u'data_file'] = logfile else: logfile = self.var._logfile # Register the logfile with OpenSesame self.experiment.data_files.append(logfile) # Determine event detection. Currently, only the EyeLink has native # event detection. if tracker_type == u'eyelink': event_detection = u'native' else: event_detection = u'pygaze' # Initialize pygaze and the eye-tracker object self.experiment.pygaze_display = Display(u'opensesame') self.experiment.pygaze_eyetracker = EyeTracker( self.experiment.pygaze_display, trackertype=tracker_type, eventdetection=event_detection, saccade_velocity_threshold=self.var.sacc_vel_thr, saccade_acceleration_threshold=self.var.sacc_acc_thr, logfile=logfile, **kwdict) if self.var.calbeep == u'yes': from openexp.synth import synth self.beep = synth(self.experiment) self.experiment.pygaze_eyetracker.set_draw_calibration_target_func( self.draw_calibration_canvas) self.experiment.pygaze_eyetracker.set_draw_drift_correction_target_func( self.draw_calibration_canvas) self.experiment.cleanup_functions.append(self.close) if self.var.calibrate == u'yes': self.experiment.pygaze_eyetracker.calibrate() self.python_workspace[ u'eyetracker'] = self.experiment.pygaze_eyetracker
def run(self): """ desc: The run phase of the plug-in goes here. """ if hasattr(self.experiment, u'pygaze_eyetracker'): raise osexception( \ u'You should have only one instance of `pygaze_init` in your experiment') self.set_item_onset() # Determine the tracker type and perform certain tracker-specific # operations. if self.tracker_type == u'Simple dummy': tracker_type = u'dumbdummy' elif self.tracker_type == u'Advanced dummy (mouse simulation)': tracker_type = u'dummy' elif self.tracker_type == u'EyeLink': tracker_type = u'eyelink' elif self.tracker_type == u'Tobii': tracker_type = u'tobii' elif self.tracker_type == u'SMI': tracker_type = u'smi' elif self.tracker_type == u'EyeTribe': tracker_type = u'eyetribe' else: raise osexception(u'Unknown tracker type: %s' % self.tracker_type) # Determine logfile if self.get(u'_logfile') == u'automatic': logfile = os.path.splitext(self.get(u'logfile'))[0] if tracker_type == u'eyelink': # Automatically shorten filenames like 'subject-0', because # these are too long. This avoids having to rename logfiles # all the time. basename = os.path.basename(logfile) dirname = os.path.dirname(logfile) if len(basename) > 8 and basename.startswith(u'subject-'): basename = u'sub_' + basename[8:] logfile = os.path.join(dirname, basename) print(u'Attention: EyeLink logfile renamed to %s.edf' \ % logfile) elif basename == u'defaultlog': logfile = u'default' print(u'Attention: EyeLink logfile renamed to %s.edf' \ % logfile) logfile = logfile + u'.edf' else: logfile = self.get(u'_logfile') # Determine event detection if tracker_type == u'eyelink': event_detection = u'native' else: event_detection = u'pygaze' # Initialize pygaze and the eye-tracker object self.experiment.pygaze_display = Display(u'opensesame') self.experiment.pygaze_eyetracker = EyeTracker( self.experiment.pygaze_display, trackertype=tracker_type, data_file=logfile, eventdetection=event_detection, saccade_velocity_threshold=self.get(u'sacc_vel_thr'), saccade_acceleration_threshold=self.get(u'sacc_acc_thr'), ip=self.get(u'smi_ip'), sendport=self.get(u'smi_send_port'), receiveport=self.get(u'smi_recv_port'), logfile=logfile, eyelink_force_drift_correct=self.get( u'eyelink_force_drift_correct'),pupil_size_mode=self.get( u'eyelink_pupil_size_mode')) if self.get(u'calbeep') == 'yes': from openexp.synth import synth self.beep = synth(self.experiment) self.experiment.pygaze_eyetracker.set_draw_calibration_target_func( self.draw_calibration_canvas) self.experiment.pygaze_eyetracker.set_draw_drift_correction_target_func( self.draw_calibration_canvas) self.experiment.cleanup_functions.append(self.close) if self.calibrate == u'yes': self.experiment.pygaze_eyetracker.calibrate()
def __init__(self, experiment, resolution, data_file=u'default', fg_color=(255, 255, 255), bg_color=(0, 0, 0), saccade_velocity_threshold=35, saccade_acceleration_threshold=9500, force_drift_correct=False, ip='127.0.0.1', sendport=4444, receiveport=5555, screen_w=399, screen_h=299): """<DOC> Constructor. Initializes the connection to the Eyelink. Arguments: experiment -- The experiment object. resolution -- A (width, height) tuple. Keyword arguments: data_file -- The name of the IDF file. (default=u'default.idf') fg_color -- The foreground color for the calibration screen. # (default=255,255,255); SMI only allows black # and white, so colour is recalculated to # grayscale, using Y' = 0.299*r + 0.587*g + 0.114*b bg_color -- The background color for the calibration screen. # (default=0,0,0); SMI only allows black # and white, so colour is recalculated to # grayscale, using Y' = 0.299*r + 0.587*g + 0.114*b saccade_velocity_threshold -- The velocity threshold used for # saccade detection. (default=35) saccade_acceleration_threshold -- The acceleration threshold used # for saccade detection. # (default=9500) force_drift_correct -- ignored by libsmi ip -- internal ip address for iViewX (default = '127.0.0.1') sendport -- port number for iViewX sending (default = 4444) receiveport -- port number for iViewX receiving (default = 5555) screen_w -- physical screen width in millimeters (default = 399) screen_h -- physical screen height in millimeters (default = 299) </DOC>""" # properties self.experiment = experiment # self.display = display # self.screen = libscreen.Screen() self.outputfile = data_file if type(fg_color) != str: bw = int(0.299*fg_color[0] + 0.587*fg_color[1] + 0.114*fg_color[2]) self.fgc = (bw, bw, bw) self.calfgc = bw else: self.fgc = fg_color self.calfgc = 255 if type(bg_color) != str: bw = int(0.299*bg_color[0] + 0.587*bg_color[1] + 0.114*bg_color[2]) self.bgc = (bw, bw, bw) self.calbgc = bw else: self.bgc = bg_color self.calbgc = 0 self.description = "OpenSesame_experiment" self.participant = "participant" self.connected = False self.recording = False self.calibrated = False self.validated = False self.eye_used = 0 # 0=left, 1=right, 2=binocular self.left_eye = 0 self.right_eye = 1 self.binocular = 2 self.cv = canvas(self.experiment, fgcolor=self.fgc, bgcolor=self.bgc) self.kb = keyboard(self.experiment) self.errorbeep = synth(self.experiment, osc='saw', freq=100, length=100) self.errdist = 2 # degrees self.fixtresh = 1.5 # degrees self.spdtresh = saccade_velocity_threshold # degrees per second; saccade speed threshold self.accthresh = saccade_acceleration_threshold # degrees per second**2; saccade acceleration threshold self.weightdist = 10 # weighted distance, used for determining whether a movement is due to measurement error (1 is ok, higher is more conservative and will result in only larger saccades to be detected) self.dispsize = resolution # display size in pixels self.screensize = (screen_w/10.0, screen_h/10.0) # display size in cm self.prevsample = (-1,-1) self.maxtries = 100 # number of samples obtained before giving up (for obtaining accuracy and tracker distance information, as well as starting or stopping recording) # set logger res = iViewXAPI.iV_SetLogger(c_int(1), c_char_p(data_file + '_SMILOG.txt')) if res != 1: err = errorstring(res) print("Error in libsmi.libsmi.__init__: failed to set logger; %s" % err) # first logger argument is for logging type (I'm guessing these are decimal bit codes) # LOG status bitcode # 1 = LOG_LEVEL_BUG 00001 # 2 = LOG_LEVEL_iV_FCT 00010 # 4 = LOG_LEVEL_ETCOM 00100 # 8 = LOG_LEVEL_ALL 01000 # 16 = LOG_LEVEL_IV_COMMAND 10000 # these can be used together, using a bitwise or, e.g.: 1|2|4 (bitcode 00111) # connect to iViewX res = iViewXAPI.iV_Connect(c_char_p(ip), c_int(sendport), c_char_p(ip), c_int(receiveport)) if res == 1: res = iViewXAPI.iV_GetSystemInfo(byref(systemData)) self.samplerate = systemData.samplerate self.sampletime = 1000.0 / self.samplerate if res != 1: err = errorstring(res) print("Error in libsmi.libsmi.__init__: failed to get system information; %s" % err) # handle connection errors else: err = errorstring(res) print("Error in libsmi.libsmi.__init__: establishing connection failed; %s" % err) self.connected = False # initiation report self.log("pygaze initiation report start") self.log("experiment: %s" % self.description) self.log("participant: %s" % self.participant) self.log("display resolution: %sx%s" % (self.dispsize[0],self.dispsize[1])) self.log("display size in cm: %sx%s" % (self.screensize[0],self.screensize[1])) self.log("samplerate: %s Hz" % self.samplerate) self.log("sampletime: %s ms" % self.sampletime) self.log("fixation threshold: %s degrees" % self.fixtresh) self.log("speed threshold: %s degrees/second" % self.spdtresh) self.log("accuracy threshold: %s degrees/second**2" % self.accthresh) self.log("pygaze initiation report end")