def record(self, sec, file='', block=True): """Capture sound input for duration <sec>, save to a file. Return the path/name to the new file. Uses onset time (epoch) as a meaningful identifier for filename and log. """ while self.recorder.running: pass self.duration = float(sec) self.onset = core.getTime() # note: report onset time in log, and use in filename logging.data('%s: Record: onset %.3f, capture %.3fs' % (self.loggingId, self.onset, self.duration) ) if not file: onsettime = '-%.3f' % self.onset self.savedFile = onsettime.join(os.path.splitext(self.wavOutFilename)) else: self.savedFile = os.path.abspath(file).strip('.wav') + '.wav' t0 = core.getTime() self.recorder.run(self.savedFile, self.duration, self.sampletype) self.rate = sound.pyoSndServer.getSamplingRate() if block: core.wait(self.duration - .0008) # .0008 fudge factor for better reporting # actual timing is done by Clean_objects logging.exp('%s: Record: stop. %.3f, capture %.3fs (est)' % (self.loggingId, core.getTime(), core.getTime() - t0) ) else: logging.exp('%s: Record: return immediately, no blocking' % (self.loggingId) ) return self.savedFile
def waitKeys(maxWait=float('inf'), keyList=None, timeStamped=False): """ Same as `~psychopy.event.getKeys`, but halts everything (including drawing) while awaiting input from keyboard. Implicitly clears keyboard, so any preceding keypresses will be lost. :Parameters: maxWait : any numeric value. Maximum number of seconds period and which keys to wait for. Default is float('inf') which simply waits forever. Returns None if times out. """ #NB pygame.event does have a wait() function that will #do this and maybe leave more cpu idle time? key = None clearEvents('keyboard') # So that we only take presses from here onwards. # Check for keypresses until maxWait is exceeded timer = psychopy.core.Clock() while key == None and timer.getTime() < maxWait: # Pump events on pyglet windows if they exist if havePyglet: wins = pyglet.window.get_platform().get_default_display().get_windows() for win in wins: win.dispatch_events() # Get keypresses and return if anything is pressed keys = getKeys(keyList=keyList, timeStamped=timeStamped) if len(keys): return keys # If maxWait is exceeded (exits while-loop), return None logging.data("No keypress (maxWait exceeded)") return None
def record(self, sec, block=True): """Capture sound input for duration <sec>, save to a file. Return the path/name to the new file. Uses onset time (epoch) as a meaningful identifier for filename and log. """ RECORD_SECONDS = float(sec) self.onset = time.time() # note: report onset time in log, and use in filename logging.data('%s: Record: onset %.3f, capture %.3fs' % (self.loggingId, self.onset, RECORD_SECONDS) ) self.savedFile = self.wavOutFilename.replace(ONSET_TIME_HERE, '-%.3f' % self.onset) inputter = Input(chnl=0, mul=1) # chnl=[0,1] for stereo input t0 = time.time() # launch the recording, saving to file: recorder = Record(inputter, self.savedFile, chnls=2, fileformat=0, # .wav format sampletype=0, buffering=4) # 4 is default # launch recording, block as needed, and clean up: clean = Clean_objects(RECORD_SECONDS, recorder) # set up to stop recording clean.start() # the timer starts now, ends automatically whether block or not if block: time.sleep(RECORD_SECONDS - 0.0008) # Clean_objects() set-up takes ~0.0008s, for me logging.exp('%s: Record: stop. %.3f, capture %.3fs (est)' % (self.loggingId, time.time(), time.time() - t0) ) else: logging.exp('%s: Record: return immediately, no blocking' % (self.loggingId) ) self.duration = RECORD_SECONDS # used in playback() return self.savedFile # filename, or None
def _onPygletKey(symbol, modifiers, emulated=False): """handler for on_key_press pyglet events, or call directly to emulate a key press Appends a tuple with (keyname, timepressed) into the global _keyBuffer. The _keyBuffer can then be accessed as normal using event.getKeys(), .waitKeys(), clearBuffer(), etc. J Gray 2012: Emulated means add a key (symbol) to the buffer virtually. This is useful for fMRI_launchScan, and for unit testing (in testTheApp) Logging distinguished EmulatedKey events from real Keypress events. For emulation, the key added to the buffer is unicode(symbol), instead of pyglet.window.key.symbol_string(symbol) S Mathot 2012: Implement fallback to _onPygletText """ global useText keyTime=psychopy.core.getTime() #capture when the key was pressed if emulated: thisKey = unicode(symbol) keySource = 'EmulatedKey' else: thisKey = pyglet.window.key.symbol_string(symbol).lower() #convert symbol into key string #convert pyglet symbols to pygame forms ( '_1'='1', 'NUM_1'='[1]') # 'user_key' indicates that Pyglet has been unable to make sense out of # the keypress. In that case, we fall back to _onPygletText to handle # the input. if 'user_key' in thisKey: useText = True return useText = False thisKey = thisKey.lstrip('_').lstrip('NUM_') keySource = 'Keypress' _keyBuffer.append( (thisKey,keyTime) ) # tuple logging.data("%s: %s" % (keySource, thisKey))
def _record(self, sec, filename="", block=True, log=True): while self.recorder.running: pass self.duration = float(sec) self.onset = core.getTime() # for duration estimation, high precision self.fileOnset = core.getAbsTime() # for log and filename, 1 sec precision ms = "%.3f" % (core.getTime() - int(core.getTime())) if log and self.autoLog: logging.data("%s: Record: onset %d, capture %.3fs" % (self.loggingId, self.fileOnset, self.duration)) if not filename: onsettime = "-%d" % self.fileOnset + ms[1:] self.savedFile = onsettime.join(os.path.splitext(self.wavOutFilename)) else: self.savedFile = os.path.abspath(filename).strip(".wav") + ".wav" t0 = core.getTime() self.recorder.run(self.savedFile, self.duration, **self.options) self.rate = sound.pyoSndServer.getSamplingRate() if block: core.wait(self.duration, 0) if log and self.autoLog: logging.exp( "%s: Record: stop. %.3f, capture %.3fs (est)" % (self.loggingId, core.getTime(), core.getTime() - t0) ) while self.recorder.running: core.wait(0.001, 0) else: if log and self.autoLog: logging.exp("%s: Record: return immediately, no blocking" % (self.loggingId)) return self.savedFile
def _onGLFWKey(*args, **kwargs): """Callback for key/character events for the GLFW backend. :return: """ keyTime = psychopy.core.getTime() # get timestamp # TODO - support for key emulation win_ptr, key, scancode, action, modifiers = args global useText if key == glfw.KEY_UNKNOWN: useText = True return useText = False # get the printable name, always make lowercase key_name = glfw.get_key_name(key, scancode) # if there is no localized key name or space if key_name is None or key_name == ' ': try: key_name = _glfw_keycodes_[key] except KeyError: pass else: key_name = key_name.lower() # TODO - modifier integration keySource = 'Keypress' _keyBuffer.append((key_name, modifiers, keyTime)) # tuple logging.data("%s: %s" % (keySource, key_name))
def _onPygletText(text, emulated=False): """handler for on_text pyglet events, or call directly to emulate a text event. S Mathot 2012: This function only acts when the key that is pressed corresponds to a non-ASCII text character (Greek, Arabic, Hebrew, etc.). In that case the symbol that is passed to _onPygletKey() is translated into a useless 'user_key()' string. If this happens, _onPygletText takes over the role of capturing the key. Unfortunately, _onPygletText() cannot solely handle all input, because it does not respond to spacebar presses, etc. """ global useText if not useText: # _onPygletKey has handled the input return # This is needed because sometimes the execution # sequence is messed up (somehow) useText = False # capture when the key was pressed: keyTime = psychopy.core.getTime() if emulated: keySource = 'EmulatedKey' else: keySource = 'KeyPress' _keyBuffer.append((text.lower(), lastModifiers, keyTime)) logging.data("%s: %s" % (keySource, text))
def _record(self, sec, filename='', block=True): while self.recorder.running: pass self.duration = float(sec) self.onset = core.getTime() # for duration estimation, high precision self.fileOnset = core.getAbsTime() # for log and filename, 1 sec precision logging.data('%s: Record: onset %d, capture %.3fs' % (self.loggingId, self.fileOnset, self.duration) ) if not file: onsettime = '-%d' % self.fileOnset self.savedFile = onsettime.join(os.path.splitext(self.wavOutFilename)) else: self.savedFile = os.path.abspath(filename).strip('.wav') + '.wav' t0 = core.getTime() self.recorder.run(self.savedFile, self.duration, **self.options) self.rate = sound.pyoSndServer.getSamplingRate() if block: core.wait(self.duration, 0) logging.exp('%s: Record: stop. %.3f, capture %.3fs (est)' % (self.loggingId, core.getTime(), core.getTime() - t0) ) while self.recorder.running: core.wait(.001, 0) else: logging.exp('%s: Record: return immediately, no blocking' % (self.loggingId) ) return self.savedFile
def _onGLFWMouseScroll(*args, **kwargs): """Callback for mouse scrolling events. For most computer mice with scroll wheels, only the vertical (Y-offset) is relevant. """ window_ptr, x_offset, y_offset = args global mouseWheelRel mouseWheelRel = mouseWheelRel + numpy.array([x_offset, y_offset]) msg = "Mouse: wheel shift=(%i,%i)" logging.data(msg % (x_offset, y_offset))
def _onPygletMouseRelease(x,y, button, modifiers): global mouseButtons if button == pyglet.window.mouse.LEFT: mouseButtons[0]=0 label='Left' if button == pyglet.window.mouse.MIDDLE: mouseButtons[1]=0 label='Middle' if button == pyglet.window.mouse.RIGHT: mouseButtons[2]=0 label='Right' logging.data("Mouse: %s button up, pos=(%i,%i)" %(label, x,y))
def _onPygletKey(symbol, modifiers, emulated=False): """handler for on_key_press pyglet events; call directly to emulate a key press Appends a tuple with (keyname, timepressed) into the global _keyBuffer. The _keyBuffer can then be accessed as normal using event.getKeys(), .waitKeys(), clearBuffer(), etc. J Gray 2012: Emulated means add a key (symbol) to the buffer virtually. This is useful for fMRI_launchScan, and for unit testing (in testTheApp) Logging distinguishes EmulatedKey events from real Keypress events. For emulation, the key added to the buffer is unicode(symbol), instead of pyglet.window.key.symbol_string(symbol). S Mathot 2012: Implement fallback to _onPygletText 5AM Solutions 2016: Add the keyboard modifier flags to the key buffer. M Cutone 2018: Added GLFW backend support. """ global useText, lastModifiers keyTime = psychopy.core.getTime() # capture when the key was pressed if emulated: if not isinstance(modifiers, int): msg = 'Modifiers must be passed as an integer value.' raise ValueError(msg) thisKey = str(symbol) keySource = 'EmulatedKey' else: thisKey = pyglet.window.key.symbol_string( symbol).lower() # convert symbol into key string # convert pyglet symbols to pygame forms ( '_1'='1', 'NUM_1'='[1]') # 'user_key' indicates that Pyglet has been unable to make sense # out of the keypress. In that case, we fall back to _onPygletText # to handle the input. if 'user_key' in thisKey: useText = True lastModifiers = modifiers return useText = False thisKey = thisKey.lstrip('_').lstrip('NUM_') # Pyglet 1.3.0 returns 'enter' when Return key (0xFF0D) is pressed # in Windows Python3. So we have to replace 'enter' with 'return'. if thisKey == 'enter': thisKey = 'return' keySource = 'Keypress' _keyBuffer.append((thisKey, modifiers, keyTime)) # tuple logging.data("%s: %s" % (keySource, thisKey)) _process_global_event_key(thisKey, modifiers)
def stop(self): """Interrupt a recording that is in progress; close & keep the file. Ends the recording before the duration that was initially specified. The same file name is retained, with the same onset time but a shorter duration. The same recording cannot be resumed after a stop (it is not a pause), but you can start a new one. """ if not self.recorder.running: logging.exp('%s: Stop requested, but no record() in progress' % self.loggingId ) return self.duration = core.getTime() - self.onset # new shorter duration self.recorder.stop() logging.data('%s: Record stopped early, new duration %.3fs' % (self.loggingId, self.duration))
def _onPygletMousePress(x,y, button, modifiers): global mouseButtons, mouseClick, mouseTimes if button == pyglet.window.mouse.LEFT: mouseButtons[0]=1 mouseTimes[0]= psychopy.clock.getTime()-mouseClick[0].getLastResetTime() label='Left' if button == pyglet.window.mouse.MIDDLE: mouseButtons[1]=1 mouseTimes[1]= psychopy.clock.getTime()-mouseClick[1].getLastResetTime() label='Middle' if button == pyglet.window.mouse.RIGHT: mouseButtons[2]=1 mouseTimes[2]= psychopy.clock.getTime()-mouseClick[2].getLastResetTime() label='Right' logging.data("Mouse: %s button down, pos=(%i,%i)" %(label, x,y))
def _onPygletMouseRelease(x, y, button, modifiers, emulated=False): global mouseButtons if emulated: label = 'Emulated' else: label = '' if button & LEFT: mouseButtons[0] = 0 label += ' Left' if button & MIDDLE: mouseButtons[1] = 0 label += ' Middle' if button & RIGHT: mouseButtons[2] = 0 label += ' Right' logging.data("Mouse: %s button up, pos=(%i,%i)" % (label, x, y))
def _onGLFWText(*args, **kwargs): """Handle unicode character events if _onGLFWKey() cannot. :return: """ keyTime = psychopy.core.getTime() # get timestamp # TODO - support for key emulation win_ptr, codepoint, modifiers = args # win = glfw.get_window_user_pointer(win_ptr) text = chr(codepoint) # convert to unicode character (Python 3.0) global useText if not useText: # _onPygletKey has handled the input return keySource = 'KeyPress' _keyBuffer.append((text, keyTime)) logging.data("%s: %s" % (keySource, text))
def _record(self, sec, filename='', block=True, log=True): filename = pathToString(filename) while self.recorder.running: pass self.duration = float(sec) # for duration estimation, high precision: self.onset = core.getTime() # use time for unique log and filename, 1 sec precision self.fileOnset = core.getAbsTime() ms = "%.3f" % (core.getTime() - int(core.getTime())) if log and self.autoLog: msg = '%s: Record: onset %d, capture %.3fs' logging.data(msg % (self.loggingId, self.fileOnset, self.duration)) if not filename: onsettime = '-%d' % self.fileOnset + ms[1:] self.savedFile = onsettime.join( os.path.splitext(self.wavOutFilename)) else: self.savedFile = os.path.abspath(filename) if not self.savedFile.endswith('.wav'): self.savedFile += '.wav' t0 = core.getTime() self.recorder.run(self.savedFile, self.duration, **self.options) self.rate = sound.backend.pyoSndServer.getSamplingRate() if block: core.wait(self.duration, 0) if log and self.autoLog: msg = '%s: Record: stop. %.3f, capture %.3fs (est)' logging.exp(msg % (self.loggingId, core.getTime(), core.getTime() - t0)) while self.recorder.running: core.wait(.001, 0) else: if log and self.autoLog: msg = '%s: Record: return immediately, no blocking' logging.exp(msg % (self.loggingId)) return self.savedFile
def _onPygletMousePress(x,y, button, modifiers, emulated=False): """button left=1, middle=2, right=4; """ global mouseButtons, mouseClick, mouseTimes if emulated: label = 'Emulated' else: label = '' if button & LEFT: mouseButtons[0]=1 mouseTimes[0]= psychopy.clock.getTime()-mouseClick[0].getLastResetTime() label += ' Left' if button & MIDDLE: mouseButtons[1]=1 mouseTimes[1]= psychopy.clock.getTime()-mouseClick[1].getLastResetTime() label += ' Middle' if button & RIGHT: mouseButtons[2]=1 mouseTimes[2]= psychopy.clock.getTime()-mouseClick[2].getLastResetTime() label += ' Right' logging.data("Mouse: %s button down, pos=(%i,%i)" %(label.strip(), x,y))
# %% RENDER_LOOP # Create Counters i = 0 # give the system time to settle core.wait(1) # wait for scanner trigger triggerText.draw() myWin.flip() event.waitKeys(keyList=['5'], timeStamped=False) # reset clocks clock.reset() logging.data('StartOfRun' + unicode(expInfo['run'])) while clock.getTime() < totalTime: keyMask = conditions[i, 0] # blank if conditions[i, 1] == 0: # set texture visTexture = wedge # set timing for the opacity visOpa = cycTransp # horibar elif conditions[i, 1] == 1: # set stimulus position
def begin_trial(self): logging.debug(u'Entered SentenceTrial().begin_trial()') self.text_left.text = '' self.text_right.text = '' logging.info(u'{}: Reset text'.format(self.text_left.name)) logging.info(u'{}: Reset text'.format(self.text_right.name)) self.show_blank(.5 * SPEED_MULTIPLIER) fixation_length = (1 + 1 * random()) * SPEED_MULTIPLIER self.show_fixation(fixation_length) sentence_correct = True prev_pos = '' prev_resp = '' logging.exp(u'trial_clock: Reset time') self.trial_clock.reset() for pair in self.trial: self.show_fixation(0.2 * SPEED_MULTIPLIER) target_pos = self.show_pair(pair) logging.exp(u'pair_clock: Reset time') self.pair_clock.reset() acc, response_time, response = self.get_response(target_pos) self.clear_pair() self.trial.addData('target_pos', target_pos) if target_pos == 0: self.trial.addData('target_pos.verbose', 'L') else: self.trial.addData('target_pos.verbose', 'R') self.trial.addData('resp', response) if response == 0: self.trial.addData('resp.verbose', 'L') else: self.trial.addData('resp.verbose', 'R') self.trial.addData('resp.RT', '{:.2f}'.format(response_time * 1000)) self.trial.addData('resp.acc', acc) self.trial.addData('prev.pos', prev_pos) self.trial.addData('prev.resp', prev_resp) if self.autorun: self.trial.addData( 'TRIAL_AUTORUN', u'EXPERIMENT IN AUTORUN MODE DO NOT USE DATA') prev_pos = target_pos prev_resp = response self.parent.experiment.nextEntry() if acc == 0: logging.exp(u'Incorrect sentence path chosen') sentence_correct = False break block_time = self.trial_clock.getTime() self.show_feedback(sentence_correct) self.experiment.loopEnded(self.trial) if sentence_correct: logging.info(u'Sentence completed accurately.') logging.data(u'Block completion time: {}'.format(block_time)) logging.data(u'Block accuracy: {}'.format(1)) return 1, block_time, fixation_length else: logging.info(u'Sentence was not completed accurately.') logging.data(u'Block completion time: {}'.format(block_time)) logging.data(u'Block accuracy: {}'.format(0)) return 0, block_time, fixation_length
def get_response(self, target_pos): logging.exp(u'Waiting for response...') if self.autorun: logging.exp(u'Autorun active. Sending automatic response...') auto_response_time = 0.5 + random() if randint(0, 100) < 98: return 1, auto_response_time, target_pos else: return 0, auto_response_time, int(not target_pos) if self.use_srbox: response, response_time = self.srbox.waitKeys( keyList=[1, 5], timeStamped=self.pair_clock) response = response[0] else: response, response_time = event.waitKeys( keyList=['c', 'm'], timeStamped=self.pair_clock)[0] logging.exp(u'Key presses received') # response_time = self.pair_clock.getTime() if response in ('c', 1): response = 0 elif response in ('m', 5): response = 1 logging.exp(u'Kepress position: {}'.format(response)) if response == target_pos: logging.info(u'Kepress does match target position.') logging.data(u'Response: {}'.format(response)) logging.data(u'Acc: {}'.format(1)) logging.data(u'Response time: {}'.format(response_time)) return 1, response_time, response else: logging.info(u'Kepress does match target position.') logging.data(u'Response: {}'.format(response)) logging.data(u'Acc: {}'.format(0)) logging.data(u'Response time: {}'.format(response_time)) return 0, response_time, response
def _onPygletMouseWheel(x, y, scroll_x, scroll_y): global mouseWheelRel mouseWheelRel = mouseWheelRel + numpy.array([scroll_x, scroll_y]) msg = "Mouse: wheel shift=(%i,%i), pos=(%i,%i)" logging.data(msg % (scroll_x, scroll_y, x, y))
""" globalClock = core.Clock( ) #if this isn't provided the log times will reflect secs since python started logging.setDefaultClock(globalClock) #use this for logging.console.setLevel( logging.DEBUG) #set the console to receive nearly all messges logDat = logging.LogFile( 'logLastRun.log', filemode='w', #if you set this to 'a' it will append instead of overwriting level=logging.WARNING ) #errors, data and warnings will be sent to this logfile #the following will go to any files with the appropriate minimum level set logging.info('Something fairly unimportant') logging.data('Something about our data. Data is likely very important!') logging.warning( 'Handy while building your experiment - highlights possible flaws in code/design' ) logging.error( "You might have done something that PsychoPy can't handle! But hopefully this gives you some idea what." ) #some things should be logged timestamped on the next video frame #For instance the time of a stimulus appearing is related to the flip: win = visual.Window([400, 400]) for n in range(5): win.logOnFlip('frame %i occured' % n, level=logging.EXP) if n in [2, 4]: win.logOnFlip('an even frame occured', level=logging.EXP) win.flip()
def waitKeys(maxWait=float('inf'), keyList=None, modifiers=False, timeStamped=False, clearEvents=True): """Same as `~psychopy.event.getKeys`, but halts everything (including drawing) while awaiting input from keyboard. :Parameters: maxWait : any numeric value. Maximum number of seconds period and which keys to wait for. Default is float('inf') which simply waits forever. keyList : **None** or [] Allows the user to specify a set of keys to check for. Only keypresses from this set of keys will be removed from the keyboard buffer. If the keyList is `None`, all keys will be checked and the key buffer will be cleared completely. NB, pygame doesn't return timestamps (they are always 0) modifiers : **False** or True If True will return a list of tuples instead of a list of keynames. Each tuple has (keyname, modifiers). The modifiers are a dict of keyboard modifier flags keyed by the modifier name (eg. 'shift', 'ctrl'). timeStamped : **False**, True, or `Clock` If True will return a list of tuples instead of a list of keynames. Each tuple has (keyname, time). If a `core.Clock` is given then the time will be relative to the `Clock`'s last reset. clearEvents : **True** or False Whether to clear the keyboard event buffer (and discard preceding keypresses) before starting to monitor for new keypresses. Returns None if times out. """ if clearEvents: # Only consider keypresses from here onwards. # We need to invoke clearEvents(), but our keyword argument is # also called clearEvents. We can work around this conflict by # accessing the global scope explicitly. globals()['clearEvents']('keyboard') # Check for keypresses until maxWait is exceeded # # NB pygame.event does have a wait() function that will # do this and maybe leave more cpu idle time? timer = psychopy.core.Clock() got_keypress = False while not got_keypress and timer.getTime() < maxWait: # Pump events on pyglet windows if they exist. if havePyglet: for win in _default_display_.get_windows(): win.dispatch_events() # Get keypresses and return if anything is pressed. keys = getKeys(keyList=keyList, modifiers=modifiers, timeStamped=timeStamped) if keys: got_keypress = True if got_keypress: return keys else: logging.data('No keypress (maxWait exceeded)') return None
def waitKeys(maxWait = None, keyList=None): """ Halts everything (including drawing) while awaiting input from keyboard. Then returns *list* of keys pressed. Implicitly clears keyboard, so any preceding keypresses will be lost. Optional arguments specify maximum wait period and which keys to wait for. Returns None if times out. """ #NB pygame.event does have a wait() function that will #do this and maybe leave more cpu idle time? key=None clearEvents('keyboard')#so that we only take presses from here onwards. if maxWait!=None and keyList!=None: #check keylist AND timer timer = psychopy.core.Clock() while key==None and timer.getTime()<maxWait: if havePyglet: wins = pyglet.window.get_platform().get_default_display().get_windows() for win in wins: win.dispatch_events()#pump events on pyglet windows keys = getKeys() #check if we got a key in list if len(keys)>0 and (keys[0] in keyList): key = keys[0] elif keyList!=None: #check the keyList each time there's a press while key==None: if havePyglet: wins = pyglet.window.get_platform().get_default_display().get_windows() for win in wins: win.dispatch_events()#pump events on pyglet windows keys = getKeys() #check if we got a key in list if len(keys)>0 and (keys[0] in keyList): key = keys[0] elif maxWait!=None: #onyl wait for the maxWait timer = psychopy.core.Clock() while key==None and timer.getTime()<maxWait: if havePyglet: wins = pyglet.window.get_platform().get_default_display().get_windows() for win in wins: win.dispatch_events()#pump events on pyglet windows keys = getKeys() #check if we got a key in list if len(keys)>0: key = keys[0] else: #simply take the first key we get while key==None: if havePyglet: wins = pyglet.window.get_platform().get_default_display().get_windows() for win in wins: win.dispatch_events()#pump events on pyglet windows keys = getKeys() #check if we got a key in list if len(keys)>0: key = keys[0] #after the wait period or received a valid keypress if key: logging.data("Key pressed: %s" %key) return [key]#need to convert back to a list else: return None #no keypress in period
def main_block_design(win, globalClock): ############## Stimuli preparation ############## # Fixation cross preparation fixation = visual.Circle(win, radius=10, lineColor='white', fillColor='white', units='pix') subject_instructions = visual.TextStim(win, pos=[0, 0], text='', alignVert='center', wrapWidth=1.5) tennis_sound = sound.Sound(Path_in_sounds + sounds_filename_tennis) house_sound = sound.Sound(Path_in_sounds + sounds_filename_house) faces_sound = sound.Sound(Path_in_sounds + sounds_filename_faces) tennis = [string_tennis, tennis_sound] house = [string_house, house_sound] faces = [string_faces, faces_sound] ############## Definitions/Functions ############## ## handle Rkey presses each frame def escapeCondition(): for key in event.getKeys(): if key in ['escape', 'q']: return False return True ## Display just fixation def displayFixation(win, fixation_time=2, break_flag=True): timer_fixation = core.CountdownTimer(fixation_time) while (timer_fixation.getTime() > 0 and break_flag == True): fixation.draw() win.flip() # Update screen break_flag = escapeCondition() return break_flag ## Display just a message def displayInstruction(win, string_instruction, sound, string_time=2, break_flag=True): timer_string = core.CountdownTimer(string_time) sound.play() while (timer_string.getTime() > 0 and break_flag == True): subject_instructions.text = string_instruction subject_instructions.draw() win.flip() # Update screen break_flag = escapeCondition() return break_flag ## Initialise experiment: select trails and log them block_order = np.random.permutation([tennis, house, faces] * blocks_number) logging.data("Trails order:") logging.data(block_order) ############## Exp. begin ############## # Display first set of instructions and wait message1 = visual.TextStim(win, pos=[0, 0], text=init_mess_1, alignVert='center', wrapWidth=1.5) message1.size = .5 message1.draw() win.flip() event.waitKeys() #pause until there's a keypress # Waiting for the scanner if SCANNER: message3 = visual.TextStim(win, pos=[0, 0.25], text=scanner_message, alignVert='center', wrapWidth=1.5) message3.size = .5 message3.draw() win.flip() while 1: allKeys = event.getKeys() if MR_settings['sync'] in allKeys: break # Start run experiment_begin = dt.now() inizio = globalClock.getTime() logging.data('Begin of the experiment (trigger) at: %.6f' % (inizio)) # Run experiment a 'run' at the time for i_block in block_order: i_block_string = i_block[0] i_block_sound = i_block[1] logging.data('*** Run: ' + str(i_block_string) + ' ***') # Fixation if displayFixation(win, fixation_time=inter_blocks_length) == False: break # Show condition "tennis" or "house" if displayInstruction(win, string_instruction=i_block_string, string_time=block_length, sound=i_block_sound) == False: break # Display final fixation if displayFixation(win, fixation_time=inter_blocks_length) == False: return # Display final message message4 = visual.TextStim(win, pos=[0, 0.25], text=final_message, alignVert='center', wrapWidth=1.5) message4.size = .5 message4.draw() win.flip() core.wait(3) logging.data('***** End *****\n') logging.data('Total time spent: %s' % (dt.now() - experiment_begin)) logging.data('Every frame duration saved in %s' % (path_out + Frames_durations_name)) return
#create a window to draw in myWin =visual.Window((600,600), allowGUI=False, bitsMode=None, units='norm', winType='pyglet') #INITIALISE SOME STIMULI dotPatch =visual.DotStim(myWin, rgb=(1.0,1.0,1.0), dir=270, nDots=100, fieldShape='circle', fieldPos=(0.0,0.0),fieldSize=1, dotLife=5, #number of frames for each dot to be drawn signalDots='same', #are the signal and noise dots 'different' or 'same' popns (see Scase et al) noiseDots='direction', #do the noise dots follow random- 'walk', 'direction', or 'position' speed=0.01, coherence=0.9) message =visual.TextStim(myWin,text='Hit Q to quit', pos=(0,-0.5)) trialClock =core.Clock() myWin.setRecordFrameIntervals() n=0 while True:#quits after 20 secs n+=1 dotPatch.draw() message.draw() myWin.flip()#redraw the buffer for n in range(10): logging.info('%i info' %n) #handle key presses each frame for key in event.getKeys(): if key in ['escape','q']: logging.data('final fps = %.3f' % myWin.fps()) myWin.close() core.quit() event.clearEvents()#keep the event buffer from overflowing
""" sentencecomp.py - code to run the sentence comprehension task for the reading remediation study """ from psychopy import visual, core, event, logging,gui import numpy as N import pickle import datetime import sys import os import inspect import hashlib from socket import gethostname from exptutils import * # study-specific routines def load_sentences(filename): f=open(filename) ll=f.readlines() f.close() s={} s['sentence']=[] s['cond']=[] s['onset']=[] for l in ll: l_s=l.split('\t') #print l_s s['sentence'].append(' '.join(l_s[2:]).strip('\n'))
i for i in range(joystick.numButtons) if joystick.newButtonState[i] and not joystick.oldButtonState[i] ] joystick.releasedButtons = [ i for i in range(joystick.numButtons) if not joystick.newButtonState[i] and joystick.oldButtonState[i] ] joystick.newPressedButtons = [ i for i in joystick.activeButtons if i in joystick.pressedButtons ] joystick.oldButtonState = joystick.newButtonState joystick.buttons = joystick.newPressedButtons [ logging.data( "joystick_{}_button: {}, pos=({:1.4f},{:1.4f})".format( joystick.device_number, i, joystick.getX(), joystick.getY())) for i in joystick.pressedButtons ] if len(joystick.buttons) > 0: # state changed to a new click # abort routine on response continueRoutine = False # check for quit (typically the Esc key) if endExpNow or keyboard.Keyboard().getKeys(keyList=["escape"]): core.quit() # check if all components have finished if not continueRoutine: # a component has requested a forced-end of Routine break continueRoutine = False # will revert to True if at least one component still running for thisComponent in trialComponents:
if t >= 0.0 and joystick.status == NOT_STARTED: # keep track of start time/frame for later joystick.tStart = t # not accounting for scr refresh joystick.frameNStart = frameN # exact frame index win.timeOnFlip(joystick, 'tStartRefresh') # time at next scr refresh joystick.status = STARTED joystick.joystickClock.reset() if joystick.status == STARTED: # only update if started and not finished! joystick.newButtonState = joystick.getAllButtons()[:] if joystick.newButtonState != joystick.oldButtonState: # New button press joystick.pressedButtons = [i for i in range(joystick.numButtons) if joystick.newButtonState[i] and not joystick.oldButtonState[i]] joystick.releasedButtons = [i for i in range(joystick.numButtons) if not joystick.newButtonState[i] and joystick.oldButtonState[i]] joystick.newPressedButtons = [i for i in joystick.activeButtons if i in joystick.pressedButtons] joystick.oldButtonState = joystick.newButtonState joystick.buttons = joystick.newPressedButtons [logging.data("joystick_{}_button: {}, pos=({:1.4f},{:1.4f})".format(joystick.device_number, i, joystick.getX(), joystick.getY())) for i in joystick.pressedButtons] if len(joystick.buttons) > 0: # state changed to a new click # abort routine on response continueRoutine = False # check for quit (typically the Esc key) if endExpNow or keyboard.Keyboard().getKeys(keyList=["escape"]): core.quit() # check if all components have finished if not continueRoutine: # a component has requested a forced-end of Routine break continueRoutine = False # will revert to True if at least one component still running for thisComponent in trialComponents: if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: continueRoutine = True
today_date, operator, subject_code, subject_age, subject_gender,\ SCANNER, Tr, Volumes, Skip, Sync = all_infos # Prepare out folder path_out = Dir_save + today_date + '_' + subject_code path_out = createOutFolder(path_out) # Set the log module to report warnings to the standard output window globalClock = core.Clock() logging.setDefaultClock(globalClock) logging.console.setLevel(logging.WARNING) lastLog = logging.LogFile(path_out + Log_name, level=logging.DATA, filemode='w', encoding='utf8') logging.data("------------- " + strftime("%Y-%m-%d %H:%M:%S", gmtime()) + " -------------") logging.data(pyschopy_prefs) logging.data("Saving in folder: " + path_out) logging.data("Operator: " + operator + "\n") logging.data("Subject. Code: " + subject_code + " - Age: " + str(subject_age) + " - Gender: " + subject_gender) logging.data("Scanner. TR: " + Tr + " - Volumes: " + Volumes + " - Skip: " + Skip + " - Sync: " + Sync + "\n") logging.data("Using %s (with %s driver) for sounds" % (sound.audioLib, sound.audioDriver) + '\n') logging.data('***** Starting *****') # Start window win = visual.Window(Screen_dimensions, monitor="mon", units="norm",
from __future__ import division from psychopy import logging, core, visual globalClock = core.Clock() # if this isn't provided the log times will reflect secs since python started logging.setDefaultClock(globalClock) logging.console.setLevel(logging.DEBUG) # receive nearly all messages logDat = logging.LogFile('logLastRun.log', filemode='w', # if you set this to 'a' it will append instead of overwriting level=logging.WARNING) # errors, data and warnings will be sent to this logfile # the following will go to any files with the appropriate minimum level set logging.info('Something fairly unimportant') logging.data('Something about our data. Data is likely very important!') logging.warning('Handy while building your experiment - highlights possible flaws in code/design') logging.error("You might have done something that PsychoPy can't handle! But hopefully this gives you some idea what.") # some things should be logged timestamped on the next video frame # For instance the time of a stimulus appearing is related to the flip: win = visual.Window([400, 400]) for n in range(5): win.logOnFlip('frame %i occured' %n, level=logging.EXP) if n in [2, 4]: win.logOnFlip('an even frame occured', level=logging.EXP) win.flip() # LogFiles can also simply receive direct input from the write() method # messages using write() will be sent immediately, and are often not # in correct chronological order with logged messages
button_resp.frameNStart = frameN # exact frame index win.timeOnFlip(button_resp, 'tStartRefresh') # time at next scr refresh button_resp.status = STARTED # joyButtons checking is just starting win.callOnFlip(button_resp.clock.reset) # t=0 on next screen flip if button_resp.status == STARTED: button_resp.newButtonState = button_resp.device.getAllButtons()[:] button_resp.pressedButtons = [] button_resp.releasedButtons = [] button_resp.newPressedButtons = [] if button_resp.newButtonState != button_resp.oldButtonState: button_resp.pressedButtons = [i for i in range(button_resp.numButtons) if button_resp.newButtonState[i] and not button_resp.oldButtonState[i]] button_resp.releasedButtons = [i for i in range(button_resp.numButtons) if not button_resp.newButtonState[i] and button_resp.oldButtonState[i]] button_resp.oldButtonState = button_resp.newButtonState button_resp.newPressedButtons = [i for i in [0, 1, 2, 3, 4] if i in button_resp.pressedButtons] [logging.data("joystick_{}_button: {}".format(button_resp.device_number,i)) for i in button_resp.pressedButtons] theseKeys = button_resp.newPressedButtons if len(theseKeys) > 0: # at least one key was pressed button_resp.keys = theseKeys[-1] # just the last key pressed button_resp.rt = button_resp.clock.getTime() # a response ends the routine continueRoutine = False # check for quit (typically the Esc key) if endExpNow or keyboard.Keyboard().getKeys(keyList=["escape"]): core.quit() # check if all components have finished if not continueRoutine: # a component has requested a forced-end of Routine break continueRoutine = False # will revert to True if at least one component still running
def waitKeys(maxWait=float('inf'), keyList=None, modifiers=False, timeStamped=False, clearEvents=True): """Same as `~psychopy.event.getKeys`, but halts everything (including drawing) while awaiting input from keyboard. :Parameters: maxWait : any numeric value. Maximum number of seconds period and which keys to wait for. Default is float('inf') which simply waits forever. keyList : **None** or [] Allows the user to specify a set of keys to check for. Only keypresses from this set of keys will be removed from the keyboard buffer. If the keyList is `None`, all keys will be checked and the key buffer will be cleared completely. NB, pygame doesn't return timestamps (they are always 0) modifiers : **False** or True If True will return a list of tuples instead of a list of keynames. Each tuple has (keyname, modifiers). The modifiers are a dict of keyboard modifier flags keyed by the modifier name (eg. 'shift', 'ctrl'). timeStamped : **False**, True, or `Clock` If True will return a list of tuples instead of a list of keynames. Each tuple has (keyname, time). If a `core.Clock` is given then the time will be relative to the `Clock`'s last reset. clearEvents : **True** or False Whether to clear the keyboard event buffer (and discard preceding keypresses) before starting to monitor for new keypresses. Returns None if times out. """ if clearEvents: # Only consider keypresses from here onwards. # We need to invoke clearEvents(), but our keyword argument is # also called clearEvents. We can work around this conflict by # accessing the global scope explicitly. globals()['clearEvents']('keyboard') # Check for keypresses until maxWait is exceeded # # NB pygame.event does have a wait() function that will # do this and maybe leave more cpu idle time? timer = psychopy.core.Clock() got_keypress = False while not got_keypress and timer.getTime() < maxWait: # Pump events on pyglet windows if they exist. if havePyglet: defDisplay = pyglet.window.get_platform().get_default_display() for win in defDisplay.get_windows(): win.dispatch_events() # Get keypresses and return if anything is pressed. keys = getKeys(keyList=keyList, modifiers=modifiers, timeStamped=timeStamped) if keys: got_keypress = True if got_keypress: return keys else: logging.data('No keypress (maxWait exceeded)') return None
def waitForResponse(self): trial = self.trial node = self.node target = self.keytarget trialCompleted = False trialError = False interkeyWaitTime = None nPrevCorrect = 0 while not trialCompleted: # Set the time to wait for a keypress # At most the trial time remaining, if we've pressed one key then # up to that amount maxWait = self.responseTimeLeft() if interkeyWaitTime: maxWait = min(interkeyWaitTime, maxWait) kbe = self.keyboard.waitForPresses(keys=keypress_map.keys(), maxWait=maxWait) keystate = self.keyboard.state.keys() exp_time = self.exp_timer.getTime() block_time = self.block_timer.getTime() timeLeft = self.responseTimeLeft() response = [int(x in keystate) for x in response_keys] nCorrect = sum([x and y for x, y in zip(response, target)]) nIncorrect = sum(response) - nCorrect responseIsCorrect = (response == target) rt = self.trial_time - timeLeft if responseIsCorrect: # Correct trialCompleted = True trialError = False elif (nIncorrect == 0) and (nCorrect > nPrevCorrect): # Pressed a new correct key nPrevCorrect = nCorrect if interkeyWaitTime is None: interkeyWaitTime = self.interkey_time elif timeLeft < 0 and not self.demo: # timed out on the trial trialCompleted = True trialError = True elif interkeyWaitTime and not kbe and not self.demo: # interkey timeout trialCompleted = True trialError = True elif (nIncorrect > 0): # incorrect response # wrong key trialCompleted = True trialError = True event_data = { 'nCorrect': nCorrect, 'nIncorrect': nIncorrect, 'timedOut': timeLeft < 0, 'node': node, 'target': target, 'response': response, # 'SOA': self.jitter[self.trial], 'trial': trial, 'blockTime': block_time, 'expTime': exp_time, 'trialTime': rt, 'error': trialError, 'completed': trialCompleted } self.data.append(event_data) logging.data(event_data) self.accuracy_record.append(not trialError) return trialError