Example #1
0
def compareXlsxFiles(pathToActual, pathToCorrect):
    from openpyxl.reader.excel import load_workbook

    # Make sure the file is there
    expBook = load_workbook(pathToCorrect)
    actBook = load_workbook(pathToActual)
    error = None

    for wsN, expWS in enumerate(expBook.worksheets):
        actWS = actBook.worksheets[wsN]
        for key, expVal in expWS._cells.items():
            actVal = actWS._cells[key].value
            expVal = expVal.value
            # determine whether there will be errors
            try:
                # convert to float if possible and compare with a reasonable
                # (default) precision
                expVal = float(expVal)
                isFloatable = True
            except:
                isFloatable = False
            if isFloatable and abs(expVal - float(actVal)) > 0.0001:
                error = "Cell %s: %f != %f" % (key, expVal, actVal)
                break
            elif not isFloatable and expVal != actVal:
                error = "Cell %s: %s != %s" % (key, expVal, actVal)
                break
    if error:
        pathToLocal, ext = os.path.splitext(pathToCorrect)
        pathToLocal = pathToLocal + "_local" + ext
        shutil.copyfile(pathToActual, pathToLocal)
        logging.warning("xlsxActual!=xlsxCorr: Saving local copy to %s" % pathToLocal)
        raise IOError, error
Example #2
0
def _handleFileCollision(fileName, fileCollisionMethod):
    """ Handle filename collisions by overwriting, renaming, or failing hard.

    :Parameters:

        fileCollisionMethod: 'overwrite', 'rename', 'fail'
            If a file with the requested name already exists, specify how to deal with it. 'overwrite' will overwite existing files in place, 'rename' will append an integer to create a new file ('trials1.psydat', 'trials2.pysdat' etc) and 'error' will raise an IOError.
    """
    if fileCollisionMethod == 'overwrite':
        logging.warning('Data file, %s, will be overwritten' % fileName)
    elif fileCollisionMethod == 'fail':
        raise IOError("Data file %s already exists. Set argument fileCollisionMethod to overwrite." % fileName)
    elif fileCollisionMethod == 'rename':
        rootName, extension = os.path.splitext(fileName)
        matchingFiles = glob.glob("%s*%s" % (rootName, extension))
        count = len(matchingFiles)

        fileName = "%s_%d%s" % (rootName, count, extension) # Build the renamed string.

        if os.path.exists(fileName): # Check to make sure the new fileName hasn't been taken too.
            raise IOError("New fileName %s has already been taken. Something is wrong with the append counter." % fileName)

    else:
        raise ValueError("Argument fileCollisionMethod was invalid: %s" % str(fileCollisionMethod))

    return fileName
Example #3
0
def rgb2dklCart(picture, conversionMatrix=None):
    """Convert an RGB image into Cartesian DKL space"""
    #Turn the picture into an array so we can do maths
    picture=numpy.array(picture)
    #Find the original dimensions of the picture
    origShape = picture.shape

    #this is the inversion of the dkl2rgb conversion matrix
    if conversionMatrix==None:
        conversionMatrix = numpy.asarray([\
            #LUMIN->%L-M->L+M-S
            [ 0.25145542,  0.64933633,  0.09920825],
            [ 0.78737943, -0.55586618, -0.23151325],
            [ 0.26562825,  0.63933074, -0.90495899]])
        logging.warning('This monitor has not been color-calibrated. Using default DKL conversion matrix.')
    else:
        conversionMatrix = numpy.linalg.inv(conversionMatrix)

    #Reshape the picture so that it can multiplied by the conversion matrix
    red = picture[:,:,0]
    green = picture[:,:,1]
    blue = picture[:,:,2]

    dkl = numpy.asarray([red.reshape([-1]), green.reshape([-1]), blue.reshape([-1])])

    #Multiply the picture by the conversion matrix
    dkl=numpy.dot(conversionMatrix, dkl)

    #Reshape the picture so that it's back to it's original shape
    dklPicture = numpy.reshape(numpy.transpose(dkl), origShape)
    return dklPicture
Example #4
0
 def onResize(self, width, height):
     """A method that will be called if the window detects a resize event
     """
     logging.warning("dispatchEvents() method in {} was called "
                     "but is not implemented. Is it needed?"
                     .format(self.win.winType)
                     )
Example #5
0
def lms2rgb(lms_Nx3, conversionMatrix=None):
    """Convert from cone space (Long, Medium, Short) to RGB.

    Requires a conversion matrix, which will be generated from generic
    Sony Trinitron phosphors if not supplied (note that you will not get
    an accurate representation of the color space unless you supply a
    conversion matrix)

    usage::

        rgb_Nx3 = lms2rgb(dkl_Nx3(el,az,radius), conversionMatrix)

    """

    lms_3xN = numpy.transpose(lms_Nx3)#its easier to use in the other orientation!

    if conversionMatrix==None:
        cones_to_rgb = numpy.asarray([ \
            #L        M        S
            [ 4.97068857, -4.14354132, 0.17285275],#R
            [-0.90913894, 2.15671326, -0.24757432],#G
            [-0.03976551, -0.14253782, 1.18230333]#B
            ])
        logging.warning('This monitor has not been color-calibrated. Using default LMS conversion matrix.')
    else: cones_to_rgb=conversionMatrix

    rgb_to_cones = numpy.linalg.pinv(cones_to_rgb)#get inverse
    rgb = numpy.dot(cones_to_rgb, lms_3xN)
    return numpy.transpose(rgb)#return in the shape we received it
Example #6
0
 def _getNextFrame(self):
     """get next frame info ( do not decode frame yet)
     """
     while self.status == PLAYING:
         if self._video_stream.grab():
             self._prev_frame_index = self._next_frame_index
             self._prev_frame_sec = self._next_frame_sec
             self._next_frame_index = self._video_stream.get(
                 cv2.CAP_PROP_POS_FRAMES)
             self._next_frame_sec = self._video_stream.get(
                 cv2.CAP_PROP_POS_MSEC)/1000.0
             self._video_perc_done = self._video_stream.get(
                 cv2.CAP_PROP_POS_AVI_RATIO)
             self._next_frame_displayed = False
             halfInterval = self._inter_frame_interval/2.0
             if self.getTimeToNextFrameDraw() > -halfInterval:
                 return self._next_frame_sec
             else:
                 self.nDroppedFrames += 1
                 if self.nDroppedFrames < reportNDroppedFrames:
                     msg = "MovieStim2 dropping video frame index: %d"
                     logging.warning(msg % self._next_frame_index)
                 elif self.nDroppedFrames == reportNDroppedFrames:
                     msg = ("Multiple Movie frames have occurred - "
                            "I'll stop bothering you about them!")
                     logging.warning(msg)
         else:
             self._onEos()
             break
Example #7
0
    def __init__(self,
                    win,
                    contrast=1.0,
                    gamma=None,
                    nEntries=256,
                    mode='bits++',
                    rampType = 'configFile'):
        self.win = win
        self.contrast=contrast
        self.nEntries=nEntries
        self.mode = mode
        self.method = 'fast' #used to allow setting via USB which was 'slow'
        self.gammaCorrect = 'software' #Bits++ doesn't do its own correction so we need to

        #import pyglet.GL late so that we can import bits.py without it initially
        global GL, visual
        from psychopy import visual
        import pyglet.gl as GL

        if self.gammaCorrect=='software':
            if gamma is None:
                self.gamma = win.gamma #inherit from window
            elif len(gamma)>2: # [Lum,R,G,B] or [R,G,B]
                self.gamma=gamma[-3:]
            else:
                self.gamma = [gamma, gamma, gamma]
        if init():
            setVideoMode(NOGAMMACORRECT|VIDEOENCODEDCOMMS)
            self.initialised=True
            logging.debug('found and initialised bits++')
        else:
            self.initialised=False
            logging.warning("couldn't initialise bits++")

        #do the processing
        self._HEADandLUT = np.zeros((524,1,3),np.uint8)
        self._HEADandLUT[:12,:,0] = np.asarray([ 36, 63, 8, 211, 3, 112, 56, 34,0,0,0,0]).reshape([12,1])#R
        self._HEADandLUT[:12,:,1] = np.asarray([ 106, 136, 19, 25, 115, 68, 41, 159,0,0,0,0]).reshape([12,1])#G
        self._HEADandLUT[:12,:,2] = np.asarray([ 133, 163, 138, 46, 164, 9, 49, 208,0,0,0,0]).reshape([12,1])#B
        self.LUT=np.zeros((256,3),'d')        #just a place holder
        self.setLUT()#this will set self.LUT and update self._LUTandHEAD
        self._setupShaders()
        #replace window methods with our custom ones
        self.win._prepareFBOrender = self._prepareFBOrender
        self.win._finishFBOrender = self._finishFBOrender
        self.win._afterFBOrender = self._afterFBOrender
        #set gamma of the window to the identity LUT
        if rampType == 'configFile':
            #now check that we have a valid configuration of the box
            self.config = Config(self)
            #check that this matches the prev config for our graphics card etc
            ok=False #until we find otherwise
            ok = self.config.quickCheck()
            if ok:
                self.win.gammaRamp = self.config.identityLUT
            else:
                rampType = None
        if not rampType == 'configFile': #'this must NOT be an `else` from the above `if` because can be overidden
            #possibly we were given a numerical rampType (as in the :func:`psychopy.gamma.setGamma()`)
            self.win.winHandle.setGamma(self.win.winHandle, rampType=rampType)
Example #8
0
    def __init__(self, win=None, portName=None, mode=''):

        serialdevice.SerialDevice.__init__(self, port=portName, baudrate=19200,
                 byteSize=8, stopBits=1,
                 parity="N", #'N'one, 'E'ven, 'O'dd, 'M'ask,
                 eol='\n',
                 maxAttempts=1, pauseDuration=0.1,
                 checkAwake=True)
        if not self.OK:
            return
        #we have a confirmed connection. Now check details about device and system
        if not hasattr(self, 'info'):
            self.info = self.getInfo()
        self.config = None
        self.mode = mode
        self.win = win
        if self.win is not None:
            if not hasattr(self.win, '_prepareFBOrender'):
                logging.error("BitsSharp was given an object as win argument but this is not a visual.Window")
            self.win._prepareFBOrender = self._prepareFBOrender
            self.win._finishFBOrender = self._finishFBOrender
            self._setupShaders()
            #now check that we have a valid configuration of the box
            self.checkConfig(level=0)
        else:
            self.config = None # makes no sense if we have a window?
            logging.warning("%s was not given any PsychoPy win" %(self))
Example #9
0
    def __init__(self,
                    win,
                    contrast=1.0,
                    gamma=[1.0,1.0,1.0],
                    nEntries=256,
                    mode='bits++',):
        self.win = win
        self.contrast=contrast
        self.nEntries=nEntries
        self.mode = mode
        self.method = 'fast' #used to allow setting via USB which was 'slow'

        if len(gamma)>2: # [Lum,R,G,B] or [R,G,B]
            self.gamma=gamma[-3:]
        else:
            self.gamma = [gamma, gamma, gamma]

        if init():
            setVideoMode(NOGAMMACORRECT|VIDEOENCODEDCOMMS)
            self.initialised=True
            logging.debug('found and initialised bits++')
        else:
            self.initialised=False
            logging.warning("couldn't initialise bits++")

        #do the processing
        self._HEADandLUT = np.zeros((524,1,3),np.uint8)
        self._HEADandLUT[:12,:,0] = np.asarray([ 36, 63, 8, 211, 3, 112, 56, 34,0,0,0,0]).reshape([12,1])#R
        self._HEADandLUT[:12,:,1] = np.asarray([ 106, 136, 19, 25, 115, 68, 41, 159,0,0,0,0]).reshape([12,1])#G
        self._HEADandLUT[:12,:,2] = np.asarray([ 133, 163, 138, 46, 164, 9, 49, 208,0,0,0,0]).reshape([12,1])#B
        self.LUT=np.zeros((256,3),'d')        #just a place holder
        self.setLUT()#this will set self.LUT and update self._LUTandHEAD
        self._setupShaders()
Example #10
0
    def push(self, infoStream=None):
        """Push to remote from local copy of the repository

        Parameters
        ----------
        infoStream

        Returns
        -------
            1 if successful
            -1 if project deleted on remote
        """
        if infoStream:
            infoStream.write("\nPushing changes from remote...")
        try:
            info = self.repo.git.push(self.remoteWithToken, 'master')
            infoStream.write("\n{}".format(info))
        except git.exc.GitCommandError as e:
            if ("The project you were looking for could not be found" in
                    traceback.format_exc()):
                    # pointing to a project at pavlovia but it doesn't exist
                    logging.warning("Project not found on gitlab.pavlovia.org")
                    return MISSING_REMOTE
            else:
                raise e

        logging.debug('push complete: {}'.format(self.remoteHTTPS))
        if infoStream:
            infoStream.write("done")
        return 1
Example #11
0
    def calibrateZero(self):
        """Perform a calibration to zero light.

        For early versions of the ColorCAL this had to be called after
        connecting to the device. For later versions the dark calibration
        was performed at the factory and stored in non-volatile memory.

        You can check if you need to run a calibration with::

            ColorCAL.getNeedsCalibrateZero()
        """
        val = self.sendMessage(b"UZC", timeout=1.0)
        if val == 'OK00':
            pass
        elif val == 'ER11':
            logging.error(
                "Could not calibrate ColorCAL2. Is it properly covered?")
            return False
        else:  # unlikely
            logging.warning(
                "Received surprising result from ColorCAL2: %s" % val)
            return False
        # then take a measurement to see if we are close to zero lum (ie is it
        # covered?)
        self.ok, x, y, z = self.measure()
        if y > 3:
            logging.error('There seems to be some light getting to the '
                          'detector. It should be well-covered for zero '
                          'calibration')
            return False
        self._zeroCalibrated = True
        self.calibMatrix = self.getCalibMatrix()
        return True
Example #12
0
    def _setupFrameBuffer(self):
        # Setup framebuffer
        self.frameBuffer = FB.glGenFramebuffersEXT(1)

        FB.glBindFramebufferEXT(FB.GL_FRAMEBUFFER_EXT, self.frameBuffer)
        # Setup depthbuffer
        self.depthBuffer = FB.glGenRenderbuffersEXT(1)
        FB.glBindRenderbufferEXT (FB.GL_RENDERBUFFER_EXT,self.depthBuffer)
        FB.glRenderbufferStorageEXT (FB.GL_RENDERBUFFER_EXT, GL.GL_DEPTH_COMPONENT, int(self.size[0]), int(self.size[1]))

        # Create texture to render to
        self.frameTexture = c_uint(0)
        GL.glGenTextures (1, self.frameTexture)
        GL.glBindTexture (GL.GL_TEXTURE_2D, self.frameTexture)
        GL.glTexParameteri (GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR)
        GL.glTexParameteri (GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR)
        GL.glTexImage2D (GL.GL_TEXTURE_2D, 0, GL.GL_RGBA32F_ARB, int(self.size[0]), int(self.size[1]), 0,
                         GL.GL_RGBA, GL.GL_FLOAT, None)

        #attach texture to the frame buffer
        FB.glFramebufferTexture2DEXT (FB.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT,
                                      GL.GL_TEXTURE_2D, self.frameTexture, 0)
        FB.glFramebufferRenderbufferEXT(FB.GL_FRAMEBUFFER_EXT, GL.GL_DEPTH_ATTACHMENT_EXT,
                                        FB.GL_RENDERBUFFER_EXT, self.depthBuffer)

        status = FB.glCheckFramebufferStatusEXT (FB.GL_FRAMEBUFFER_EXT)
        if status != FB.GL_FRAMEBUFFER_COMPLETE_EXT:
            logging.warning("Error in framebuffer activation")
            return
        GL.glDisable(GL.GL_TEXTURE_2D)
Example #13
0
 def pavlovia(self, proj):
     global knownProjects
     self.__dict__['pavlovia'] = proj
     if not hasattr(proj, 'attributes'):
         return
     thisID = proj.attributes['path_with_namespace']
     if thisID in knownProjects \
             and os.path.exists(knownProjects[thisID]['localRoot']):
         rememberedProj = knownProjects[thisID]
         if rememberedProj['idNumber'] != proj.attributes['id']:
             logging.warning("Project {} has changed gitlab ID since last "
                             "use (was {} now {})"
                             .format(thisID,
                                     rememberedProj['idNumber'],
                                     proj.attributes['id']))
         self.update(rememberedProj)
     elif 'localRoot' in self:
         # this means the local root was set before the remote was known
         self['id'] = proj.attributes['path_with_namespace']
         self['idNumber'] = proj.attributes['id']
         knownProjects[self['id']] = self
     else:
         self['localRoot'] = ''
         self['id'] = proj.attributes['path_with_namespace']
         self['idNumber'] = proj.attributes['id']
     self['remoteSSH'] = proj.ssh_url_to_repo
     self['remoteHTTPS'] = proj.http_url_to_repo
Example #14
0
    def setMarker(self, tone=19000, secs=0.015, volume=0.03, log=True):
        """Sets the onset marker, where `tone` is either in hz or a custom sound.

        The default tone (19000 Hz) is recommended for auto-detection, as being
        easier to isolate from speech sounds (and so reliable to detect). The default duration
        and volume are appropriate for a quiet setting such as a lab testing
        room. A louder volume, longer duration, or both may give better results
        when recording loud sounds or in noisy environments, and will be
        auto-detected just fine (even more easily). If the hardware microphone
        in use is not physically near the speaker hardware, a louder volume is
        likely to be required.

        Custom sounds cannot be auto-detected, but are supported anyway for
        presentation purposes. E.g., a recording of someone saying "go" or
        "stop" could be passed as the onset marker.
        """
        if hasattr(tone, "play"):
            self.marker_hz = 0
            self.marker = tone
            if log and self.autoLog:
                logging.exp("custom sound set as marker; getMarkerOnset() will not be able to auto-detect onset")
        else:
            self.marker_hz = float(tone)
            sampleRate = sound.pyoSndServer.getSamplingRate()
            if sampleRate < 2 * self.marker_hz:
                # NyquistError
                logging.warning(
                    "Recording rate (%i Hz) too slow for %i Hz-based marker detection."
                    % (int(sampleRate), self.marker_hz)
                )
            if log and self.autoLog:
                logging.exp("frequency of recording onset marker: %.1f" % self.marker_hz)
            self.marker = sound.Sound(self.marker_hz, secs, volume=volume, name=self.name + ".marker_tone")
Example #15
0
 def __init__(self, name='', autoLog=True):
     self.name = name
     self.status = NOT_STARTED
     self.autoLog = autoLog
     if self.autoLog:
         logging.warning("%s is calling MinimalStim.__init__() with autolog=True. Set autoLog to True only at the end of __init__())" \
                         %(self.__class__.__name__))
Example #16
0
    def __init__(self,
                    win,
                    contrast=1.0,
                    gamma=[1.0,1.0,1.0],
                    nEntries=256,
                    mode='bits++',):
        self.win = win
        self.contrast=contrast
        self.nEntries=nEntries
        #set standardised name for mode
        if mode in ['bits','bits++']:
            self.mode = 'bits++'
        elif mode in ['color','color++','colour','colour++']:
            self.mode = 'color++'
        elif mode in ['mono','mono++']:
            self.mode = 'mono++'
        else:
            logging.error("Unknown mode '%s' for BitsBox" %mode)

        if len(gamma)>2: # [Lum,R,G,B] or [R,G,B]
            self.gamma=gamma[-3:]
        else:
            self.gamma = [gamma, gamma, gamma]

        if init():
            setVideoMode(NOGAMMACORRECT|VIDEOENCODEDCOMMS)
            self.initialised=True
            logging.debug('found and initialised bits++')
        else:
            self.initialised=False
            logging.warning("couldn't initialise bits++")

        if self.mode == 'bits++':
            #do the processing
            self._HEADandLUT = numpy.zeros((524,1,3),numpy.uint8)
            self._HEADandLUT[:12,:,0] = numpy.asarray([ 36, 63, 8, 211, 3, 112, 56, 34,0,0,0,0]).reshape([12,1])#R
            self._HEADandLUT[:12,:,1] = numpy.asarray([ 106, 136, 19, 25, 115, 68, 41, 159,0,0,0,0]).reshape([12,1])#G
            self._HEADandLUT[:12,:,2] = numpy.asarray([ 133, 163, 138, 46, 164, 9, 49, 208,0,0,0,0]).reshape([12,1])#B
            self.LUT=numpy.zeros((256,3),'d')#just a place holder
            self.setLUT()#this will set self.LUT and update self._LUTandHEAD
        elif haveShaders:
            self.monoModeShader = shaders.compileProgram(fragment=shaders.bitsMonoModeFrag,
                                   attachments=[shaders.gammaCorrectionFrag])
            self.colorModeShader =shaders.compileProgram(fragment=shaders.bitsColorModeFrag,
                                   attachments=[shaders.gammaCorrectionFrag])
            GL.glUseProgram(self.colorModeShader)
            prog = self.colorModeShader
            GL.glUniform1f(GL.glGetUniformLocation(prog, 'sampleSpacing'), 1.0)
            #Set default encoding gamma for power-law shader to (1.0, 1.0, 1.0):
            GL.glUniform3f(GL.glGetUniformLocation(prog, 'ICMEncodingGamma'), 1.0, 1.0, 1.0)
            # Default min and max luminance is 0.0 to 1.0, therefore reciprocal 1/range is also 1.0:
            GL.glUniform3f(GL.glGetUniformLocation(prog, 'ICMMinInLuminance'), 0.0, 0.0, 0.0)
            GL.glUniform3f(GL.glGetUniformLocation(prog, 'ICMMaxInLuminance'), 1.0, 1.0, 1.0)
            GL.glUniform3f(GL.glGetUniformLocation(prog, 'ICMReciprocalLuminanceRange'), 1.0, 1.0, 1.0)
            # Default gain to postmultiply is 1.0:
            GL.glUniform3f(GL.glGetUniformLocation(prog, 'ICMOutputGain'), 1.0, 1.0, 1.0)
            # Default bias to is 0.0:
            GL.glUniform3f(GL.glGetUniformLocation(prog, 'ICMOutputBias'), 0.0, 0.0, 0.0)
            GL.glUniform2f(GL.glGetUniformLocation(prog, 'ICMClampToColorRange'), 0.0, 1.0)
            GL.glUseProgram(0)
Example #17
0
def setPortAddress(address=0x0378):
    """Set the memory address or device node for your parallel port
    of your parallel port, to be used in subsequent commands

    common port addresses::

        LPT1 = 0x0378 or 0x03BC
        LPT2 = 0x0278 or 0x0378
        LPT3 = 0x0278

    or for Linux::
        /dev/parport0

    This routine will attempt to find a usable driver depending
    on your platform
    """

    global PORT
    # convert u"0x0378" into 0x0378
    if isinstance(address, basestring) and address.startswith('0x'):
        address = int(address, 16)

    # This is useful with the Linux-based driver where deleting
    # the port object ensures that we're not longer holding the
    # device node open and that we won't error if we end up
    # re-opening it
    if PORT is not None:
        del PORT

    try:
        PORT = ParallelPort(address=address)
    except Exception as exp:
        logging.warning('Could not initiate port: %s' % str(exp))
        PORT = None
Example #18
0
def openOutputFile(fileName=None, append=False, fileCollisionMethod='rename',
                   encoding='utf-8-sig'):
    """Open an output file (or standard output) for writing.

    :Parameters:

    fileName : None, 'stdout', or str
        The desired output file name. If `None` or `stdout`, return
        `sys.stdout`. Any other string will be considered a filename.
    append : bool, optional
        If ``True``, append data to an existing file; otherwise, overwrite
        it with new data.
        Defaults to ``True``, i.e. appending.
    fileCollisionMethod : string, optional
        How to handle filename collisions. Valid values are `'rename'`,
        `'overwrite'`, and `'fail'`.
        This parameter is ignored if ``append``  is set to ``True``.
        Defaults to `rename`.
    encoding : string, optional
        The encoding to use when writing the file. This parameter will be
        ignored if `append` is `False` and `fileName` ends with `.psydat`
        or `.npy` (i.e. if a binary file is to be written).
        Defaults to ``'utf-8'``.

    :Returns:

    f : file
        A writable file handle.

    """
    fileName = pathToString(fileName)
    if (fileName is None) or (fileName == 'stdout'):
        return sys.stdout

    if append:
        mode = 'a'
    else:
        if fileName.endswith(('.psydat', '.npy')):
            mode = 'wb'
        else:
            mode = 'w'

        # Rename the output file if a file of that name already exists
        # and it should not be appended.
        if os.path.exists(fileName) and not append:
            fileName = handleFileCollision(
                fileName,
                fileCollisionMethod=fileCollisionMethod)

    # Do not use encoding when writing a binary file.
    if 'b' in mode:
        encoding = None

    if os.path.exists(fileName) and mode in ['w', 'wb']:
        logging.warning('Data file %s will be overwritten!' % fileName)

    # The file wil always be opened in binary writing mode,
    # see https://docs.python.org/2/library/codecs.html#codecs.open
    f = codecs.open(fileName, mode=mode, encoding=encoding)
    return f
Example #19
0
def rush(value=True):    
    """Raise the priority of the current thread/process using 
        - sched_setscheduler
    
    NB for rush() to work on (debian-based?) linux requires that the script is run using a copy of python that
    is allowed to change priority, eg: sudo setcap cap_sys_nice=eip <sys.executable>, and maybe restart PsychoPy.
    If <sys.executable> is the system python, its important to restore it back to normal to avoid possible 
    side-effects. Alternatively, use a different python executable, and change its cap_sys_nice.
    
    For RedHat-based systems, 'sudo chrt ...' at run-time might be needed instead, not sure.
    see http://rt.et.redhat.com/wiki/images/8/8e/Rtprio.pdf
    """
    if importCtypesFailed: return False
    
    if value:#set to RR with max priority
        schedParams = _SchedParams()
        schedParams.sched_priority = c.sched_get_priority_max(SCHED_RR)
        err = c.sched_setscheduler(0,SCHED_RR, ctypes.byref(schedParams))
        if err==-1:#returns 0 if OK
            logging.warning("""Failed to raise thread priority with sched_setscheduler.
To enable rush(), if you are using a debian-based linux, try this in a terminal window:
  'sudo setcap cap_sys_nice=eip %s'  [NB: You may need to install 'setcap' first.]
If you are using the system's python (eg /usr/bin/python2.x), its highly recommended
to change cap_sys_nice back to normal afterwards:
  'sudo setcap cap_sys_nice= %s'""" % (sys.executable,sys.executable))
    else:#set to RR with normal priority
        schedParams = _SchedParams()
        schedParams.sched_priority = c.sched_get_priority_min(SCHED_NORMAL)
        err = c.sched_setscheduler(0,SCHED_NORMAL, ctypes.byref(schedParams))
        if err==-1:#returns 0 if OK
            logging.warning("""Failed to set thread priority back to normal level with sched_setscheduler.
Try:  'sudo setcap cap_sys_nice= %s'""" % (sys.executable))
    
    return True
Example #20
0
def compareScreenshot(fileName, win, crit=5.0):
    """Compare the current back buffer of the given window with the file

    Screenshots are stored and compared against the files under path
    kept in TESTS_DATA_PATH.  Thus specify relative path to that
    directory
    """
    #if we start this from a folder below run.py the data folder won't be found
    fileName = pjoin(TESTS_DATA_PATH, fileName)
    #get the frame from the window
    win.getMovieFrame(buffer='back')
    frame=win.movieFrames[-1]
    win.movieFrames=[]
    #if the file exists run a test, if not save the file
    if not isfile(fileName):
        frame.save(fileName, optimize=1)
        skip("Created %s" % basename(fileName))
    else:
        expected = Image.open(fileName)
        expDat = np.array(expected.getdata())
        imgDat = np.array(frame.getdata())
        rms = (((imgDat-expDat)**2).sum()/len(imgDat))**0.5
        filenameLocal = fileName.replace('.png','_local.png')
        if rms >= crit/2:
            #there was SOME discrepency
            logging.warning('PsychoPyTests: RMS=%.3g at threshold=%3.g'
                  % (rms, crit))
        if not rms<crit: #don't do `if rms>=crit because that doesn't catch rms=nan
            frame.save(filenameLocal, optimize=1)
            logging.warning('PsychoPyTests: Saving local copy into %s' % filenameLocal)
        assert rms<crit, \
            "RMS=%.3g at threshold=%.3g. Local copy in %s" % (rms, crit, filenameLocal)
Example #21
0
 def _getCtrlValue(self, ctrl):
     """Retrieve the current value from the control (whatever type of ctrl
     it is, e.g. checkbox.GetValue, textctrl.GetStringSelection
     Different types of control have different methods for retrieving the
     value.  This function checks them all and returns the value or None.
     """
     if ctrl is None:
         return None
     elif hasattr(ctrl, '_choices'):  # for wx.Choice
         if self.name == 'audioDevice':
             # convert the option back to a list with preferred at top
             val = ctrl._choices
             preferred = ctrl._choices.pop(ctrl.GetSelection())
             val.insert(0, preferred)
             return val
         else:
             return ctrl._choices[ctrl.GetSelection()]
     elif hasattr(ctrl, 'GetValue'):  # e.g. TextCtrl
         return ctrl.GetValue()
     elif hasattr(ctrl, 'GetLabel'):  # for wx.StaticText
         return ctrl.GetLabel()
     else:
         msg = "failed to retrieve the value for pref: %s"
         logging.warning(msg % ctrl.valueCtrl)
         return None
Example #22
0
 def OnDropFiles(self, x, y, filenames):
     logging.debug('PsychoPyBuilder: received dropped files: %s' % filenames)
     for filename in filenames:
         if filename.endswith('.psyexp') or filename.lower().endswith('.py'):
             self.builder.fileOpen(filename=filename)
         else:
             logging.warning('dropped file ignored: did not end in .psyexp or .py')
Example #23
0
    def __init__(self,
                 port=None,
                 sendBreak=False,
                 smoothing=False,
                 bufferSize=262144):
        # if we're trying to send the break signal then presumably the device
        # is sleeping
        if sendBreak:
            checkAwake = False
        else:
            checkAwake = True
        # run initialisation; parity = enable parity checking
        super(BlackBoxToolkit, self).__init__(port,
                                              baudrate=230400, eol="\r\n",
                                              parity='N',
                                              pauseDuration=1.0,  # 1 second pause!! slow device
                                              checkAwake=checkAwake)
        if sendBreak:
            self.sendBreak()
            time.sleep(3.0)  # give time to reset

        if smoothing == False:
            # For use with CRT monitors which require smoothing. LCD monitors do not.
            # Remove smoothing for optos, but keep mic smoothing - refer to BBTK handbook re: mic smoothing latency
            # Important to remove smoothing for optos, as smoothing adds 20ms delay to timing.
            logging.info("Opto sensor smoothing removed.  Mic1 and Mic2 smoothing still active.")
            self.setSmoothing('11000000')
            self.pause()

        try: # set buffer size - can make proportional to size of data (32 bytes per line * events)+1000
            self.com.set_buffer_size(bufferSize)
        except Exception:
            logging.warning("Could not set buffer size. The default buffer size for Windows is 4096 bytes.")
Example #24
0
def rgb2lms(rgb_Nx3, conversionMatrix=None):
    """Convert from RGB to cone space (LMS).

    Requires a conversion matrix, which will be generated from generic
    Sony Trinitron phosphors if not supplied (note that you will not get
    an accurate representation of the color space unless you supply a
    conversion matrix)

    usage::

        lms_Nx3 = rgb2lms(rgb_Nx3(el,az,radius), conversionMatrix)

    """

    # its easier to use in the other orientation!
    rgb_3xN = numpy.transpose(rgb_Nx3)

    if conversionMatrix is None:
        cones_to_rgb = numpy.asarray([
            # L        M        S
            [4.97068857, -4.14354132, 0.17285275],  # R
            [-0.90913894, 2.15671326, -0.24757432],  # G
            [-0.03976551, -0.14253782, 1.18230333]])  # B

        logging.warning('This monitor has not been color-calibrated. '
                        'Using default LMS conversion matrix.')
    else:
        cones_to_rgb = conversionMatrix
    rgb_to_cones = numpy.linalg.inv(cones_to_rgb)

    lms = numpy.dot(rgb_to_cones, rgb_3xN)
    return numpy.transpose(lms)  # return in the shape we received it
Example #25
0
 def _getNextFrame(self):
     # get next frame info ( do not decode frame yet)
     while self.status == PLAYING:
         if self._video_stream.grab():
             self._prev_frame_index = self._next_frame_index
             self._prev_frame_sec = self._next_frame_sec
             self._next_frame_index = self._video_stream.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
             if self._requested_fps and self._no_audio:
                 self._next_frame_sec = self._next_frame_index/self._requested_fps#*self._video_stream.get(cv2.cv.CV_CAP_PROP_POS_MSEC)/1000.0
             else:
                 self._next_frame_sec = self._video_stream.get(cv2.cv.CV_CAP_PROP_POS_MSEC)/1000.0
             self._video_perc_done = self._video_stream.get(cv2.cv.CV_CAP_PROP_POS_AVI_RATIO)
             self._next_frame_displayed = False
             if self.getTimeToNextFrameDraw() > -self._inter_frame_interval/2.0:
                 return self._next_frame_sec
             else:
                 self.nDroppedFrames += 1
                 if self.nDroppedFrames < reportNDroppedFrames:
                     logging.warning("MovieStim2 dropping video frame index: %d"%(self._next_frame_index))
                 elif self.nDroppedFrames == reportNDroppedFrames:
                     logging.warning("Multiple Movie frames have "
                                     "occurred - I'll stop bothering you "
                                     "about them!")
         else:
             self._onEos()
             break
Example #26
0
def sendUsageStats(app=None):
    """Sends anonymous, very basic usage stats to psychopy server:
      the version of PsychoPy
      the system used (platform and version)
      the date
    """

    v = psychopy.__version__
    dateNow = time.strftime("%Y-%m-%d_%H:%M")
    miscInfo = ''

    # get platform-specific info
    if sys.platform == 'darwin':
        OSXver, junk, architecture = platform.mac_ver()
        systemInfo = "OSX_%s_%s" % (OSXver, architecture)
    elif sys.platform.startswith('linux'):
        systemInfo = '%s_%s_%s' % (
            'Linux',
            ':'.join([x for x in platform.dist() if x != '']),
            platform.release())
        if len(systemInfo) > 30:  # if it's too long PHP/SQL fails to store!?
            systemInfo = systemInfo[0:30]
    elif sys.platform == 'win32':
        systemInfo = "win32_v" + platform.version()
    else:
        systemInfo = platform.system() + platform.release()
    u = "http://www.psychopy.org/usage.php?date=%s&sys=%s&version=%s&misc=%s"
    URL = u % (dateNow, systemInfo, v, miscInfo)
    try:
        page = requests.get(URL, proxies=web.proxies)  # proxies
    except Exception:
        logging.warning("Couldn't connect to psychopy.org\n"
                        "Check internet settings (and proxy "
                        "setting in PsychoPy Preferences.")
Example #27
0
    def push(self, syncPanel=None, progressHandler=None):
        """Push to remote from local copy of the repository

        Parameters
        ----------
        syncPanel
        progressHandler

        Returns
        -------
            1 if successful
            -1 if project deleted on remote
        """
        if syncPanel:
            syncPanel.statusAppend("\nPushing changes to remote...")
        origin = self.repo.remotes.origin
        try:
            info = self.repo.git.push()  # progress=progressHandler
        except git.exc.GitCommandError as e:
            if ("The project you were looking for could not be found" in
                    traceback.format_exc()):
                # we are pointing to a project at pavlovia but it doesn't exist
                # suggest we create it
                logging.warning("Project not found on gitlab.pavlovia.org")
                return MISSING_REMOTE
            else:
                raise e
        logging.debug('push report: {}'.format(info))
        if syncPanel:
            syncPanel.statusAppend("done")
            if info:
                syncPanel.statusAppend("\n{}".format(info))
        return 1
Example #28
0
    def add(self, thisType, value, position=None):
        """Add data to an existing data type (and add a new one if necess)
        """
        if not thisType in self:
            self.addDataType(thisType)
        if position is None:
            # 'ran' is always the first thing to update
            repN = sum(self['ran'][self.trials.thisIndex])
            if thisType != 'ran':
                # because it has already been updated
                repN -= 1
            # make a list where 1st digit is trial number
            position = [self.trials.thisIndex]
            position.append(repN)

        # check whether data falls within bounds
        posArr = np.asarray(position)
        shapeArr = np.asarray(self.dataShape)
        if not np.alltrue(posArr < shapeArr):
            # array isn't big enough
            logging.warning('need a bigger array for: ' + thisType)
            # not implemented yet!
            self[thisType] = extendArr(self[thisType], posArr)
        # check for ndarrays with more than one value and for non-numeric data
        if (self.isNumeric[thisType] and
                ((type(value) == np.ndarray and len(value) > 1) or
                     (type(value) not in [float, int]))):
            self._convertToObjectArray(thisType)
        # insert the value
        self[thisType][position[0], int(position[1])] = value
Example #29
0
    def _setVersion(version):
        """
        Sets the version to be used for compiling using the useVersion function

        Parameters
        ----------
        version: string
            The version requested
        """

        # Set version
        if version:
            from psychopy import useVersion
            useVersion(version)

        global logging

        from psychopy import logging

        if __name__ != '__main__' and version not in [None, 'None', 'none', '']:
            version = None
            msg = "You cannot set version by calling compileScript() manually. Setting 'version' to None."
            logging.warning(msg)

        return version
Example #30
0
def rush(value=True, realtime=False):
    """Raise the priority of the current thread/process using
        - sched_setscheduler

    realtime arg is not used in Linux implementation.

    NB for rush() to work on (debian-based?) Linux requires that the
    script is run using a copy of python that is allowed to change
    priority, eg: sudo setcap cap_sys_nice=eip <sys.executable>,
    and maybe restart PsychoPy. If <sys.executable> is the system python,
    it's important to restore it back to normal to avoid possible
    side-effects. Alternatively, use a different python executable,
    and change its cap_sys_nice.

    For RedHat-based systems, 'sudo chrt ...' at run-time might be
    needed instead, not sure.
    see http://rt.et.redhat.com/wiki/images/8/8e/Rtprio.pdf
    """
    if importCtypesFailed:
        return False

    if value:  # set to RR with max priority
        schedParams = _SchedParams()
        schedParams.sched_priority = c.sched_get_priority_max(SCHED_RR)
        err = c.sched_setscheduler(0, SCHED_RR, ctypes.byref(schedParams))
        if err == -1:  # returns 0 if OK
            logging.warning(warnMax % (sys.executable, sys.executable))
    else:  # set to RR with normal priority
        schedParams = _SchedParams()
        schedParams.sched_priority = c.sched_get_priority_min(SCHED_NORMAL)
        err = c.sched_setscheduler(0, SCHED_NORMAL, ctypes.byref(schedParams))
        if err == -1:  # returns 0 if OK
            logging.warning(warnNormal % sys.executable)

    return True
Example #31
0
 def stop(self):
     """Start recording from this keyboard"""
     logging.warning("Stopping key buffers but this could be dangerous if"
                     "other keyboards rely on the same.")
     for buffer in self._buffers.values():
         buffer.stop()
Example #32
0
    def installZipFile(self, zfile, v=None):
        """If v is provided this will be used as new version number;
        otherwise try and retrieve a version number from zip file name
        """
        info = ""  # return this at the end
        if py3:
            zfileIsName = type(zfile) == str
        else:
            zfileIsName = type(zfile) in (str, unicode)
        if os.path.isfile(zfile) and zfileIsName:
            # zfile is filename not an actual file
            if v is None:  # try and deduce it
                zFilename = os.path.split(zfile)[-1]
                searchName = re.search('[0-9]*\.[0-9]*\.[0-9]*.', zFilename)
                if searchName != None:
                    v = searchName.group(0)[:-1]
                else:
                    msg = "Couldn't deduce version from zip file: %s"
                    logging.warning(msg % zFilename)
            f = open(zfile, 'rb')
            zfile = zipfile.ZipFile(f)
        else:  # assume here that zfile is a ZipFile
            pass  # todo: error checking - is it a zipfile?

        currPath = self.app.prefs.paths['psychopy']
        currVer = psychopy.__version__
        # any commands that are successfully executed may need to be undone if
        # a later one fails
        undoStr = ""
        # depending on install method, needs diff handling
        # if path ends with 'psychopy' then move it to 'psychopy-version' and
        # create a new 'psychopy' folder for new version
        # does the path contain any version number?
        versionLabelsInPath = re.findall('PsychoPy-.*/', currPath)
        # e.g. the mac standalone app, no need to refer to new version number
        onWin32 = bool(sys.platform == 'win32' and
                       int(sys.getwindowsversion()[1]) > 5)
        if len(versionLabelsInPath) == 0:
            unzipTarget = currPath
            try:  # to move existing PsychoPy
                os.rename(currPath, "%s-%s" % (currPath, currVer))
                undoStr += 'os.rename("%s-%s" %(currPath, currVer),currPath)\n'
            except Exception:
                if onWin32:
                    msg = _translate("To upgrade you need to restart the app"
                                     " as admin (Right-click the app and "
                                     "'Run as admin')")
                else:
                    msg = _translate("Could not move existing PsychoPy "
                                     "installation (permissions error?)")
                return msg
        else:  # setuptools-style installation
            # generate new target path
            unzipTarget = currPath
            for thisVersionLabel in versionLabelsInPath:
                # remove final slash from the re.findall
                pathVersion = thisVersionLabel[:-1]
                unzipTarget = unzipTarget.replace(pathVersion,
                                                  "PsychoPy-%s" % v)
                # find the .pth file that specifies the python dir
                # create the new installation directory BEFORE changing pth
                # file
                nUpdates, newInfo = self.updatePthFile(pathVersion,
                                                       "PsychoPy-%s" % v)
                if nUpdates == -1:  # there was an error (likely permissions)
                    undoStr += 'self.updatePthFile(unzipTarget, currPath)\n'
                    exec(undoStr)  # undo previous changes
                    return newInfo

        try:
            # create the new installation dir AFTER renaming existing dir
            os.makedirs(unzipTarget)
            undoStr += 'os.remove(%s)\n' % unzipTarget
        except Exception:  # revert path rename and inform user
            exec(undoStr)  # undo previous changes
            if onWin32:
                msg = _translate(
                    "Right-click the app and 'Run as admin'):\n%s")
            else:
                msg = _translate("Failed to create directory for new version"
                                 " (permissions error?):\n%s")
            return msg % unzipTarget

        # do the actual extraction
        for name in zfile.namelist():  # for each file within the zip
            # check that this file is part of psychopy (not metadata or docs)
            if name.count('/psychopy/') < 1:
                continue
            try:
                targetFile = os.path.join(unzipTarget,
                                          name.split('/psychopy/')[1])
                targetContainer = os.path.split(targetFile)[0]
                if not os.path.isdir(targetContainer):
                    os.makedirs(targetContainer)  # make the containing folder
                if targetFile.endswith('/'):
                    os.makedirs(targetFile)  # it's a folder
                else:
                    outfile = open(targetFile, 'wb')
                    outfile.write(zfile.read(name))
                    outfile.close()
            except Exception:
                exec(undoStr)  # undo previous changes
                logging.error('failed to unzip file: ' + name)
                logging.error(sys.exc_info()[0])
        info += _translate('Success. \nChanges to PsychoPy will be completed'
                           ' when the application is next run')
        self.cancelBtn.SetDefault()
        self.installBtn.Disable()
        return info
Example #33
0
    def __init__(self,
                 win,
                 image="",
                 units="",
                 pos=(0.0, 0.0),
                 flipHoriz=False,
                 flipVert=False,
                 name='',
                 autoLog=True):
        """
        :Parameters:
            win :
                a :class:`~psychopy.visual.Window` object (required)
            image :
                The filename, including relative or absolute path. The image
                can be any format that the Python Imagin Library can import
                (almost any). Can also be an image already loaded by PIL.
            units : **None**, 'height', 'norm', 'cm', 'deg' or 'pix'
                If None then the current units of the :class:`~psychopy.visual.Window` will be used.
                See :ref:`units` for explanation of other options.
            pos :
                The centre of the stimulus, as a tuple (0., 0.) or a list [0., 0.] for the x and y.
                The origin is the screen centre, the units are determined
                by units (see above). Stimuli can be positioned off-screen, beyond the
                window!
            name : string
                The name of the object to be using during logged messages about
                this stim
        """
        #what local vars are defined (these are the init params) for use by __repr__
        self._initParams = dir()
        self._initParams.remove('self')
        self.autoLog = False
        self.win = win
        self.name = name
        super(SimpleImageStim, self).__init__()

        #unit conversions
        if units != None and len(units): self.units = units
        else: self.units = win.units

        self.useShaders = win._haveShaders  #use shaders if available by default, this is a good thing

        self.pos = numpy.array(pos, float)
        self.setImage(image)
        #check image size against window size
        if (self.size[0] > self.win.size[0]) or (self.size[1] >
                                                 self.win.size[1]):
            logging.warning(
                "Image size (%s, %s)  was larger than window size (%s, %s). Will draw black screen."
                % (self.size[0], self.size[1], self.win.size[0],
                   self.win.size[1]))

        #check position with size, warn if stimuli not fully drawn
        if ((self.pos[0] + (self.size[0] / 2.0) > self.win.size[0] / 2.0) or
            (self.pos[0] - (self.size[0] / 2.0) < -self.win.size[0] / 2.0)):
            logging.warning(
                "The image does not completely fit inside the window in the X direction."
            )

        if ((self.pos[1] + (self.size[1] / 2.0) > self.win.size[1] / 2.0) or
            (self.pos[1] - (self.size[1] / 2.0) < -self.win.size[1] / 2.0)):
            logging.warning(
                "The image does not completely fit inside the window in the Y direction."
            )

        #flip if necessary
        self.flipHoriz = False  #initially it is false, then so the flip according to arg above
        self.setFlipHoriz(flipHoriz)
        self.flipVert = False  #initially it is false, then so the flip according to arg above
        self.setFlipVert(flipVert)

        self._calcPosRendered()

        #set autoLog (now that params have been initialised)
        self.autoLog = autoLog
        if autoLog:
            logging.exp("Created %s = %s" % (self.name, repr(self)))
Example #34
0
#!/usr/bin/env python2
"""filters.py placeholder file for backwards compatibility; Dec 2015
"""

from psychopy import logging

logging.warning('Deprecated v1.84.00: instead of `from psychopy import '
                'filters`, now do `from psychopy.visual import filters`')

from psychopy.visual.filters import *  # pylint: disable=0401,W0614
Example #35
0
    def __init__(self,
                 win,
                 filename="",
                 units='pix',
                 size=None,
                 pos=(0.0, 0.0),
                 ori=0.0,
                 flipVert=False,
                 flipHoriz=False,
                 color=(1.0, 1.0, 1.0),
                 colorSpace='rgb',
                 opacity=1.0,
                 volume=1.0,
                 name='',
                 loop=False,
                 autoLog=True,
                 depth=0.0,
                 noAudio=False,
                 vframe_callback=None,
                 fps=None,
                 interpolate=True):
        """
        :Parameters:

            filename :
                a string giving the relative or absolute path to the movie.
            flipVert : True or *False*
                If True then the movie will be top-bottom flipped
            flipHoriz : True or *False*
                If True then the movie will be right-left flipped
            volume :
                The nominal level is 100, and 0 is silence.
            loop : bool, optional
                Whether to start the movie over from the beginning if draw is
                called and the movie is done.

        """
        # what local vars are defined (these are the init params) for use
        # by __repr__
        self._initParams = dir()
        self._initParams.remove('self')
        super(MovieStim3, self).__init__(win,
                                         units=units,
                                         name=name,
                                         autoLog=False)

        retraceRate = win._monitorFrameRate
        if retraceRate is None:
            retraceRate = win.getActualFrameRate()
        if retraceRate is None:
            logging.warning("FrameRate could not be supplied by psychopy; "
                            "defaulting to 60.0")
            retraceRate = 60.0
        self._retraceInterval = 1.0 / retraceRate
        self.filename = filename
        self.loop = loop
        self.flipVert = flipVert
        self.flipHoriz = flipHoriz
        self.pos = numpy.asarray(pos, float)
        self.depth = depth
        self.opacity = float(opacity)
        self.interpolate = interpolate
        self.noAudio = noAudio
        self._audioStream = None
        self.useTexSubImage2D = True

        self._videoClock = Clock()
        self.loadMovie(self.filename)
        self.setVolume(volume)
        self.nDroppedFrames = 0

        # size
        if size is None:
            self.size = numpy.array([self._mov.w, self._mov.h], float)
        else:
            self.size = val2array(size)
        self.ori = ori
        self._updateVertices()
        # set autoLog (now that params have been initialised)
        self.autoLog = autoLog
        if autoLog:
            logging.exp("Created %s = %s" % (self.name, str(self)))
button_resp.device_number = 0

try:
    numJoysticks = joysticklib.getNumJoysticks()
    if numJoysticks > 0:
        button_resp.device = joysticklib.Joystick(0)
        try:
            joystickCache
        except NameError:
            joystickCache={}
        if not 0 in joystickCache:
            joystickCache[0] = joysticklib.Joystick(0)
        button_resp.device = joystickCache[0]
    else:
        button_resp.device = virtualjoybuttonslib.VirtualJoyButtons(0)
        logging.warning("joystick_{}: Using keyboard emulation 'ctrl' + 'Alt' + digit.".format(button_resp.device_number))
except Exception:
    pass
    
if not button_resp.device:
    logging.error('No joystick/gamepad device found.')
    core.quit()

button_resp.status = None
button_resp.clock = core.Clock()
button_resp.numButtons = button_resp.device.getNumButtons()


# Create some handy timers
globalClock = core.Clock()  # to track the time since experiment started
routineTimer = core.CountdownTimer()  # to track time remaining of each (non-slip) routine 
Example #37
0
    def loadFromXML(self, filename):
        """Loads an xml file and parses the builder Experiment from it
        """
        self._doc.parse(filename)
        root = self._doc.getroot()

        # some error checking on the version (and report that this isn't valid
        # .psyexp)?
        filenameBase = os.path.basename(filename)
        if root.tag != "PsychoPy2experiment":
            logging.error('%s is not a valid .psyexp file, "%s"' %
                          (filenameBase, root.tag))
            # the current exp is already vaporized at this point, oops
            return
        self.psychopyVersion = root.get('version')
        versionf = float(self.psychopyVersion.rsplit('.', 1)[0])
        if versionf < 1.63:
            msg = 'note: v%s was used to create %s ("%s")'
            vals = (self.psychopyVersion, filenameBase, root.tag)
            logging.warning(msg % vals)

        # Parse document nodes
        # first make sure we're empty
        self.flow = Flow(exp=self)  # every exp has exactly one flow
        self.routines = {}
        self.namespace = NameSpace(self)  # start fresh
        modifiedNames = []
        duplicateNames = []

        # fetch exp settings
        settingsNode = root.find('Settings')
        for child in settingsNode:
            self._getXMLparam(params=self.settings.params,
                              paramNode=child,
                              componentNode=settingsNode)
        # name should be saved as a settings parameter (only from 1.74.00)
        if self.settings.params['expName'].val in ['', None, 'None']:
            shortName = os.path.splitext(filenameBase)[0]
            self.setExpName(shortName)
        # fetch routines
        routinesNode = root.find('Routines')
        allCompons = getAllComponents(self.prefsBuilder['componentsFolders'],
                                      fetchIcons=False)
        # get each routine node from the list of routines
        for routineNode in routinesNode:
            routineGoodName = self.namespace.makeValid(routineNode.get('name'))
            if routineGoodName != routineNode.get('name'):
                modifiedNames.append(routineNode.get('name'))
            self.namespace.user.append(routineGoodName)
            routine = Routine(name=routineGoodName, exp=self)
            # self._getXMLparam(params=routine.params, paramNode=routineNode)
            self.routines[routineNode.get('name')] = routine
            for componentNode in routineNode:

                componentType = componentNode.tag
                if componentType in allCompons:
                    # create an actual component of that type
                    component = allCompons[componentType](
                        name=componentNode.get('name'),
                        parentName=routineNode.get('name'),
                        exp=self)
                else:
                    # create UnknownComponent instead
                    component = allCompons['UnknownComponent'](
                        name=componentNode.get('name'),
                        parentName=routineNode.get('name'),
                        exp=self)
                # check for components that were absent in older versions of
                # the builder and change the default behavior
                # (currently only the new behavior of choices for RatingScale,
                # HS, November 2012)
                # HS's modification superceded Jan 2014, removing several
                # RatingScale options
                if componentType == 'RatingScaleComponent':
                    if (componentNode.get('choiceLabelsAboveLine')
                            or componentNode.get('lowAnchorText')
                            or componentNode.get('highAnchorText')):
                        pass
                    # if not componentNode.get('choiceLabelsAboveLine'):
                    #    # this rating scale was created using older version
                    #    component.params['choiceLabelsAboveLine'].val=True
                # populate the component with its various params
                for paramNode in componentNode:
                    self._getXMLparam(params=component.params,
                                      paramNode=paramNode,
                                      componentNode=componentNode)
                compGoodName = self.namespace.makeValid(
                    componentNode.get('name'))
                if compGoodName != componentNode.get('name'):
                    modifiedNames.append(componentNode.get('name'))
                self.namespace.add(compGoodName)
                component.params['name'].val = compGoodName
                routine.append(component)
        # for each component that uses a Static for updates, we need to set
        # that
        for thisRoutine in list(self.routines.values()):
            for thisComp in thisRoutine:
                for thisParamName in thisComp.params:
                    thisParam = thisComp.params[thisParamName]
                    if thisParamName == 'advancedParams':
                        continue  # advanced isn't a normal param
                    elif thisParam.updates and "during:" in thisParam.updates:
                        # remove the part that says 'during'
                        updates = thisParam.updates.split(': ')[1]
                        routine, static = updates.split('.')
                        if routine not in self.routines:
                            msg = ("%s was set to update during %s Static "
                                   "Component, but that component no longer "
                                   "exists")
                            logging.warning(msg % (thisParamName, static))
                        else:
                            self.routines[routine].getComponentFromName(
                                static).addComponentUpdate(
                                    thisRoutine.params['name'],
                                    thisComp.params['name'], thisParamName)
        # fetch flow settings
        flowNode = root.find('Flow')
        loops = {}
        for elementNode in flowNode:
            if elementNode.tag == "LoopInitiator":
                loopType = elementNode.get('loopType')
                loopName = self.namespace.makeValid(elementNode.get('name'))
                if loopName != elementNode.get('name'):
                    modifiedNames.append(elementNode.get('name'))
                self.namespace.add(loopName)
                loop = eval('%s(exp=self,name="%s")' % (loopType, loopName))
                loops[loopName] = loop
                for paramNode in elementNode:
                    self._getXMLparam(paramNode=paramNode, params=loop.params)
                    # for conditions convert string rep to list of dicts
                    if paramNode.get('name') == 'conditions':
                        param = loop.params['conditions']
                        # e.g. param.val=[{'ori':0},{'ori':3}]
                        try:
                            param.val = eval('%s' % (param.val))
                        except SyntaxError:
                            # This can occur if Python2.7 conditions string
                            # contained long ints (e.g. 8L) and these can't be
                            # parsed by Py3. But allow the file to carry on
                            # loading and the conditions will still be loaded
                            # from the xlsx file
                            pass
                # get condition names from within conditionsFile, if any:
                try:
                    # psychophysicsstaircase demo has no such param
                    conditionsFile = loop.params['conditionsFile'].val
                except Exception:
                    conditionsFile = None
                if conditionsFile in ['None', '']:
                    conditionsFile = None
                if conditionsFile:
                    try:
                        trialList, fieldNames = data.importConditions(
                            conditionsFile, returnFieldNames=True)
                        for fname in fieldNames:
                            if fname != self.namespace.makeValid(fname):
                                duplicateNames.append(fname)
                            else:
                                self.namespace.add(fname)
                    except Exception:
                        pass  # couldn't load the conditions file for now
                self.flow.append(LoopInitiator(loop=loops[loopName]))
            elif elementNode.tag == "LoopTerminator":
                self.flow.append(
                    LoopTerminator(loop=loops[elementNode.get('name')]))
            elif elementNode.tag == "Routine":
                if elementNode.get('name') in self.routines:
                    self.flow.append(self.routines[elementNode.get('name')])
                else:
                    logging.error("A Routine called '{}' was on the Flow but "
                                  "could not be found (failed rename?). You "
                                  "may need to re-insert it".format(
                                      elementNode.get('name')))
                    logging.flush()

        if modifiedNames:
            msg = 'duplicate variable name(s) changed in loadFromXML: %s\n'
            logging.warning(msg % ', '.join(list(set(modifiedNames))))
        if duplicateNames:
            msg = 'duplicate variable names: %s'
            logging.warning(msg % ', '.join(list(set(duplicateNames))))
        # if we succeeded then save current filename to self
        self.filename = filename
Example #38
0
    def __init__(self, win, *args, **kwargs):
        """Set up the backend window according the params of the PsychoPy win

        Before PsychoPy 1.90.0 this code was executed in Window._setupPygame()

        :param: win is a PsychoPy Window (usually not fully created yet)
        """
        BaseBackend.__init__(self, win)  # sets up self.win=win as weakref

        if win.allowStencil:
            stencil_size = 8
        else:
            stencil_size = 0
        vsync = 0

        # provide warning if stereo buffers are requested but unavailable
        if win.stereo and not GL.gl_info.have_extension('GL_STEREO'):
            logging.warning('A stereo window was requested but the graphics '
                            'card does not appear to support GL_STEREO')
            win.stereo = False

        if sys.platform == 'darwin' and not win.useRetina and pyglet.version >= "1.3":
            raise ValueError("As of PsychoPy 1.85.3 OSX windows should all be "
                             "set to useRetina=True (or remove the argument). "
                             "Pyglet 1.3 appears to be forcing "
                             "us to use retina on any retina-capable screen "
                             "so setting to False has no effect.")

        # multisampling
        sample_buffers = 0
        aa_samples = 0

        if win.multiSample:
            sample_buffers = 1
            # get maximum number of samples the driver supports
            max_samples = (GL.GLint)()
            GL.glGetIntegerv(GL.GL_MAX_SAMPLES, max_samples)

            if (win.numSamples >= 2) and (win.numSamples <= max_samples.value):
                # NB - also check if divisible by two and integer?
                aa_samples = win.numSamples
            else:
                logging.warning(
                    'Invalid number of MSAA samples provided, must be '
                    'integer greater than two. Disabling.')
                win.multiSample = False

        # options that the user might want
        config = GL.Config(depth_size=8,
                           double_buffer=True,
                           sample_buffers=sample_buffers,
                           samples=aa_samples,
                           stencil_size=stencil_size,
                           stereo=win.stereo,
                           vsync=vsync)

        defDisp = pyglet.window.get_platform().get_default_display()
        allScrs = defDisp.get_screens()
        # Screen (from Exp Settings) is 1-indexed,
        # so the second screen is Screen 1
        if len(allScrs) < int(win.screen) + 1:
            logging.warn("Requested an unavailable screen number - "
                         "using first available.")
            thisScreen = allScrs[0]
        else:
            thisScreen = allScrs[win.screen]
            if win.autoLog:
                logging.info('configured pyglet screen %i' % self.screen)
        # if fullscreen check screen size
        if win._isFullScr:
            win._checkMatchingSizes(win.size,
                                    [thisScreen.width, thisScreen.height])
            w = h = None
        else:
            w, h = win.size
        if win.allowGUI:
            style = None
        else:
            style = 'borderless'
        try:
            self.winHandle = pyglet.window.Window(width=w,
                                                  height=h,
                                                  caption="PsychoPy",
                                                  fullscreen=win._isFullScr,
                                                  config=config,
                                                  screen=thisScreen,
                                                  style=style)
        except pyglet.gl.ContextException:
            # turn off the shadow window an try again
            pyglet.options['shadow_window'] = False
            self.winHandle = pyglet.window.Window(width=w,
                                                  height=h,
                                                  caption="PsychoPy",
                                                  fullscreen=self._isFullScr,
                                                  config=config,
                                                  screen=thisScreen,
                                                  style=style)
            logging.warning(
                "Pyglet shadow_window has been turned off. This is "
                "only an issue for you if you need multiple "
                "stimulus windows, in which case update your "
                "graphics card and/or graphics drivers.")

        if sys.platform == 'win32':
            # pyHook window hwnd maps to:
            # pyglet 1.14 -> window._hwnd
            # pyglet 1.2a -> window._view_hwnd
            if pyglet.version > "1.2":
                win._hw_handle = self.winHandle._view_hwnd
            else:
                win._hw_handle = self.winHandle._hwnd
        elif sys.platform == 'darwin':
            if win.useRetina:
                global retinaContext
                retinaContext = self.winHandle.context._nscontext
                view = retinaContext.view()
                bounds = view.convertRectToBacking_(view.bounds()).size
                if win.size[0] == bounds.width:
                    win.useRetina = False  # the screen is not a retina display
                win.size = np.array([int(bounds.width), int(bounds.height)])
            try:
                # python 32bit (1.4. or 1.2 pyglet)
                win._hw_handle = self.winHandle._window.value
            except Exception:
                # pyglet 1.2 with 64bit python?
                win._hw_handle = self.winHandle._nswindow.windowNumber()
        elif sys.platform.startswith('linux'):
            win._hw_handle = self.winHandle._window

        if win.useFBO:  # check for necessary extensions
            if not GL.gl_info.have_extension('GL_EXT_framebuffer_object'):
                msg = ("Trying to use a framebuffer object but "
                       "GL_EXT_framebuffer_object is not supported. Disabled")
                logging.warn(msg)
                win.useFBO = False
            if not GL.gl_info.have_extension('GL_ARB_texture_float'):
                msg = ("Trying to use a framebuffer object but "
                       "GL_ARB_texture_float is not supported. Disabling")
                logging.warn(msg)
                win.useFBO = False

        if pyglet.version < "1.2" and sys.platform == 'darwin':
            platform_specific.syncSwapBuffers(1)

        # add these methods to the pyglet window
        self.winHandle.setGamma = setGamma
        self.winHandle.setGammaRamp = setGammaRamp
        self.winHandle.getGammaRamp = getGammaRamp
        self.winHandle.set_vsync(True)
        self.winHandle.on_text = event._onPygletText
        self.winHandle.on_key_press = event._onPygletKey
        self.winHandle.on_mouse_press = event._onPygletMousePress
        self.winHandle.on_mouse_release = event._onPygletMouseRelease
        self.winHandle.on_mouse_scroll = event._onPygletMouseWheel
        if not win.allowGUI:
            # make mouse invisible. Could go further and make it 'exclusive'
            # (but need to alter x,y handling then)
            self.winHandle.set_mouse_visible(False)
        self.winHandle.on_resize = _onResize  # avoid circular reference
        if not win.pos:
            # work out where the centre should be
            if win.useRetina:
                win.pos = [(thisScreen.width - win.size[0] / 2) / 2,
                           (thisScreen.height - win.size[1] / 2) / 2]
            else:
                win.pos = [(thisScreen.width - win.size[0]) / 2,
                           (thisScreen.height - win.size[1]) / 2]
        if not win._isFullScr:
            # add the necessary amount for second screen
            self.winHandle.set_location(int(win.pos[0] + thisScreen.x),
                                        int(win.pos[1] + thisScreen.y))

        try:  # to load an icon for the window
            iconFile = os.path.join(psychopy.prefs.paths['resources'],
                                    'psychopy.ico')
            icon = pyglet.image.load(filename=iconFile)
            self.winHandle.set_icon(icon)
        except Exception:
            pass  # doesn't matter

        # store properties of the system
        self._driver = pyglet.gl.gl_info.get_renderer()
        self._gammaErrorPolicy = win.gammaErrorPolicy
        try:
            self._origGammaRamp = self.getGammaRamp()
            self._rampSize = getGammaRampSize(
                self.screenID,
                self.xDisplay,
                gammaErrorPolicy=self._gammaErrorPolicy)
        except OSError:
            self.close()
            raise
        self._TravisTesting = (os.environ.get('TRAVIS') == 'true')
Example #39
0
 def lineColorSpace(self, value):
     logging.warning(
         "Setting color space by attribute rather than by object is deprecated. Value of lineColorSpace has been assigned to colorSpace."
     )
     self.colorSpace = value
Example #40
0
from collections import deque
import sys
import copy

import psychopy.core
import psychopy.clock
from psychopy import logging
from psychopy.constants import NOT_STARTED

try:
    import psychtoolbox as ptb
    from psychtoolbox import hid
    havePTB = True
except ImportError as err:
    logging.warning(("Import Error: " + err.args[0] +
                     ". Using event module for keyboard component."))
    from psychopy import event
    havePTB = False

defaultBufferSize = 10000


def getKeyboards():
    """Get info about the available keyboards.

    Only really useful on Mac/Linux because on these the info can be used to
    select a particular physical device when calling :class:`Keyboard`. On Win
    this function does return information correctly but the :class:Keyboard
    can't make use of it.

    Returns
Example #41
0
def initPyo(rate=44100, stereo=True, buffer=128):
    """setup the pyo (sound) server
    """
    global pyoSndServer, Sound, audioDriver, duplex, maxChnls
    Sound = SoundPyo
    global pyo
    try:
        assert pyo
    except NameError:  # pragma: no cover
        import pyo  # microphone.switchOn() calls initPyo even if audioLib is something else
    #subclass the pyo.Server so that we can insert a __del__ function that shuts it down
    # skip coverage since the class is never used if we have a recent version of pyo
    class _Server(pyo.Server):  # pragma: no cover
        core = core  #make libs class variables so they don't get deleted first
        logging = logging

        def __del__(self):
            self.stop()
            self.core.wait(
                0.5)  #make sure enough time passes for the server to shutdown
            self.shutdown()
            self.core.wait(
                0.5)  #make sure enough time passes for the server to shutdown
            self.logging.debug(
                'pyo sound server shutdown')  #this may never get printed

    if '.'.join(map(str, pyo.getVersion())) < '0.6.4':
        Server = _Server
    else:
        Server = pyo.Server

    # if we already have a server, just re-initialize it
    if 'pyoSndServer' in globals() and hasattr(pyoSndServer, 'shutdown'):
        pyoSndServer.stop()
        core.wait(
            0.5)  #make sure enough time passes for the server to shutdown
        pyoSndServer.shutdown()
        core.wait(0.5)
        pyoSndServer.reinit(sr=rate,
                            nchnls=maxChnls,
                            buffersize=buffer,
                            audio=audioDriver)
        pyoSndServer.boot()
    else:
        if platform == 'win32':
            #check for output device/driver
            devNames, devIDs = pyo.pa_get_output_devices()
            audioDriver, outputID = _bestDriver(devNames, devIDs)
            if outputID is None:
                audioDriver = 'Windows Default Output'  #using the default output because we didn't find the one(s) requested
                outputID = pyo.pa_get_default_output()
            if outputID is not None:
                logging.info('Using sound driver: %s (ID=%i)' %
                             (audioDriver, outputID))
                maxOutputChnls = pyo.pa_get_output_max_channels(outputID)
            else:
                logging.warning(
                    'No audio outputs found (no speakers connected?')
                return -1
            #check for valid input (mic)
            devNames, devIDs = pyo.pa_get_input_devices()
            audioInputName, inputID = _bestDriver(devNames, devIDs)
            if inputID is None:
                audioInputName = 'Windows Default Input'  #using the default input because we didn't find the one(s) requested
                inputID = pyo.pa_get_default_input()
            if inputID is not None:
                logging.info('Using sound-input driver: %s (ID=%i)' %
                             (audioInputName, inputID))
                maxInputChnls = pyo.pa_get_input_max_channels(inputID)
                duplex = bool(maxInputChnls > 0)
            else:
                maxInputChnls = 0
                duplex = False
        else:  #for other platforms set duplex to True (if microphone is available)
            audioDriver = prefs.general['audioDriver'][0]
            maxInputChnls = pyo.pa_get_input_max_channels(
                pyo.pa_get_default_input())
            maxOutputChnls = pyo.pa_get_output_max_channels(
                pyo.pa_get_default_output())
            duplex = bool(maxInputChnls > 0)

        maxChnls = min(maxInputChnls, maxOutputChnls)
        if maxInputChnls < 1:  # pragma: no cover
            logging.warning(
                '%s.initPyo could not find microphone hardware; recording not available'
                % __name__)
            maxChnls = maxOutputChnls
        if maxOutputChnls < 1:  # pragma: no cover
            logging.error(
                '%s.initPyo could not find speaker hardware; sound not available'
                % __name__)
            return -1

        # create the instance of the server:
        if platform in ['darwin', 'linux2']:
            #for mac/linux we set the backend using the server audio param
            pyoSndServer = Server(sr=rate,
                                  nchnls=maxChnls,
                                  buffersize=buffer,
                                  audio=audioDriver)
        else:
            #with others we just use portaudio and then set the OutputDevice below
            pyoSndServer = Server(sr=rate, nchnls=maxChnls, buffersize=buffer)

        pyoSndServer.setVerbosity(1)
        if platform == 'win32':
            pyoSndServer.setOutputDevice(outputID)
            if inputID is not None:
                pyoSndServer.setInputDevice(inputID)
        #do other config here as needed (setDuplex? setOutputDevice?)
        pyoSndServer.setDuplex(duplex)
        pyoSndServer.boot()
    core.wait(0.5)  #wait for server to boot before starting te sound stream
    pyoSndServer.start()
    try:
        Sound()  # test creation, no play
    except pyo.PyoServerStateException:
        msg = "Failed to start pyo sound Server"
        if platform == 'darwin' and audioDriver != 'portaudio':
            msg += "; maybe try prefs.general.audioDriver 'portaudio'?"
        logging.error(msg)
        core.quit()
    logging.debug('pyo sound server started')
    logging.flush()
Example #42
0
    def __init__(
            self,
            win,
            units='',
            lineWidth=1.5,
            lineColor=False,  # uses False in place of None to distinguish between "not set" and "transparent"
            fillColor=False,  # uses False in place of None to distinguish between "not set" and "transparent"
            colorSpace='rgb',
            vertices=((-0.5, 0), (0, +0.5), (+0.5, 0)),
            closeShape=True,
            pos=(0, 0),
            size=1,
            ori=0.0,
            opacity=None,
            contrast=1.0,
            depth=0,
            interpolate=True,
            name=None,
            autoLog=None,
            autoDraw=False,
            # legacy
            color=False,
            lineRGB=False,
            fillRGB=False,
            fillColorSpace=None,
            lineColorSpace=None):
        """ """  # all doc is in the attributes
        # what local vars are defined (these are the init params) for use by
        # __repr__
        self._initParams = dir()
        self._initParams.remove('self')

        # Initialize inheritance and remove unwanted methods; autoLog is set
        # later
        super(BaseShapeStim, self).__init__(win,
                                            units=units,
                                            name=name,
                                            autoLog=False)

        self.pos = numpy.array(pos, float)
        self.closeShape = closeShape
        self.lineWidth = lineWidth
        self.interpolate = interpolate

        # Appearance
        self.colorSpace = colorSpace
        if fillColor is not False:
            self.fillColor = fillColor
        elif color is not False:
            # Override fillColor with color if not set
            self.fillColor = color
        else:
            # Default to None if neither are set
            self.fillColor = None
        if lineColor is not False:
            self.lineColor = lineColor
        elif color is not False:
            # Override lineColor with color if not set
            self.lineColor = color
        else:
            # Default to black if neither are set
            self.lineColor = 'black'
        if lineRGB is not False:
            # Override with RGB if set
            logging.warning("Use of rgb arguments to stimuli are deprecated."
                            " Please use color and colorSpace args instead")
            self.setLineColor(lineRGB, colorSpace='rgb', log=None)
        if fillRGB is not False:
            # Override with RGB if set
            logging.warning("Use of rgb arguments to stimuli are deprecated."
                            " Please use color and colorSpace args instead")
            self.setFillColor(fillRGB, colorSpace='rgb', log=None)
        self.contrast = contrast
        if opacity:
            self.opacity = opacity

        # Other stuff
        self.depth = depth
        self.ori = numpy.array(ori, float)
        self.size = numpy.array([0.0, 0.0]) + size  # make sure that it's 2D
        if vertices != ():  # flag for when super-init'ing a ShapeStim
            self.vertices = vertices  # call attributeSetter
        self.autoDraw = autoDraw  # call attributeSetter

        # set autoLog now that params have been initialised
        wantLog = autoLog is None and self.win.autoLog
        self.__dict__['autoLog'] = autoLog or wantLog
        if self.autoLog:
            logging.exp("Created %s = %s" % (self.name, str(self)))
Example #43
0
def main(info):
    # save log of subjects
    write_subjectlog(subjectlog, info)
    run_nr = int(info['run_nr'])
    subj = info['subject_id']
    fullscr = info['fullscr']
    time = core.Clock()
    subj_dir = pjoin(RESDIR, 'sub-' + subj)
    if not pexists(subj_dir):
        os.makedirs(subj_dir)
    log_fn = config['log_template'].format(
        subj=subj,
        task_name=config['task_name'],
        runnr=run_nr,
        timestamp=ptime.strftime(time_template),
    )
    log_fn = pjoin(subj_dir, log_fn)
    log_responses = logging.LogFile(log_fn, level=logging.INFO)
    # set up global key for quitting; if that happens, log will be moved to
    # {log_fn}__halted.txt
    event.globalKeys.add(key='q',
                         modifiers=['ctrl'],
                         func=move_halted_log,
                         func_args=[log_fn],
                         name='quit experiment gracefully')
    # --- LOAD STIMULI ORDER FOR THIS PARTICIPANT ---
    stim_json = pjoin(PWD, 'cfg',
                      'sub-{0}_task-localizer_4runs.json'.format(subj))
    # create stimulus order if not existing
    if not os.path.exists(stim_json):
        logging.warning("Creating stimulus order for {0}".format(subj))
        MAKESTIMPY = pjoin(HERE, 'make_stim_order.py')
        cmd = "python {cmd} --subid {subj} --output {output} " \
              "--nruns 4".format(cmd=MAKESTIMPY, subj=subj,
                                 output=dirname(stim_json))
        logging.warning("Running '{0}'".format(cmd))
        sp.check_call(cmd.split())
    with open(stim_json, 'rb') as f:
        stimuli = json.load(f)[str(run_nr)]
    # ------------------------
    print "Opening screen"
    tbegin = time.getTime()
    using_scanner = info['scanner?']
    # Setting up visual
    size = [1280, 1024]
    scrwin = visual.Window(size=size,
                           allowGUI=False, units='pix',
                           screen=1, rgb=[-1, -1, -1],
                           fullscr=fullscr)
    # load clips
    print "Loading stimuli"
    loading = visual.TextStim(scrwin,
                              text="Loading stimuli...",
                              height=31)
    loading.draw()
    scrwin.flip()
    stimuli_clip = dict()
    for stim in stimuli:
        if stim['stim_type'] != 'fixation':
            stim_fn = stim['stim_fn']
            print("Loading {0}".format(stim_fn))
            stimuli_clip[stim_fn] = \
                visual.MovieStim3(scrwin, pjoin(PWD, stim_fn),
                                  size=(1280, 940),
                                  name=stim_fn,
                                  noAudio=True, loop=True)
    scrwin.flip()
    cross_hair = visual.TextStim(scrwin, text='+', height=31,
                                 pos=(0, 0), color='#FFFFFF')
    if using_scanner:
        intro_msg = "Waiting for trigger..."
    else:
        intro_msg = "Press Enter to start"
    intro_msg = instructions + '\n' + intro_msg
    intro = visual.TextStim(scrwin, text=intro_msg, height=31, wrapWidth=900)
    # Start of experiment
    intro.draw()
    scrwin.flip()
    # open up serial port and wait for first trigger
    if using_scanner:
        ser_port = '/dev/ttyUSB0'
        ser = serial.Serial(ser_port, 115200, timeout=.0001)
        ser.flushInput()
        trigger = ''
        while trigger != '5':
            trigger = ser.read()
    else:
        from psychopy.hardware.emulator import launchScan
        event.waitKeys(keyList=['return'])
        # XXX: set up TR here
        MR_settings = {
            'TR': 1,
            'volumes': 280,
            'sync': '5',
            'skip': 3,
            'sound': False,
        }
        vol = launchScan(scrwin, MR_settings, globalClock=time, mode='Test')

        class FakeSerial(object):
            @staticmethod
            def read():
                k = event.getKeys(['1', '2', '5'])
                return k[-1] if k else ''

        ser = FakeSerial()

    # set up timer for experiment starting from first trigger
    timer_exp = core.Clock()
    trunbegin = timer_exp.getTime()
    # setup bids log
    logbids("onset\tduration\tstim_type\trepetition")
    # duration will be filled later
    template_bids = '{onset:.3f}\t{duration:.3f}\t{stim_type}\t{stim_fn}\t' \
                    '{repetition}'
    # and now we just loop through the trials
    for trial in stimuli:
        stim_type = trial['stim_type']
        stim_fn = trial['stim_fn']
        duration = trial['duration']
        logbids(template_bids.format(
            onset=timer_exp.getTime(),
            duration=duration,
            stim_type=stim_type,
            stim_fn=stim_fn,
            repetition=trial.get('repetition', 0)),
        )
        trial_counter = core.CountdownTimer(duration)
        if stim_type == 'fixation':
            cross_hair.draw()
            scrwin.flip()
            logging.flush()
            while trial_counter.getTime() > 0:
                pass
        else:
            movie = stimuli_clip[stim_fn]
            while trial_counter.getTime() > 0:
                key = ser.read()
                if key in ['1', '2']:
                    logbids(template_bids.format(
                        onset=timer_exp.getTime(),
                        duration=0.,
                        stim_type='button_press',
                        stim_fn=None,
                        repetition=0)
                    )
                if movie.status != visual.FINISHED:
                    movie.draw()
                    scrwin.flip()
                else:
                    cross_hair.draw()
                    scrwin.flip()
    logging.exp("Done in {0:.2f}s".format(timer_exp.getTime()))
    logging.flush()
    scrwin.close()
    core.quit()
Example #44
0
    def __init__(self, win, *args, **kwargs):
        """Set up the backend window according the params of the PsychoPy win

        Before PsychoPy 1.90.0 this code was executed in Window._setupPygame()

        Parameters
        ----------
        win : psychopy.visual.Window instance
            PsychoPy Window (usually not fully created yet).
        share : psychopy.visual.Window instance
            PsychoPy Window to share a context with
        bpc : array_like
            Bits per color (R, G, B).
        refreshHz : int
            Refresh rate in Hertz.
        depthBits : int,
            Framebuffer (back buffer) depth bits.
        swapInterval : int
            Swap interval for the current OpenGL context.
        stencilBits : int
            Framebuffer (back buffer) stencil bits.
        winTitle : str
            Optional window title string.
        *args
            Additional position arguments.
        **kwargs
            Additional keyword arguments.

        """
        BaseBackend.__init__(self, win)

        # window to share a context with
        shareWin = kwargs.get('share', None)
        if shareWin is not None:
            if shareWin.winType == 'glfw':
                shareContext = shareWin.winHandle
            else:
                logging.warning(
                    'Cannot share a context with a non-GLFW window. Disabling.'
                )
                shareContext = None
        else:
            shareContext = None

        if sys.platform == 'darwin' and not win.useRetina and pyglet.version >= "1.3":
            raise ValueError("As of PsychoPy 1.85.3 OSX windows should all be "
                             "set to useRetina=True (or remove the argument). "
                             "Pyglet 1.3 appears to be forcing "
                             "us to use retina on any retina-capable screen "
                             "so setting to False has no effect.")

        # window framebuffer configuration
        bpc = kwargs.get('bpc', (8, 8, 8))
        if isinstance(bpc, int):
            win.bpc = (bpc, bpc, bpc)
        else:
            win.bpc = bpc

        win.refreshHz = int(kwargs.get('refreshHz', 60))
        win.depthBits = int(kwargs.get('depthBits', 8))
        win.stencilBits = int(kwargs.get('stencilBits', 8))
        # win.swapInterval = int(kwargs.get('swapInterval', 1))  # vsync ON if 1

        # get monitors, with GLFW the primary display is ALWAYS at index 0
        allScrs = glfw.get_monitors()
        if len(allScrs) < int(win.screen) + 1:
            logging.warn("Requested an unavailable screen number - "
                         "using first available.")
            win.screen = 0

        thisScreen = allScrs[win.screen]
        if win.autoLog:
            logging.info('configured GLFW screen %i' % win.screen)

        # find a matching video mode (can we even support this configuration?)
        isVidmodeSupported = False
        for vidmode in glfw.get_video_modes(thisScreen):
            size, bpc, hz = vidmode
            if win._isFullScr:  # size and refresh rate are ignored if windowed
                hasSize = size == tuple(win.size)
                hasHz = hz == win.refreshHz
            else:
                hasSize = hasHz = True
            hasBpc = bpc == tuple(win.bpc)
            if hasSize and hasBpc and hasHz:
                isVidmodeSupported = True
                break

        nativeVidmode = glfw.get_video_mode(thisScreen)
        if not isVidmodeSupported:
            # the requested video mode is not supported, use current

            logging.warning(
                ("The specified video mode is not supported by this display, "
                 "using native mode ..."))

            actualWidth, actualHeight = nativeVidmode.size
            redBits, greenBits, blueBits = nativeVidmode.bits
            # change the window settings
            if win._isFullScr:
                logging.warning((
                    "Overriding user video settings: size {} -> {}, bpc {} -> "
                    "{}, refreshHz {} -> {}".format(
                        tuple(win.size), (actualWidth, actualHeight),
                        tuple(win.bpc), (redBits, greenBits, blueBits),
                        win.refreshHz, nativeVidmode.refresh_rate)))

                win.clientSize = np.array((actualWidth, actualHeight), np.int)
            else:
                logging.warning(
                    ("Overriding user video settings: bpc {} -> "
                     "{}, refreshHz {} -> {}".format(
                         tuple(win.bpc), (redBits, greenBits, blueBits),
                         win.refreshHz, nativeVidmode.refresh_rate)))

            win.bpc = (redBits, greenBits, blueBits)
            win.refreshHz = nativeVidmode.refresh_rate

        if win._isFullScr:
            useDisplay = thisScreen
        else:
            useDisplay = None

        # configure stereo
        useStereo = 0
        if win.stereo:
            # provide warning if stereo buffers are requested but unavailable
            if not glfw.extension_supported('GL_STEREO'):
                logging.warning(
                    'A stereo window was requested but the graphics '
                    'card does not appear to support GL_STEREO')
                win.stereo = False
            else:
                useStereo = 1

        # setup multisampling
        # This enables multisampling on the window backbuffer, not on other
        # framebuffers.
        msaaSamples = 0
        if win.multiSample:
            maxSamples = (GL.GLint)()
            GL.glGetIntegerv(GL.GL_MAX_SAMPLES, maxSamples)
            if (win.numSamples & (win.numSamples - 1)) != 0:
                # power of two?
                logging.warning(
                    'Invalid number of MSAA samples provided, must be '
                    'power of two. Disabling.')
            elif 0 > win.numSamples > maxSamples.value:
                # check if within range
                logging.warning(
                    'Invalid number of MSAA samples provided, outside of valid '
                    'range. Disabling.')
            else:
                msaaSamples = win.numSamples
        win.multiSample = msaaSamples > 0

        # disable stencil buffer
        if not win.allowStencil:
            win.stencilBits = 0

        # set buffer configuration hints
        glfw.window_hint(glfw.RED_BITS, win.bpc[0])
        glfw.window_hint(glfw.GREEN_BITS, win.bpc[1])
        glfw.window_hint(glfw.BLUE_BITS, win.bpc[2])
        glfw.window_hint(glfw.REFRESH_RATE, win.refreshHz)
        glfw.window_hint(glfw.STEREO, useStereo)
        glfw.window_hint(glfw.SAMPLES, msaaSamples)
        glfw.window_hint(glfw.STENCIL_BITS, win.stencilBits)
        glfw.window_hint(glfw.DEPTH_BITS, win.depthBits)
        glfw.window_hint(glfw.AUTO_ICONIFY, 0)

        # window appearance and behaviour hints
        if not win.allowGUI:
            glfw.window_hint(glfw.DECORATED, 0)

        # create the window
        self.winHandle = glfw.create_window(
            width=win.clientSize[0],
            height=win.clientSize[1],
            title=str(kwargs.get('winTitle', "PsychoPy (GLFW)")),
            monitor=useDisplay,
            share=shareContext)

        # The window's user pointer maps the Python Window object to its GLFW
        # representation.
        glfw.set_window_user_pointer(self.winHandle, win)
        glfw.make_context_current(self.winHandle)  # ready to use

        # set the position of the window if not fullscreen
        if not win._isFullScr:
            # if no window position is specified, centre it on-screen
            if win.pos is None:
                size, bpc, hz = nativeVidmode
                win.pos = [(size[0] - win.clientSize[0]) / 2.0,
                           (size[1] - win.clientSize[1]) / 2.0]

            # get the virtual position of the monitor, apply offset to the
            # window position
            px, py = glfw.get_monitor_pos(thisScreen)
            glfw.set_window_pos(self.winHandle, int(win.pos[0] + px),
                                int(win.pos[1] + py))

        elif win._isFullScr and win.pos is not None:
            logging.warn("Ignoring window 'pos' in fullscreen mode.")

        # set the window icon
        if hasattr(glfw, 'set_window_icon'):
            glfw.set_window_icon(self.winHandle, 1, _WINDOW_ICON_)

        # set the window size to the framebuffer size
        self._frameBufferSize = np.array(
            glfw.get_framebuffer_size(self.winHandle))

        if win.useFBO:  # check for necessary extensions
            if not glfw.extension_supported('GL_EXT_framebuffer_object'):
                msg = ("Trying to use a framebuffer object but "
                       "GL_EXT_framebuffer_object is not supported. Disabled")
                logging.warn(msg)
                win.useFBO = False
            if not glfw.extension_supported('GL_ARB_texture_float'):
                msg = ("Trying to use a framebuffer object but "
                       "GL_ARB_texture_float is not supported. Disabling")
                logging.warn(msg)
                win.useFBO = False

        # Assign event callbacks, these are dispatched when 'poll_events' is
        # called.
        glfw.set_mouse_button_callback(self.winHandle,
                                       event._onGLFWMouseButton)
        glfw.set_scroll_callback(self.winHandle, event._onGLFWMouseScroll)
        glfw.set_key_callback(self.winHandle, event._onGLFWKey)
        glfw.set_char_mods_callback(self.winHandle, event._onGLFWText)

        # set swap interval to manual setting, independent of waitBlanking
        self.setSwapInterval(int(kwargs.get('swapInterval', 1)))

        # give the window class GLFW specific methods
        win.setMouseType = self.setMouseType
        if not win.allowGUI:
            self.setMouseVisibility(False)
Example #45
0
    def __init__(self,
                 win,
                 tex     ="sqrXsqr",
                 mask    ="none",
                 units   ="",
                 pos     =(0.0,0.0),
                 size    =(1.0,1.0),
                 radialCycles=3,
                 angularCycles=4,
                 radialPhase=0,
                 angularPhase=0,
                 ori     =0.0,
                 texRes =64,
                 angularRes=100,
                 visibleWedge=(0, 360),
                 rgb   =None,
                 color=(1.0,1.0,1.0),
                 colorSpace='rgb',
                 dkl=None,
                 lms=None,
                 contrast=1.0,
                 opacity=1.0,
                 depth=0,
                 rgbPedestal = (0.0,0.0,0.0),
                 interpolate=False,
                 name=None,
                 autoLog=None,
                 maskParams=None):
        """ """ # Empty docstring on __init__, Simply inherits methods from GratingStim
        #what local vars are defined (these are the init params) for use by __repr__
        self._initParams = dir()
        self._initParams.remove('self')

        super(RadialStim, self).__init__(win, units=units, name=name, autoLog=False) #autolog should start off false

        self.useShaders = win._haveShaders  #use shaders if available by default, this is a good thing

        # UGLY HACK again. (See same section in GratingStim for ideas)
        self.__dict__['contrast'] = 1
        self.__dict__['size'] = 1
        self.__dict__['sf'] = 1
        self.__dict__['tex'] = tex

        #initialise textures for stimulus
        self._texID = GL.GLuint()
        GL.glGenTextures(1, ctypes.byref(self._texID))
        self._maskID = GL.GLuint()
        GL.glGenTextures(1, ctypes.byref(self._maskID))
        self.__dict__['maskParams'] = maskParams
        self.maskRadialPhase = 0
        self.texRes = texRes #must be power of 2
        self.interpolate = interpolate
        self.rgbPedestal = val2array(rgbPedestal, False, length=3)

        #these are defined by the GratingStim but will just cause confusion here!
        self.setSF = None
        self.setPhase = None

        self.colorSpace=colorSpace
        if rgb!=None:
            logging.warning("Use of rgb arguments to stimuli are deprecated. Please use color and colorSpace args instead")
            self.setColor(rgb, colorSpace='rgb', log=False)
        elif dkl!=None:
            logging.warning("Use of dkl arguments to stimuli are deprecated. Please use color and colorSpace args instead")
            self.setColor(dkl, colorSpace='dkl', log=False)
        elif lms!=None:
            logging.warning("Use of lms arguments to stimuli are deprecated. Please use color and colorSpace args instead")
            self.setColor(lms, colorSpace='lms', log=False)
        else:
            self.setColor(color, log=False)

        self.ori = float(ori)
        self.__dict__['angularRes'] = angularRes
        self.__dict__['radialPhase'] = radialPhase
        self.__dict__['radialCycles'] = radialCycles
        self.__dict__['visibleWedge'] = numpy.array(visibleWedge)
        self.__dict__['angularCycles'] = angularCycles
        self.__dict__['angularPhase'] = angularPhase
        self.pos = numpy.array(pos, float)
        self.depth=depth
        self.__dict__['sf'] = 1
        self.size = val2array(size, False)

        self.tex = tex
        self.mask = mask
        self.contrast = float(contrast)
        self.opacity = float(opacity)

        #
        self._updateEverything()

        # set autoLog now that params have been initialised
        self.__dict__['autoLog'] = autoLog or autoLog is None and self.win.autoLog
        if self.autoLog:
            logging.exp("Created %s = %s" %(self.name, str(self)))
Example #46
0
audioDriver = None

for thisLibName in prefs.general['audioLib']:
    try:
        if thisLibName == 'pyo':
            import pyo
            havePyo = True
        elif thisLibName == 'pygame':
            import pygame
            from pygame import mixer, sndarray
        else:
            raise ValueError(
                "Audio lib options are currently only 'pyo' or 'pygame', not '%s'"
                % thisLibName)
    except:
        logging.warning('%s audio lib was requested but not loaded: %s' %
                        (thisLibName, sys.exc_info()[1]))
        continue  #to try next audio lib
    #if we got this far we were sucessful in loading the lib
    audioLib = thisLibName
    logging.info('sound is using audioLib: %s' % audioLib)
    break

stepsFromA = {
    'C': -9,
    'Csh': -8,
    'Dfl': -8,
    'D': -7,
    'Dsh': -6,
    'Efl': -6,
    'E': -5,
    'F': -4,
Example #47
0
def getProject(filename):
    """Will try to find (locally synced) pavlovia Project for the filename
    """
    if not haveGit:
        raise exceptions.DependencyError(
            "gitpython and a git installation required for getProject()")

    gitRoot = getGitRoot(filename)
    if gitRoot in knownProjects:
        return knownProjects[gitRoot]
    elif gitRoot:
        # Existing repo but not in our knownProjects. Investigate
        logging.info("Investigating repo at {}".format(gitRoot))
        localRepo = git.Repo(gitRoot)
        proj = None
        for remote in localRepo.remotes:
            for url in remote.urls:
                if "gitlab.pavlovia.org" in url:
                    # could be 'https://gitlab.pavlovia.org/NameSpace/Name.git'
                    # or may be '[email protected]:NameSpace/Name.git'
                    namespaceName = url.split('gitlab.pavlovia.org')[1]
                    # remove the first char (: or /)
                    if namespaceName[0] in ['/', ':']:
                        namespaceName = namespaceName[1:]
                    # remove the .git at the end if present
                    namespaceName = namespaceName.replace('.git', '')
                    pavSession = getCurrentSession()
                    if not pavSession.user:
                        nameSpace = namespaceName.split('/')[0]
                        if nameSpace in knownUsers:  # Log in if user is known
                            login(nameSpace, rememberMe=True)
                        else:  # Check whether project repo is found in any of the known users accounts
                            for user in knownUsers:
                                try:
                                    login(user)
                                except requests.exceptions.ConnectionError:
                                    break
                                foundProject = False
                                for repo in pavSession.findUserProjects():
                                    if namespaceName in repo['id']:
                                        foundProject = True
                                        logging.info(
                                            "Logging in as {}".format(user))
                                        break
                                if not foundProject:
                                    logging.warning(
                                        "Could not find {namespace} in your Pavlovia accounts. "
                                        "Logging in as {user}.".format(
                                            namespace=namespaceName,
                                            user=user))
                    if pavSession.user:
                        proj = pavSession.getProject(namespaceName,
                                                     repo=localRepo)
                        if proj.pavlovia and proj.pavlovia.get_id() == 0:
                            logging.warning(
                                _translate(
                                    "We found a repository pointing to {} "
                                    "but no project was found there (deleted?)"
                                ).format(url))
                    else:
                        logging.warning(
                            _translate(
                                "We found a repository pointing to {} "
                                "but no user is logged in for us to check it".
                                format(url)))
                    return proj

        if proj == None:
            logging.warning("We found a repository at {} but it "
                            "doesn't point to gitlab.pavlovia.org. "
                            "You could create that as a remote to "
                            "sync from PsychoPy.".format(gitRoot))
Example #48
0
def init(rate=44100, stereo=True, buffer=128):
    """setup the pyo (sound) server
    """
    global pyoSndServer, Sound, audioDriver, duplex, maxChnls
    Sound = SoundPyo
    global pyo
    try:
        assert pyo
    except NameError:  # pragma: no cover
        import pyo
        # can be needed for microphone.switchOn(), which calls init even
        # if audioLib is something else

    # subclass the pyo.Server so that we can insert a __del__ function that
    # shuts it down skip coverage since the class is never used if we have
    # a recent version of pyo

    class _Server(pyo.Server):  # pragma: no cover
        # make libs class variables so they don't get deleted first
        core = core
        logging = logging

        def __del__(self):
            self.stop()
            # make sure enough time passes for the server to shutdown
            self.core.wait(0.5)
            self.shutdown()
            # make sure enough time passes for the server to shutdown
            self.core.wait(0.5)
            # this may never get printed
            self.logging.debug('pyo sound server shutdown')

    if '.'.join(map(str, pyo.getVersion())) < '0.6.4':
        Server = _Server
    else:
        Server = pyo.Server

    # if we already have a server, just re-initialize it
    if 'pyoSndServer' in globals() and hasattr(pyoSndServer, 'shutdown'):
        pyoSndServer.stop()
        # make sure enough time passes for the server to shutdown
        core.wait(0.5)
        pyoSndServer.shutdown()
        core.wait(0.5)
        pyoSndServer.reinit(sr=rate,
                            nchnls=maxChnls,
                            buffersize=buffer,
                            audio=audioDriver)
        pyoSndServer.boot()
    else:
        if sys.platform == 'win32':
            # check for output device/driver
            #todo: Throwing errors on one users' config https://discourse.psychopy.org/t/error-with-microphone-component-on-psychopy-2020/13168
            devNames, devIDs = get_output_devices()
            audioDriver, outputID = _bestDriver(devNames, devIDs)
            if outputID is None:
                # using the default output because we didn't find the one(s)
                # requested
                audioDriver = 'Windows Default Output'
                outputID = pyo.pa_get_default_output()
            if outputID is not None:
                logging.info(u'Using sound driver: %s (ID=%i)' %
                             (audioDriver, outputID))
                maxOutputChnls = pyo.pa_get_output_max_channels(outputID)
            else:
                logging.warning(
                    'No audio outputs found (no speakers connected?')
                return -1
            # check for valid input (mic)
            # If no input device is available, devNames and devIDs are empty
            # lists.
            devNames, devIDs = get_input_devices()
            audioInputName, inputID = _bestDriver(devNames, devIDs)
            # Input devices were found, but requested devices were not found
            if len(devIDs) > 0 and inputID is None:
                defaultID = pyo.pa_get_default_input()
                if defaultID is not None and defaultID != -1:
                    # default input is found
                    # use the default input because we didn't find the one(s)
                    # requested
                    audioInputName = 'Windows Default Input'
                    inputID = defaultID
                else:
                    # default input is not available
                    inputID = None
            if inputID is not None:
                msg = u'Using sound-input driver: %s (ID=%i)'
                logging.info(msg % (audioInputName, inputID))
                maxInputChnls = pyo.pa_get_input_max_channels(inputID)
                duplex = bool(maxInputChnls > 0)
            else:
                maxInputChnls = 0
                duplex = False
        # for other platforms set duplex to True (if microphone is available)
        else:
            audioDriver = prefs.hardware['audioDriver'][0]
            maxInputChnls = pyo.pa_get_input_max_channels(
                pyo.pa_get_default_input())
            maxOutputChnls = pyo.pa_get_output_max_channels(
                pyo.pa_get_default_output())
            duplex = bool(maxInputChnls > 0)

        maxChnls = min(maxInputChnls, maxOutputChnls)
        if maxInputChnls < 1:  # pragma: no cover
            msg = (u'%s.init could not find microphone hardware; '
                   u'recording not available')
            logging.warning(msg % __name__)
            maxChnls = maxOutputChnls
        if maxOutputChnls < 1:  # pragma: no cover
            msg = (u'%s.init could not find speaker hardware; '
                   u'sound not available')
            logging.error(msg % __name__)
            return -1

        # create the instance of the server:
        if sys.platform == 'darwin' or sys.platform.startswith('linux'):
            # for mac/linux we set the backend using the server audio param
            pyoSndServer = Server(sr=rate,
                                  nchnls=maxChnls,
                                  buffersize=buffer,
                                  audio=audioDriver)
        else:
            # with others we just use portaudio and then set the OutputDevice
            # below
            pyoSndServer = Server(sr=rate, nchnls=maxChnls, buffersize=buffer)

        pyoSndServer.setVerbosity(1)
        if sys.platform == 'win32':
            pyoSndServer.setOutputDevice(outputID)
            if inputID is not None:
                pyoSndServer.setInputDevice(inputID)
        # do other config here as needed (setDuplex? setOutputDevice?)
        pyoSndServer.setDuplex(duplex)
        pyoSndServer.boot()
    core.wait(0.5)  # wait for server to boot before starting the sound stream
    pyoSndServer.start()

    # atexit is filo, will call stop then shutdown upon closing
    atexit.register(pyoSndServer.shutdown)
    atexit.register(pyoSndServer.stop)
    try:
        Sound()  # test creation, no play
    except pyo.PyoServerStateException:
        msg = "Failed to start pyo sound Server"
        if sys.platform == 'darwin' and audioDriver != 'portaudio':
            msg += "; maybe try prefs.general.audioDriver 'portaudio'?"
        logging.error(msg)
        core.quit()
    logging.debug('pyo sound server started')
    logging.flush()
Example #49
0
    def __init__(self,
                 name='',
                 version='',
                 extraInfo=None,
                 runtimeInfo=None,
                 originPath=None,
                 savePickle=True,
                 saveWideText=True,
                 dataFileName='',
                 autoLog=True,
                 appendFiles=False):
        """
        :parameters:

            name : a string or unicode
                As a useful identifier later

            version : usually a string (e.g. '1.1.0')
                To keep track of which version of the experiment was run

            extraInfo : a dictionary
                Containing useful information about this run
                (e.g. {'participant':'jwp','gender':'m','orientation':90} )

            runtimeInfo : :class:`psychopy.info.RunTimeInfo`
                Containing information about the system as detected at
                runtime

            originPath : string or unicode
                The path and filename of the originating script/experiment
                If not provided this will be determined as the path of the
                calling script.

            dataFileName : string
                This is defined in advance and the file will be saved at any
                point that the handler is removed or discarded (unless
                .abort() had been called in advance).
                The handler will attempt to populate the file even in the
                event of a (not too serious) crash!

            savePickle : True (default) or False

            saveWideText : True (default) or False

            autoLog : True (default) or False
        """
        self.loops = []
        self.loopsUnfinished = []
        self.name = name
        self.version = version
        self.runtimeInfo = runtimeInfo
        if extraInfo is None:
            self.extraInfo = {}
        else:
            self.extraInfo = extraInfo
        self.originPath = originPath
        self.savePickle = savePickle
        self.saveWideText = saveWideText
        self.dataFileName = dataFileName
        self.thisEntry = {}
        self.entries = []  # chronological list of entries
        self._paramNamesSoFar = []
        self.dataNames = []  # names of all the data (eg. resp.keys)
        self.autoLog = autoLog
        self.appendFiles = appendFiles

        if dataFileName in ['', None]:
            logging.warning('ExperimentHandler created with no dataFileName'
                            ' parameter. No data will be saved in the event '
                            'of a crash')
        else:
            # fail now if we fail at all!
            checkValidFilePath(dataFileName, makeValid=True)
        atexit.register(self.close)
Example #50
0
audioDriver = None

for thisLibName in prefs.general['audioLib']:
    try:
        if thisLibName == 'pyo':
            import pyo
            havePyo = True
        elif thisLibName == 'pygame':
            import pygame
            from pygame import mixer, sndarray
        else:
            raise ValueError(
                "Audio lib options are currently only 'pyo' or 'pygame', not '%s'"
                % thisLibName)
    except:
        logging.warning('%s audio lib was requested but not loaded: %s' %
                        (thisLibName, sys.exc_info()[1]))
        continue  #to try next audio lib
    #if we got this far we were sucessful in loading the lib
    audioLib = thisLibName
    break

if audioLib == None:
    logging.warning(
        'No audio lib could be loaded. Sounds will not be available.')


class _SoundBase:
    """Create a sound object, from one of many ways.
    """
    def __init__(self,
                 value="C",
Example #51
0
    def __init__(self,
                 win,
                 tex="sin",
                 mask="none",
                 units=None,
                 anchor="center",
                 pos=(0.0, 0.0),
                 size=None,
                 sf=None,
                 ori=0.0,
                 phase=(0.0, 0.0),
                 texRes=128,
                 rgb=None,
                 dkl=None,
                 lms=None,
                 color=(1.0, 1.0, 1.0),
                 colorSpace='rgb',
                 contrast=1.0,
                 opacity=None,
                 depth=0,
                 rgbPedestal=(0.0, 0.0, 0.0),
                 interpolate=False,
                 blendmode='avg',
                 name=None,
                 autoLog=None,
                 autoDraw=False,
                 maskParams=None):
        """ """  # Empty docstring. All doc is in attributes
        # what local vars are defined (these are the init params) for use by
        # __repr__
        self._initParams = dir()
        for unecess in ['self', 'rgb', 'dkl', 'lms']:
            self._initParams.remove(unecess)
        # initialise parent class
        super(GratingStim, self).__init__(win,
                                          units=units,
                                          name=name,
                                          autoLog=False)

        # UGLY HACK: Some parameters depend on each other for processing.
        # They are set "superficially" here.
        # TO DO: postpone calls to _createTexture, setColor and
        # _calcCyclesPerStim whin initiating stimulus
        self.__dict__['contrast'] = 1
        self.__dict__['size'] = 1
        self.__dict__['sf'] = 1
        self.__dict__['tex'] = tex
        self.__dict__['maskParams'] = maskParams

        # initialise textures and masks for stimulus
        self._texID = GL.GLuint()
        GL.glGenTextures(1, ctypes.byref(self._texID))
        self._maskID = GL.GLuint()
        GL.glGenTextures(1, ctypes.byref(self._maskID))
        self.__dict__['texRes'] = texRes  # must be power of 2
        self.interpolate = interpolate

        # NB Pedestal isn't currently being used during rendering - this is a
        # place-holder
        self.rgbPedestal = val2array(rgbPedestal, False, length=3)
        # No need to invoke decorator for color updating. It is done just
        # below.
        self.colorSpace = colorSpace
        self.color = color
        if rgb != None:
            logging.warning("Use of rgb arguments to stimuli are deprecated."
                            " Please use color and colorSpace args instead")
            self.color = Color(rgb, 'rgb')
        elif dkl != None:
            logging.warning("Use of dkl arguments to stimuli are deprecated."
                            " Please use color and colorSpace args instead")
            self.color = Color(dkl, 'dkl')
        elif lms != None:
            logging.warning("Use of lms arguments to stimuli are deprecated."
                            " Please use color and colorSpace args instead")
            self.color = Color(lms, 'lms')

        # set other parameters
        self.ori = float(ori)
        self.phase = val2array(phase, False)
        self._origSize = None  # updated if an image texture is loaded
        self._requestedSize = size
        self.size = size
        self.sf = val2array(sf)
        self.pos = val2array(pos, False, False)
        self.depth = depth
        self.anchor = anchor

        self.tex = tex
        self.mask = mask
        self.contrast = float(contrast)
        self.opacity = opacity
        self.autoLog = autoLog
        self.autoDraw = autoDraw
        self.blendmode = blendmode

        # fix scaling to window coords
        self._calcCyclesPerStim()

        # generate a displaylist ID
        self._listID = GL.glGenLists(1)

        # JRG: doing self._updateList() here means MRO issues for RadialStim,
        # which inherits from GratingStim but has its own _updateList code.
        # So don't want to do the update here (= ALSO the init of RadialStim).
        # Could potentially define a BaseGrating class without
        # updateListShaders code, and have GratingStim and RadialStim
        # inherit from it and add their own _updateList stuff.
        # Seems unnecessary. Instead, simply defer the update to the
        # first .draw(), should be fast:
        # self._updateList()  # ie refresh display list
        self._needUpdate = True

        # set autoLog now that params have been initialised
        wantLog = autoLog is None and self.win.autoLog
        self.__dict__['autoLog'] = autoLog or wantLog
        if self.autoLog:
            logging.exp("Created {} = {}".format(self.name, self))
Example #52
0
def getKeys(keyList=None, modifiers=False, timeStamped=False):
    """Returns a list of keys that were pressed.

    :Parameters:
        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.

    :Author:
        - 2003 written by Jon Peirce
        - 2009 keyList functionality added by Gary Strangman
        - 2009 timeStamped code provided by Dave Britton
        - 2016 modifiers code provided by 5AM Solutions
    """
    keys = []

    if havePygame and display.get_init():
        # see if pygame has anything instead (if it exists)
        windowSystem = 'pygame'
        for evts in evt.get(locals.KEYDOWN):
            # pygame has no keytimes
            keys.append((pygame.key.name(evts.key), 0))
    elif havePyglet:
        # for each (pyglet) window, dispatch its events before checking event
        # buffer
        windowSystem = 'pyglet'
        for win in _default_display_.get_windows():
            try:
                win.dispatch_events()  # pump events on pyglet windows
            except ValueError as e:  # pragma: no cover
                # Pressing special keys, such as 'volume-up', results in a
                # ValueError. This appears to be a bug in pyglet, and may be
                # specific to certain systems and versions of Python.
                logging.error(u'Failed to handle keypress')

        global _keyBuffer
        if len(_keyBuffer) > 0:
            # then pyglet is running - just use this
            keys = _keyBuffer
            # _keyBuffer = []  # DO /NOT/ CLEAR THE KEY BUFFER ENTIRELY

    elif haveGLFW:
        windowSystem = 'glfw'
        # 'poll_events' is called when a window is flipped, all the callbacks
        # populate the buffer
        if len(_keyBuffer) > 0:
            keys = _keyBuffer

    if keyList is None:
        _keyBuffer = []  # clear buffer entirely
        targets = keys  # equivalent behavior to getKeys()
    else:
        nontargets = []
        targets = []
        # split keys into keepers and pass-thrus
        for key in keys:
            if key[0] in keyList:
                targets.append(key)
            else:
                nontargets.append(key)
        _keyBuffer = nontargets  # save these

    # now we have a list of tuples called targets
    # did the user want timestamped tuples or keynames?
    if modifiers == False and timeStamped == False:
        keyNames = [k[0] for k in targets]
        return keyNames
    elif timeStamped == False:
        keyNames = [(k[0], modifiers_dict(k[1])) for k in targets]
        return keyNames
    elif timeStamped and windowSystem == 'pygame':
        # provide a warning and set timestamps to be None
        logging.warning(
            'Pygame keyboard events do not support timestamped=True')
        relTuple = [[
            _f
            for _f in (k[0], modifiers and modifiers_dict(k[1]) or None, None)
            if _f
        ] for k in targets]
        return relTuple
    elif hasattr(timeStamped, 'getLastResetTime'):
        # keys were originally time-stamped with
        #   core.monotonicClock._lastResetTime
        # we need to shift that by the difference between it and
        # our custom clock
        _last = timeStamped.getLastResetTime()
        _clockLast = psychopy.core.monotonicClock.getLastResetTime()
        timeBaseDiff = _last - _clockLast
        relTuple = [[
            _f for _f in (k[0], modifiers and modifiers_dict(k[1]) or None,
                          k[-1] - timeBaseDiff) if _f
        ] for k in targets]
        return relTuple
    elif timeStamped is True:
        return [[
            _f
            for _f in (k[0], modifiers and modifiers_dict(k[1]) or None, k[-1])
            if _f
        ] for k in targets]
    elif isinstance(timeStamped, (float, int, int)):
        relTuple = [[
            _f for _f in (k[0], modifiers and modifiers_dict(k[1]) or None,
                          k[-1] - timeStamped) if _f
        ] for k in targets]
        return relTuple
    else:  ## danger - catch anything that gets here because it shouldn't!
        raise ValueError("We received an unknown combination of params to "
                         "getKeys(): timestamped={}, windowSystem={}, "
                         "modifiers={}".format(timeStamped, windowSystem,
                                               modifiers))
Example #53
0
    def __init__(self,
                 win,
                 contrast=1.0,
                 gamma=None,
                 nEntries=256,
                 mode='bits++',
                 rampType='configFile'):
        """
        :Parameters:

            contrast :
                The contrast to be applied to the LUT.
                See :func:`BitsPlusPlus.setLUT` and
                :func:`BitsPlusPlus.setContrast` for flexibility on setting
                just a section of the LUT to a different value

            gamma :
                The value used to correct the gamma in the LUT

            nEntries : 256
                [DEPRECATED feature]

            mode : 'bits++' (or 'mono++' or 'color++')
                Note that, unlike the Bits#, this only affects the way the
                window is rendered, it does not switch the state of the Bits++
                device itself (because unlike the Bits# have no way to
                communicate with it).
                The mono++ and color++ are only supported in PsychoPy 1.82.00
                onwards. Even then they suffer from not having gamma
                correction applied on Bits++ (unlike Bits# which can apply
                a gamma table in the device hardware).

            rampType : 'configFile', None or an integer
                if 'configFile' then we'll look for a valid config in the
                userPrefs folder if an integer then this will be used during
                win.setGamma(rampType=rampType):
        """
        self.win = win
        self.contrast = contrast
        self.nEntries = nEntries
        self.mode = mode
        # used to allow setting via USB which was 'slow':
        self.method = 'fast'
        # Bits++ doesn't do its own correction so we need to:
        self.gammaCorrect = 'software'

        # import pyglet.GL late so that we can import bits.py without it
        # initially
        global GL, visual
        from psychopy import visual
        import pyglet.gl as GL

        if self.gammaCorrect == 'software':
            if gamma is None:
                # inherit from window:
                self.gamma = win.gamma
            elif len(gamma) > 2:
                # [Lum,R,G,B] or [R,G,B]
                self.gamma = gamma[-3:]
            else:
                self.gamma = [gamma, gamma, gamma]
        if init():
            setVideoMode(NOGAMMACORRECT | VIDEOENCODEDCOMMS)
            self.initialised = True
            logging.debug('Found and initialised Bits++')
        else:
            self.initialised = False
            logging.warning("Couldn't initialise Bits++")

        # do the processing
        self._HEADandLUT = np.zeros((524, 1, 3), np.uint8)
        # R:
        valsR = (36, 63, 8, 211, 3, 112, 56, 34, 0, 0, 0, 0)
        self._HEADandLUT[:12, :, 0] = np.asarray(valsR).reshape([12, 1])
        # G:
        valsG = (106, 136, 19, 25, 115, 68, 41, 159, 0, 0, 0, 0)
        self._HEADandLUT[:12, :, 1] = np.asarray(valsG).reshape([12, 1])
        # B:
        valsB = (133, 163, 138, 46, 164, 9, 49, 208, 0, 0, 0, 0)
        self._HEADandLUT[:12, :, 2] = np.asarray(valsB).reshape([12, 1])

        self.LUT = np.zeros((256, 3), 'd')  # just a place holder
        self.setLUT()  # this will set self.LUT and update self._LUTandHEAD
        self._setupShaders()
        # replace window methods with our custom ones
        self.win._prepareFBOrender = self._prepareFBOrender
        self.win._finishFBOrender = self._finishFBOrender
        self.win._afterFBOrender = self._afterFBOrender
        # set gamma of the window to the identity LUT
        if rampType == 'configFile':
            # now check that we have a valid configuration of the box
            self.config = Config(self)
            # check we matche the prev config for our graphics card etc
            ok = False  # until we find otherwise
            ok = self.config.quickCheck()
            if ok:
                self.win.gammaRamp = self.config.identityLUT
            else:
                rampType = None
        if not rampType == 'configFile':
            # 'this must NOT be an `else` from the above `if` because can be
            # overidden possibly we were given a numerical rampType (as in
            # the :func:`psychopy.gamma.setGamma()`)
            self.win.winHandle.setGamma(self.win.winHandle, rampType=rampType)
Example #54
0
    def __init__(self,
                 win,
                 units='',
                 lineWidth=1.5,
                 lineColor=(1.0, 1.0, 1.0),
                 lineColorSpace='rgb',
                 fillColor=None,
                 fillColorSpace='rgb',
                 vertices=((-0.5, 0), (0, +0.5), (+0.5, 0)),
                 closeShape=True,
                 pos=(0, 0),
                 size=1,
                 ori=0.0,
                 opacity=1.0,
                 contrast=1.0,
                 depth=0,
                 interpolate=True,
                 lineRGB=None,
                 fillRGB=None,
                 name=None,
                 autoLog=None,
                 autoDraw=False,
                 color=None,
                 colorSpace=None):
        """ """  # all doc is in the attributes
        # what local vars are defined (these are the init params) for use by
        # __repr__
        self._initParams = dir()
        self._initParams.remove('self')

        # Initialize inheritance and remove unwanted methods; autoLog is set
        # later
        super(BaseShapeStim, self).__init__(win,
                                            units=units,
                                            name=name,
                                            autoLog=False)

        self.contrast = float(contrast)
        self.opacity = float(opacity)
        self.pos = numpy.array(pos, float)
        self.closeShape = closeShape
        self.lineWidth = lineWidth
        self.interpolate = interpolate

        # Color stuff
        self.useShaders = False  # don't need to combine textures with colors
        # set color first but then potentially override
        self.__dict__['colorSpace'] = colorSpace
        self.__dict__['lineColorSpace'] = lineColorSpace
        self.__dict__['fillColorSpace'] = fillColorSpace

        if lineRGB is not None:
            logging.warning("Use of rgb arguments to stimuli are deprecated."
                            " Please use color and colorSpace args instead")
            self.setLineColor(lineRGB, colorSpace='rgb', log=None)
        elif color is not None and lineColor is None:
            pass  # user has set color but not lineColor. Don't override that
        else:
            self.setLineColor(lineColor, colorSpace=lineColorSpace, log=None)

        if fillRGB is not None:
            logging.warning("Use of rgb arguments to stimuli are deprecated."
                            " Please use color and colorSpace args instead")
            self.setFillColor(fillRGB, colorSpace='rgb', log=None)
        elif color is not None and fillColor is None:
            pass  # user has set color but not fillColor. Don't override that
        else:
            self.setFillColor(fillColor, colorSpace=fillColorSpace, log=None)

        # if the fillColor and lineColor are not set but color is
        # then the user probably wants color applied to both
        if (lineColor is (1.0, 1.0, 1.0)  # check if exactly as the default arg
                and fillColor is None and color is not None):
            self.color = color
        else:
            self.fillColor = fillColor
            self.lineColor = lineColor

        # Other stuff
        self.depth = depth
        self.ori = numpy.array(ori, float)
        self.size = numpy.array([0.0, 0.0]) + size  # make sure that it's 2D
        if vertices != ():  # flag for when super-init'ing a ShapeStim
            self.vertices = vertices  # call attributeSetter
        self.autoDraw = autoDraw  # call attributeSetter

        # set autoLog now that params have been initialised
        wantLog = autoLog is None and self.win.autoLog
        self.__dict__['autoLog'] = autoLog or wantLog
        if self.autoLog:
            logging.exp("Created %s = %s" % (self.name, str(self)))
Example #55
0
    def setLUT(self, newLUT=None, gammaCorrect=True, LUTrange=1.0):
        """Sets the LUT to a specific range of values in 'bits++' mode only

        Note that, if you leave gammaCorrect=True then any LUT values you
        supply will automatically be gamma corrected.

        The LUT will take effect on the next `Window.flip()`

        **Examples:**
            ``bitsBox.setLUT()``
                builds a LUT using bitsBox.contrast and bitsBox.gamma

            ``bitsBox.setLUT(newLUT=some256x1array)``
                (NB array should be float 0.0:1.0)
                Builds a luminance LUT using newLUT for each gun
                (actually array can be 256x1 or 1x256)

            ``bitsBox.setLUT(newLUT=some256x3array)``
               (NB array should be float 0.0:1.0)
               Allows you to use a different LUT on each gun

        (NB by using BitsBox.setContr() and BitsBox.setGamma() users may not
        need this function)
        """

        # choose endpoints
        LUTrange = np.asarray(LUTrange)
        if LUTrange.size == 1:
            startII = int(round((0.5 - LUTrange / 2.0) * 255.0))
            # +1 because python ranges exclude last value:
            endII = int(round((0.5 + LUTrange / 2.0) * 255.0)) + 1
        elif LUTrange.size == 2:
            multiplier = 1.0
            if LUTrange[1] <= 1:
                multiplier = 255.0
            startII = int(round(LUTrange[0] * multiplier))
            # +1 because python ranges exclude last value:
            endII = int(round(LUTrange[1] * multiplier)) + 1
        stepLength = 2.0 / (endII - startII - 1)

        if newLUT is None:
            # create a LUT from scratch (based on contrast and gamma)
            # rampStep = 2.0/(self.nEntries-1)
            ramp = np.arange(-1.0, 1.0 + stepLength, stepLength)
            ramp = (ramp * self.contrast + 1.0) / 2.0
            # self.LUT will be stored as 0.0:1.0 (gamma-corrected)
            self.LUT[startII:endII, 0] = copy(ramp)
            self.LUT[startII:endII, 1] = copy(ramp)
            self.LUT[startII:endII, 2] = copy(ramp)
        elif type(newLUT) in [float, int] or (newLUT.shape == ()):
            self.LUT[startII:endII, 0] = newLUT
            self.LUT[startII:endII, 1] = newLUT
            self.LUT[startII:endII, 2] = newLUT
        elif len(newLUT.shape) == 1:
            # one dimensional LUT
            # replicate LUT to other channels, check range is 0:1
            if newLUT > 1.0:
                logging.warning('newLUT should be float in range 0.0:1.0')
            self.LUT[startII:endII, 0] = copy(newLUT.flat)
            self.LUT[startII:endII, 1] = copy(newLUT.flat)
            self.LUT[startII:endII, 2] = copy(newLUT.flat)

        elif len(newLUT.shape) == 2:
            # one dimensional LUT
            # use LUT as is, check range is 0:1
            if max(max(newLUT)) > 1.0:
                raise AttributeError('newLUT should be float in range 0.0:1.0')
            self.LUT[startII:endII, :] = newLUT

        else:
            logging.warning('newLUT can be None, nx1 or nx3')

        # do gamma correction if necessary
        if self.gammaCorrect == 'software':
            gamma = self.gamma

            try:
                lin = self.win.monitor.linearizeLums
                self.LUT[startII:endII, :] = lin(self.LUT[startII:endII, :],
                                                 overrideGamma=gamma)
            except AttributeError:
                try:
                    lin = self.win.monitor.lineariseLums
                    self.LUT[startII:endII, :] = lin(
                        self.LUT[startII:endII, :], overrideGamma=gamma)
                except AttributeError:
                    pass

        # update the bits++ box with new LUT
        # get bits into correct order, shape and add to header
        # go from ubyte to uint16
        ramp16 = (self.LUT * (2**16 - 1)).astype(np.uint16)
        ramp16 = np.reshape(ramp16, (256, 1, 3))
        # set most significant bits
        self._HEADandLUT[12::2, :, :] = (ramp16[:, :, :] >> 8).astype(np.uint8)
        # set least significant bits
        self._HEADandLUT[13::2, :, :] = (ramp16[:, :, :] & 255).astype(
            np.uint8)
        self._HEADandLUTstr = self._HEADandLUT.tostring()
Example #56
0
def compareTextFiles(pathToActual,
                     pathToCorrect,
                     delim=None,
                     encoding='utf-8-sig',
                     tolerance=None):
    """Compare the text of two files, ignoring EOL differences,
    and save a copy if they differ

    State a tolerance, or percentage of errors allowed,
    to account for differences in version numbers, datetime, etc
    """

    if not os.path.isfile(pathToCorrect):
        logging.warning(
            'There was no comparison ("correct") file available, for path "{pathToActual}"\n'
            '\t\t\tSaving current file as the comparison: {pathToCorrect}'.
            format(pathToActual=pathToActual, pathToCorrect=pathToCorrect))
        shutil.copyfile(pathToActual, pathToCorrect)
        raise IOError(
            "File not found"
        )  # deliberately raise an error to see the warning message, but also to create file

    allowLines = 0
    nLinesMatch = True

    if delim is None:
        if pathToCorrect.endswith('.csv'):
            delim = ','
        elif pathToCorrect.endswith(('.dlm', '.tsv')):
            delim = '\t'

    try:
        # we have the necessary file
        with io.open(pathToActual, 'r', encoding='utf-8-sig',
                     newline=None) as f:
            txtActual = f.readlines()

        with io.open(pathToCorrect, 'r', encoding='utf-8-sig',
                     newline=None) as f:
            txtCorrect = f.readlines()

        if tolerance is not None:
            # Set number of lines allowed to fail
            allowLines = round((tolerance * len(txtCorrect)) / 100, 0)

        # Check number of lines per document for equality
        nLinesMatch = len(txtActual) == len(txtCorrect)
        assert nLinesMatch
        errLines = []

        for lineN in range(len(txtActual)):
            if delim is None:
                lineActual = txtActual[lineN]
                lineCorrect = txtCorrect[lineN]

                # just compare the entire line
                if not lineActual == lineCorrect:
                    errLines.append({
                        'actual': lineActual,
                        'correct': lineCorrect
                    })
                assert len(errLines) <= allowLines

            else:  # word by word instead
                lineActual = txtActual[lineN].split(delim)
                lineCorrect = txtCorrect[lineN].split(delim)

                for wordN in range(len(lineActual)):
                    wordActual = lineActual[wordN]
                    wordCorrect = lineCorrect[wordN]
                    try:
                        wordActual = float(wordActual.lstrip('"[').strip(']"'))
                        wordCorrect = float(
                            wordCorrect.lstrip('"[').strip(']"'))
                        # its not a whole well-formed list because .split(delim)
                        isFloat = True
                    except Exception:  #stick with simple text if not a float value
                        isFloat = False
                        pass
                    if isFloat:
                        #to a default of 8 dp?
                        assert np.allclose(wordActual,wordCorrect), "Numeric values at (%i,%i) differ: %f != %f " \
                            %(lineN, wordN, wordActual, wordCorrect)
                    else:
                        if wordActual != wordCorrect:
                            print('actual:')
                            print(repr(txtActual[lineN]))
                            print(lineActual)
                            print('expected:')
                            print(repr(txtCorrect[lineN]))
                            print(lineCorrect)
                        assert wordActual==wordCorrect, "Values at (%i,%i) differ: %s != %s " \
                            %(lineN, wordN, repr(wordActual), repr(wordCorrect))

    except AssertionError as err:
        pathToLocal, ext = os.path.splitext(pathToCorrect)
        pathToLocal = pathToLocal + '_local' + ext

        # Set assertion type
        if not nLinesMatch:  # Fail if number of lines not equal
            msg = "{} has the wrong number of lines".format(pathToActual)
        elif len(errLines) < allowLines:  # Fail if tolerance reached
            msg = 'Number of differences in {failed} exceeds the {tol}% tolerance'.format(
                failed=pathToActual, tol=tolerance or 0)
        else:
            shutil.copyfile(pathToActual, pathToLocal)
            msg = "txtActual != txtCorr: Saving local copy to {}".format(
                pathToLocal)
        logging.error(msg)
        raise AssertionError(err)
Example #57
0
    def __init__(self,
                 win,
                 text="Hello World",
                 font="",
                 pos=(0.0, 0.0),
                 depth=0,
                 rgb=None,
                 color=(1.0, 1.0, 1.0),
                 colorSpace='rgb',
                 opacity=1.0,
                 contrast=1.0,
                 units="",
                 ori=0.0,
                 height=None,
                 antialias=True,
                 bold=False,
                 italic=False,
                 alignHoriz=None,
                 alignVert=None,
                 alignText='center',
                 anchorHoriz='center',
                 anchorVert='center',
                 fontFiles=(),
                 wrapWidth=None,
                 flipHoriz=False,
                 flipVert=False,
                 languageStyle='LTR',
                 name=None,
                 autoLog=None):
        """
        **Performance OBS:** in general, TextStim is slower than many other
        visual stimuli, i.e. it takes longer to change some attributes.
        In general, it's the attributes that affect the shapes of the letters:
        ``text``, ``height``, ``font``, ``bold`` etc.
        These make the next .draw() slower because that sets the text again.
        You can make the draw() quick by calling re-setting the text
        (``myTextStim.text = myTextStim.text``) when you've changed the
        parameters.

        In general, other attributes which merely affect the presentation of
        unchanged shapes are as fast as usual. This includes ``pos``,
        ``opacity`` etc.

        The following attribute can only be set at initialization (see
        further down for a list of attributes which can be changed after
        initialization):

        **languageStyle**
            Apply settings to correctly display content from some languages
            that are written right-to-left. Currently there are three (case-
            insensitive) values for this parameter:

            - ``'LTR'`` is the default, for typical left-to-right, Latin-style
                languages.
            - ``'RTL'`` will correctly display text in right-to-left languages
                such as Hebrew. By applying the bidirectional algorithm, it
                allows mixing portions of left-to-right content (such as numbers
                or Latin script) within the string.
            - ``'Arabic'`` applies the bidirectional algorithm but additionally
                will _reshape_ Arabic characters so they appear in the cursive,
                linked form that depends on neighbouring characters, rather than
                in their isolated form. May also be applied in other scripts,
                such as Farsi or Urdu, that use Arabic-style alphabets.

        :Parameters:

        """

        # what local vars are defined (these are the init params) for use by
        # __repr__
        self._initParams = dir()
        self._initParams.remove('self')
        """
        October 2018:
            In place to remove the deprecation warning for pyglet.font.Text.
            Temporary fix until pyglet.text.Label use is identical to pyglet.font.Text.
        """
        warnings.filterwarnings(message='.*text.Label*', action='ignore')

        super(TextStim, self).__init__(win,
                                       units=units,
                                       name=name,
                                       autoLog=False)

        if win.blendMode == 'add':
            logging.warning("Pyglet text does not honor the Window setting "
                            "`blendMode='add'` so 'avg' will be used for the "
                            "text (but objects drawn after can be added)")
        self._needUpdate = True
        self._needVertexUpdate = True
        # use shaders if available by default, this is a good thing
        self.__dict__['useShaders'] = win._haveShaders
        self.__dict__['antialias'] = antialias
        self.__dict__['font'] = font
        self.__dict__['bold'] = bold
        self.__dict__['italic'] = italic
        # NB just a placeholder - real value set below
        self.__dict__['text'] = ''
        self.__dict__['depth'] = depth
        self.__dict__['ori'] = ori
        self.__dict__['flipHoriz'] = flipHoriz
        self.__dict__['flipVert'] = flipVert
        self.__dict__['languageStyle'] = languageStyle
        self._pygletTextObj = None
        self.__dict__['pos'] = numpy.array(pos, float)
        # deprecated attributes
        if alignVert:
            self.__dict__['alignVert'] = alignVert
            logging.warning("TextStim.alignVert is deprecated. Use the "
                            "anchorVert attribute instead")
            # for compatibility, alignText was historically 'left'
            anchorVert = alignHoriz
        if alignHoriz:
            self.__dict__['alignHoriz'] = alignHoriz
            logging.warning("TextStim.alignHoriz is deprecated. Use alignText "
                            "and anchorHoriz attributes instead")
            # for compatibility, alignText was historically 'left'
            alignText, anchorHoriz = alignHoriz, alignHoriz
        # alignment and anchors
        self.alignText = alignText
        self.anchorHoriz = anchorHoriz
        self.anchorVert = anchorVert

        # generate the texture and list holders
        self._listID = GL.glGenLists(1)
        # pygame text needs a surface to render to:
        if not self.win.winType in ["pyglet", "glfw"]:
            self._texID = GL.GLuint()
            GL.glGenTextures(1, ctypes.byref(self._texID))

        # Color stuff
        self.colorSpace = colorSpace
        if rgb != None:
            msg = ("Use of rgb arguments to stimuli are deprecated. Please "
                   "use color and colorSpace args instead")
            logging.warning(msg)
            self.setColor(rgb, colorSpace='rgb', log=False)
        else:
            self.setColor(color, log=False)

        self.__dict__['fontFiles'] = []
        self.fontFiles = list(fontFiles)  # calls attributeSetter
        self.setHeight(height, log=False)  # calls setFont() at some point
        # calls attributeSetter without log
        setAttribute(self, 'wrapWidth', wrapWidth, log=False)
        self.__dict__['opacity'] = float(opacity)
        self.__dict__['contrast'] = float(contrast)
        # self.width and self._fontHeightPix get set with text and
        # calcSizeRendered is called
        self.setText(text, log=False)
        self._needUpdate = True

        # set autoLog now that params have been initialised
        wantLog = autoLog is None and self.win.autoLog
        self.__dict__['autoLog'] = autoLog or wantLog
        if self.autoLog:
            logging.exp("Created %s = %s" % (self.name, str(self)))
Example #58
0
    def __init__(self,
                 win=None,
                 portName=None,
                 mode='',
                 checkConfigLevel=1,
                 gammaCorrect='hardware',
                 gamma=None,
                 noComms=False):
        """
        :Parameters:

            win : a PsychoPy :class:`~psychopy.visual.Window` object, required

            portName : the (virtual) serial port to which the device is
                connected. If None then PsychoPy will search available
                serial ports and test communication (on OSX, the first
                match of `/dev/tty.usbmodemfa*` will be used and on
                linux `/dev/ttyS0` will be used

            mode : 'bits++', 'color++', 'mono++', 'status'

            checkConfigLevel : integer
                Allows you to specify how much checking of the device is
                done to ensure a valid identity look-up table. If you specify
                one level and it fails then the check will be escalated to
                the next level (e.g. if we check level 1 and find that it
                fails we try to find a new LUT):

                    - 0 don't check at all
                    - 1 check that the graphics driver and OS version haven't
                        changed since last LUT calibration
                    - 2 check that the current LUT calibration still provides
                        identity (requires switch to status mode)
                    - 3 search for a new identity look-up table (requires
                        switch to status mode)

            gammaCorrect : string governing how gamma correction is performed
                'hardware': use the gamma correction file stored on the
                    hardware
                'FBO': gamma correct using shaders when rendering the FBO
                    to back buffer
                'bitsMode': in bits++ mode there is a user-controlled LUT
                    that we can use for gamma correction

            noComms : bool
                If True then don't try to communicate with the device at all
                (passive mode). This can be useful if you want to debug the
                system without actually having a Bits# connected.

        """

        # import pyglet.GL late so that we can import bits.py without it
        # initially
        global GL, visual
        from psychopy import visual
        import pyglet.gl as GL

        if noComms:
            self.noComms = True
            self.OK = True
            self.sendMessage = self._nullSendMessage
            self.getResponse = self._nullGetResponse
        else:
            self.noComms = False
            # look for device on valid serial ports
            # parity="N",  # 'N'one, 'E'ven, 'O'dd, 'M'ask,
            serialdevice.SerialDevice.__init__(self,
                                               port=portName,
                                               baudrate=19200,
                                               byteSize=8,
                                               stopBits=1,
                                               parity="N",
                                               eol='\n',
                                               maxAttempts=1,
                                               pauseDuration=0.1,
                                               checkAwake=True)
        if not self.OK:
            return

        # the following are used by bits++ mode
        self._HEADandLUT = np.zeros((524, 1, 3), np.uint8)
        # R
        valsR = (36, 63, 8, 211, 3, 112, 56, 34, 0, 0, 0, 0)
        self._HEADandLUT[:12, :, 0] = np.asarray(valsR).reshape([12, 1])
        # G
        valsG = (106, 136, 19, 25, 115, 68, 41, 159, 0, 0, 0, 0)
        self._HEADandLUT[:12, :, 1] = np.asarray(valsG).reshape([12, 1])
        # B
        valsB = (133, 163, 138, 46, 164, 9, 49, 208, 0, 0, 0, 0)
        self._HEADandLUT[:12, :, 2] = np.asarray(valsB).reshape([12, 1])
        self.LUT = np.zeros((256, 3), 'd')  # just a place holder

        # replace window methods with our custom ones
        self.win = win
        self.win._prepareFBOrender = self._prepareFBOrender
        self.win._finishFBOrender = self._finishFBOrender
        self.win._afterFBOrender = self._afterFBOrender

        # Bits++ doesn't do its own correction so we need to
        self.gammaCorrect = gammaCorrect
        self.gamma = gamma
        # we have a confirmed connection. Now check details about device and
        # system
        if not hasattr(self, 'info'):
            self.info = self.getInfo()
        self.config = None
        self.mode = mode
        if self.win is not None:
            if not hasattr(self.win, '_prepareFBOrender'):
                logging.error("BitsSharp was given an object as win "
                              "argument but this is not a visual.Window")
            self.win._prepareFBOrender = self._prepareFBOrender
            self.win._finishFBOrender = self._finishFBOrender
            self._setupShaders()
            # now check that we have a valid configuration of the box
            if checkConfigLevel:
                ok = self.checkConfig(level=checkConfigLevel)
            else:
                self.win.gammaRamp = self.config.identityLUT
        else:
            self.config = None  # makes no sense if we have a window?
            logging.warning("%s was not given any PsychoPy win" % (self))
Example #59
0
    def font(self, font):
        """String. Set the font to be used for text rendering. font should
        be a string specifying the name of the font (in system resources).
        """
        self.__dict__['font'] = None  # until we find one
        if self.win.winType in ["pyglet", "glfw"]:
            self._font = pyglet.font.load(font,
                                          int(self._heightPix),
                                          dpi=72,
                                          italic=self.italic,
                                          bold=self.bold)
            self.__dict__['font'] = font
        else:
            if font is None or len(font) == 0:
                self.__dict__['font'] = pygame.font.get_default_font()
            elif font in pygame.font.get_fonts():
                self.__dict__['font'] = font
            elif type(font) == str:
                # try to find a xxx.ttf file for it
                # check for possible matching filenames
                fontFilenames = glob.glob(font + '*')
                if len(fontFilenames) > 0:
                    for thisFont in fontFilenames:
                        if thisFont[-4:] in ['.TTF', '.ttf']:
                            # take the first match
                            self.__dict__['font'] = thisFont
                            break  # stop at the first one we find
                    # trhen check if we were successful
                    if self.font is None and font != "":
                        # we didn't find a ttf filename
                        msg = ("Found %s but it doesn't end .ttf. "
                               "Using default font.")
                        logging.warning(msg % fontFilenames[0])
                        self.__dict__['font'] = pygame.font.get_default_font()

            if self.font is not None and os.path.isfile(self.font):
                self._font = pygame.font.Font(self.font,
                                              int(self._heightPix),
                                              italic=self.italic,
                                              bold=self.bold)
            else:
                try:
                    self._font = pygame.font.SysFont(self.font,
                                                     int(self._heightPix),
                                                     italic=self.italic,
                                                     bold=self.bold)
                    self.__dict__['font'] = font
                    logging.info('using sysFont ' + str(font))
                except Exception:
                    self.__dict__['font'] = pygame.font.get_default_font()
                    msg = ("Couldn't find font %s on the system. Using %s "
                           "instead! Font names should be written as "
                           "concatenated names all in lower case.\ne.g. "
                           "'arial', 'monotypecorsiva', 'rockwellextra', ...")
                    logging.error(msg % (font, self.font))
                    self._font = pygame.font.SysFont(self.font,
                                                     int(self._heightPix),
                                                     italic=self.italic,
                                                     bold=self.bold)
        # re-render text after a font change
        self._needSetText = True
Example #60
0
    def _setWindowInfo(self,
                       win,
                       verbose=False,
                       refreshTest='grating',
                       usingTempWin=True):
        """find and store info about the window: refresh rate, configuration info
        """

        if refreshTest in ['grating', True]:
            msPFavg, msPFstd, msPFmd6 = visual.getMsPerFrame(
                win, nFrames=120, showVisual=bool(refreshTest == 'grating'))
            self['windowRefreshTimeAvg_ms'] = msPFavg
            self['windowRefreshTimeMedian_ms'] = msPFmd6
            self['windowRefreshTimeSD_ms'] = msPFstd
        if usingTempWin:
            return

        # These 'configuration lists' control what attributes are reported.
        # All desired attributes/properties need a legal internal name, e.g., win.winType.
        # If an attr is callable, its gets called with no arguments, e.g., win.monitor.getWidth()
        winAttrList = [
            'winType', '_isFullScr', 'units', 'monitor', 'pos', 'screen',
            'rgb', 'size'
        ]
        winAttrListVerbose = [
            'allowGUI', 'useNativeGamma', 'recordFrameIntervals',
            'waitBlanking', '_haveShaders', '_refreshThreshold'
        ]
        if verbose: winAttrList += winAttrListVerbose

        monAttrList = ['name', 'getDistance', 'getWidth', 'currentCalibName']
        monAttrListVerbose = [
            'getGammaGrid', 'getLinearizeMethod', '_gammaInterpolator',
            '_gammaInterpolator2'
        ]
        if verbose:
            monAttrList += monAttrListVerbose
        if 'monitor' in winAttrList:  # replace 'monitor' with all desired monitor.<attribute>
            i = winAttrList.index(
                'monitor'
            )  # retain list-position info, put monitor stuff there
            del winAttrList[i]
            for monAttr in monAttrList:
                winAttrList.insert(i, 'monitor.' + monAttr)
                i += 1
        for winAttr in winAttrList:
            try:
                attrValue = eval('win.' + winAttr)
            except AttributeError:
                logging.warning(
                    'AttributeError in RuntimeInfo._setWindowInfo(): Window instance has no attribute',
                    winAttr)
                continue
            if hasattr(attrValue, '__call__'):
                try:
                    a = attrValue()
                    attrValue = a
                except:
                    print('Warning: could not get a value from win.' +
                          winAttr + '()  (expects arguments?)')
                    continue
            while winAttr[0] == '_':
                winAttr = winAttr[1:]
            winAttr = winAttr[0].capitalize() + winAttr[1:]
            winAttr = winAttr.replace('Monitor._', 'Monitor.')
            if winAttr in ['Pos', 'Size']:
                winAttr += '_pix'
            if winAttr in ['Monitor.getWidth', 'Monitor.getDistance']:
                winAttr += '_cm'
            if winAttr in ['RefreshThreshold']:
                winAttr += '_sec'
            self['window' + winAttr] = attrValue