def image(self, filename): """Filename, including relative or absolute path. The image can be any format that the Python Imaging Library can import (almost any). Can also be an image already loaded by PIL. """ filename = pathToString(filename) self.__dict__['image'] = filename if isinstance(filename, basestring): # is a string - see if it points to a file if os.path.isfile(filename): self.filename = filename im = Image.open(self.filename) im = im.transpose(Image.FLIP_TOP_BOTTOM) else: logging.error("couldn't find image...%s" % filename) core.quit() else: # not a string - have we been passed an image? try: im = filename.copy().transpose(Image.FLIP_TOP_BOTTOM) except AttributeError: # apparently not an image logging.error("couldn't find image...%s" % filename) core.quit() self.filename = repr(filename) # '<Image.Image image ...>' self.size = im.size # set correct formats for bytes/floats if im.mode == 'RGBA': self.imArray = numpy.array(im).astype(numpy.ubyte) self.internalFormat = GL.GL_RGBA else: self.imArray = numpy.array(im.convert("RGB")).astype(numpy.ubyte) self.internalFormat = GL.GL_RGB self.dataType = GL.GL_UNSIGNED_BYTE self._needStrUpdate = True
def flac2wav(path, keep=True): """Uncompress: convert .flac file (on disk) to .wav format (new file). If `path` is a directory name, convert all .flac files in the directory. `keep` to retain the original .flac file(s), default `True`. """ flac_path = _getFlacPath() flac_files = [] path = pathToString(path) if path.endswith('.flac'): flac_files = [path] elif type(path) == str and os.path.isdir(path): flac_files = glob.glob(os.path.join(path, '*.flac')) if len(flac_files) == 0: logging.warn('failed to find .flac file(s) from %s' % path) return None wav_files = [] for flacfile in flac_files: wavname = flacfile.strip('.flac') + '.wav' flac_cmd = [flac_path, "-d", "--totally-silent", "-f", "-o", wavname, flacfile] _junk, se = core.shellCall(flac_cmd, stderr=True) if se: logging.error(se) if not keep: os.unlink(flacfile) wav_files.append(wavname) if len(wav_files) == 1: return wav_files[0] else: return wav_files
def findImageFile(filename): """Tests whether the filename is an image file. If not will try some common alternatives (e.g. extensions .jpg .tif...) """ # if user supplied correct path then reutnr quickly filename = pathToString(filename) isfile = os.path.isfile if isfile(filename): return filename orig = copy.copy(filename) # search for file using additional extensions extensions = ('.jpg', '.png', '.tif', '.bmp', '.gif', '.jpeg', '.tiff') # not supported: 'svg', 'eps' def logCorrected(orig, actual): logging.warn("Requested image {!r} not found but similar filename " "{!r} exists. This will be used instead but changing the " "filename is advised.".format(orig, actual)) # it already has one but maybe it's wrong? Remove it if filename.endswith(extensions): filename = os.path.splitext(orig)[0] if isfile(filename): # had an extension but didn't need one (mac?) logCorrected(orig, filename) return filename # try adding the standard set of extensions for ext in extensions: if isfile(filename + ext): filename += ext logCorrected(orig, filename) return filename
def saveAsPickle(self, fileName, fileCollisionMethod='rename'): """Basically just saves a copy of the handler (with data) to a pickle file. This can be reloaded if necessary and further analyses carried out. :Parameters: fileCollisionMethod: Collision method passed to :func:`~psychopy.tools.fileerrortools.handleFileCollision` """ fileName = pathToString(fileName) if self.thisTrialN < 1 and self.thisRepN < 1: # if both are < 1 we haven't started if self.autoLog: logging.info('.saveAsPickle() called but no trials completed.' ' Nothing saved') return -1 if not fileName.endswith('.psydat'): fileName += '.psydat' with openOutputFile(fileName=fileName, append=False, fileCollisionMethod=fileCollisionMethod) as f: pickle.dump(self, f) logging.info('saved data to %s' % f.name)
def load(self, pathToMovie): """Load a movie file from disk. Parameters ---------- pathToMovie : str Path to movie file, stream (URI) or camera. Must be a format that FFMPEG supports. """ # set the file path self._filename = pathToString(pathToMovie) # Check if the player is already started. Close it and load a new # instance if so. if self._handle is not None: # player already started # make sure it's the correct type if not isinstance(self._handle, MediaPlayer): raise TypeError( 'Incorrect type for `FFMovieStim._player`, expected ' '`ffpyplayer.player.MediaPlayer`. Got type `{}` ' 'instead.'.format(type(self._handle).__name__)) # close the player and reset self.unload() # self._selectWindow(self.win) # free buffers here !!! self.start() self._status = NOT_STARTED
def findImageFile(filename): """Tests whether the filename is an image file. If not will try some common alternatives (e.g. extensions .jpg .tif...) """ # if user supplied correct path then reutnr quickly filename = pathToString(filename) isfile = os.path.isfile if isfile(filename): return filename orig = copy.copy(filename) # search for file using additional extensions extensions = ('.jpg', '.png', '.tif', '.bmp', '.gif', '.jpeg', '.tiff') # not supported: 'svg', 'eps' def logCorrected(orig, actual): logging.warn("Requested image {!r} not found but similar filename " "{!r} exists. This will be used instead but changing the " "filename is advised.".format(orig, actual)) # it already has one but maybe it's wrong? Remove it if filename.endswith(extensions): filename = os.path.splitext(orig)[0] if isfile(filename): # had an extension but didn't need one (mac?) logCorrected(orig, filename) return filename # try adding the standard set of extensions for ext in extensions: if isfile(filename+ext): filename += ext logCorrected(orig, filename) return filename
def flac2wav(path, keep=True): """Uncompress: convert .flac file (on disk) to .wav format (new file). If `path` is a directory name, convert all .flac files in the directory. `keep` to retain the original .flac file(s), default `True`. """ flac_path = _getFlacPath() flac_files = [] path = pathToString(path) if path.endswith('.flac'): flac_files = [path] elif type(path) == str and os.path.isdir(path): flac_files = glob.glob(os.path.join(path, '*.flac')) if len(flac_files) == 0: logging.warn('failed to find .flac file(s) from %s' % path) return None wav_files = [] for flacfile in flac_files: wavname = flacfile.strip('.flac') + '.wav' flac_cmd = [ flac_path, "-d", "--totally-silent", "-f", "-o", wavname, flacfile ] _junk, se = core.shellCall(flac_cmd, stderr=True) if se: logging.error(se) if not keep: os.unlink(flacfile) wav_files.append(wavname) if len(wav_files) == 1: return wav_files[0] else: return wav_files
def loadMovie(self, filename, log=True): """Load a movie from file :Parameters: filename: string The name of the file, including path if necessary After the file is loaded MovieStim.duration is updated with the movie duration (in seconds). """ filename = pathToString(filename) self._unload() self._reset() if self._no_audio is False: self._createAudioStream() # Create Video Stream stuff self._video_stream.open(filename) vfstime = core.getTime() opened = self._video_stream.isOpened() if not opened and core.getTime() - vfstime < 1: raise RuntimeError("Error when reading image file") if not opened: raise RuntimeError("Error when reading image file") self._total_frame_count = self._video_stream.get( cv2.CAP_PROP_FRAME_COUNT) self._video_width = int(self._video_stream.get( cv2.CAP_PROP_FRAME_WIDTH)) self._video_height = int(self._video_stream.get( cv2.CAP_PROP_FRAME_HEIGHT)) self._format = self._video_stream.get( cv2.CAP_PROP_FORMAT) # TODO: Read depth from video source self._video_frame_depth = 3 cv_fps = self._video_stream.get(cv2.CAP_PROP_FPS) self._video_frame_rate = cv_fps self._inter_frame_interval = 1.0/self._video_frame_rate # Create a numpy array that can hold one video frame, as returned by # cv2. self._numpy_frame = numpy.zeros((self._video_height, self._video_width, self._video_frame_depth), dtype=numpy.uint8) self.duration = self._total_frame_count * self._inter_frame_interval self.status = NOT_STARTED self.filename = filename logAttrib(self, log, 'movie', filename)
def __init__(self, name='mic', filename='', saveDir='', sampletype=0, buffering=16, chnl=0, stereo=True, autoLog=True): """ :Parameters: name : Stem for the output file, also used in logging. filename : optional file name to use; default = 'name-onsetTimeEpoch.wav' saveDir : Directory to use for output .wav files. If a saveDir is given, it will return 'saveDir/file'. If no saveDir, then return abspath(file) sampletype : bit depth pyo recording option: 0=16 bits int, 1=24 bits int; 2=32 bits int buffering : pyo argument chnl : which audio input channel to record (default=0) stereo : how many channels to record (default True, stereo; False = mono) """ if not haveMic: raise MicrophoneError('Need to call microphone.switchOn()' ' before AudioCapture or AdvancedCapture') self.name = name self.saveDir = saveDir filename = pathToString(filename) if filename: self.wavOutFilename = filename else: self.wavOutFilename = os.path.join(self.saveDir, name + '.wav') if not self.saveDir: self.wavOutFilename = os.path.abspath(self.wavOutFilename) else: if not os.path.isdir(self.saveDir): os.makedirs(self.saveDir, 0o770) self.onset = None # becomes onset time, used in filename self.savedFile = False # becomes saved file name self.status = NOT_STARTED # for Builder component # pyo server good to go? if not pyo.serverCreated(): raise AttributeError('pyo server not created') if not pyo.serverBooted(): raise AttributeError('pyo server not booted') self.autoLog = autoLog self.loggingId = self.__class__.__name__ if self.name: self.loggingId += ' ' + self.name # the recorder object needs to persist, or else get bus errors: self.recorder = self._Recorder() self.options = {'sampletype': sampletype, 'buffering': buffering, 'chnl': chnl, 'chnls': 1 + int(stereo == True)}
def loadMovie(self, filename, log=True): """Load a movie from file. After the file is loaded `MovieStim.duration` is updated with the movie duration (in seconds). Parameters ---------- filename : str The name of the file, including path if necessary. log : bool Log this event. """ filename = pathToString(filename) self.reset() # set status and timestamps etc self._mov = None # Create Video Stream stuff if os.path.isfile(filename): self._mov = VideoFileClip(filename, audio=(1 - self.noAudio)) if (not self.noAudio) and (self._mov.audio is not None): sound = self.sound try: self._audioStream = sound.Sound( self._mov.audio.to_soundarray(), sampleRate=self._mov.audio.fps) except: # JWE added this as a patch for a moviepy oddity where the # duration is inflated in the saved file causes the # audioclip to be the wrong length, so round down and it # should work jwe_tmp = self._mov.subclip(0, round(self._mov.duration)) self._audioStream = sound.Sound( jwe_tmp.audio.to_soundarray(), sampleRate=self._mov.audio.fps) del(jwe_tmp) else: # make sure we set to None (in case prev clip had audio) self._audioStream = None elif not filename.startswith(prefs.paths['resources']): # If not found, and we aren't already looking in the Resources folder, try again in the Resources folder self.loadMovie(Path(prefs.paths['resources']) / filename, log=False) else: # Raise error if *still* not found raise IOError("Movie file '%s' was not found" % filename) # mov has attributes: # size, duration, fps # mov.audio has attributes # duration, fps (aka sampleRate), to_soundarray() self._frameInterval = 1.0 / self._mov.fps # self.duration = self._mov.duration self.filename = filename self._updateFrameTexture() logAttrib(self, log, 'movie', filename)
def run(self, filename, sec, sampletype=0, buffering=16, chnl=0, chnls=2): filename = pathToString(filename) self.running = True # chnl from psychopy.sound.backend.get_input_devices() inputter = pyo.Input(chnl=chnl, mul=1) self.recorder = pyo.Record(inputter, filename, chnls=chnls, fileformat=0, sampletype=sampletype, buffering=buffering) # handles recording offset pyo.Clean_objects(sec, self.recorder).start() threading.Timer(sec, self._stop).start() # set running flag False
def saveAsJson(self, fileName=None, encoding='utf-8', fileCollisionMethod='rename'): """ Serialize the object to the JSON format. Parameters ---------- fileName: string, or None the name of the file to create or append. Can include a relative or absolute path. If `None`, will not write to a file, but return an in-memory JSON object. 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). fileCollisionMethod : string Collision method passed to :func:`~psychopy.tools.fileerrortools.handleFileCollision`. Can be either of `'rename'`, `'overwrite'`, or `'fail'`. Notes ----- Currently, a copy of the object is created, and the copy's .origin attribute is set to an empty string before serializing because loading the created JSON file would sometimes fail otherwise. """ fileName = pathToString(fileName) self_copy = copy.deepcopy(self) self_copy.origin = '' msg = ('Setting attribute .origin to empty string during JSON ' 'serialization.') logging.warn(msg) if (fileName is None) or (fileName == 'stdout'): return json_tricks.dumps(self_copy) else: with openOutputFile(fileName=fileName, fileCollisionMethod=fileCollisionMethod, encoding=encoding) as f: json_tricks.dump(self_copy, f) logging.info('Saved JSON data to %s' % f.name)
def _assertValidVarNames(fieldNames, fileName): """screens a list of names as candidate variable names. if all names are OK, return silently; else raise with msg """ fileName = pathToString(fileName) if not all(fieldNames): msg = ('Conditions file %s: Missing parameter name(s); ' 'empty cell(s) in the first row?') raise ValueError(msg % fileName) for name in fieldNames: OK, msg = isValidVariableName(name) if not OK: # tailor message to importConditions msg = msg.replace('Variables', 'Parameters (column headers)') raise ValueError('Conditions file %s: %s%s"%s"' % (fileName, msg, os.linesep * 2, name))
def saveAsJson(self, fileName=None, encoding='utf-8', fileCollisionMethod='rename'): """ Serialize the object to the JSON format. Parameters ---------- fileName: string, or None the name of the file to create or append. Can include a relative or absolute path. If `None`, will not write to a file, but return an in-memory JSON object. encoding : string, optional The encoding to use when writing the file. fileCollisionMethod : string Collision method passed to :func:`~psychopy.tools.fileerrortools.handleFileCollision`. Can be either of `'rename'`, `'overwrite'`, or `'fail'`. Notes ----- Currently, a copy of the object is created, and the copy's .origin attribute is set to an empty string before serializing because loading the created JSON file would sometimes fail otherwise. """ fileName = pathToString(fileName) self_copy = copy.deepcopy(self) self_copy.origin = '' msg = ('Setting attribute .origin to empty string during JSON ' 'serialization.') logging.warn(msg) if (fileName is None) or (fileName == 'stdout'): return json_tricks.dumps(self_copy) else: with openOutputFile(fileName=fileName, fileCollisionMethod=fileCollisionMethod, encoding=encoding) as f: json_tricks.dump(self_copy, f) logging.info('Saved JSON data to %s' % f.name)
def loadMovie(self, filename, log=True): """Load a movie from file :Parameters: filename: string The name of the file, including path if necessary After the file is loaded MovieStim.duration is updated with the movie duration (in seconds). """ filename = pathToString(filename) self.reset() # set status and timestamps etc # Create Video Stream stuff if os.path.isfile(filename): self._mov = VideoFileClip(filename, audio=(1 - self.noAudio)) if (not self.noAudio) and (self._mov.audio is not None): sound = self.sound try: self._audioStream = sound.Sound( self._mov.audio.to_soundarray(), sampleRate=self._mov.audio.fps) except: # JWE added this as a patch for a moviepy oddity where the # duration is inflated in the saved file causes the # audioclip to be the wrong length, so round down and it # should work jwe_tmp = self._mov.subclip(0, round(self._mov.duration)) self._audioStream = sound.Sound( jwe_tmp.audio.to_soundarray(), sampleRate=self._mov.audio.fps) del(jwe_tmp) else: # make sure we set to None (in case prev clip had audio) self._audioStream = None else: raise IOError("Movie file '%s' was not found" % filename) # mov has attributes: # size, duration, fps # mov.audio has attributes # duration, fps (aka sampleRate), to_soundarray() self._frameInterval = 1.0/self._mov.fps self.duration = self._mov.duration self.filename = filename self._updateFrameTexture() logAttrib(self, log, 'movie', filename)
def loadMovie(self, filename, log=True): """Load a movie from file :Parameters: filename: string The name of the file, including path if necessary After the file is loaded MovieStim.duration is updated with the movie duration (in seconds). """ filename = pathToString(filename) self.reset() # set status and timestamps etc # Create Video Stream stuff if os.path.isfile(filename): self._mov = VideoFileClip(filename, audio=(1 - self.noAudio)) if (not self.noAudio) and (self._mov.audio is not None): sound = self.sound try: self._audioStream = sound.Sound( self._mov.audio.to_soundarray(), sampleRate=self._mov.audio.fps) except: # JWE added this as a patch for a moviepy oddity where the # duration is inflated in the saved file causes the # audioclip to be the wrong length, so round down and it # should work jwe_tmp = self._mov.subclip(0, round(self._mov.duration)) self._audioStream = sound.Sound( jwe_tmp.audio.to_soundarray(), sampleRate=self._mov.audio.fps) del (jwe_tmp) else: # make sure we set to None (in case prev clip had audio) self._audioStream = None else: raise IOError("Movie file '%s' was not found" % filename) # mov has attributes: # size, duration, fps # mov.audio has attributes # duration, fps (aka sampleRate), to_soundarray() self._frameInterval = 1.0 / self._mov.fps self.duration = self._mov.duration self.filename = filename self._updateFrameTexture() logAttrib(self, log, 'movie', filename)
def loadMovie(self, filename, log=True): """Load a movie from file :Parameters: filename: string The name of the file, including path if necessary Due to VLC oddness, .duration is not correct until the movie starts playing. """ self._reset() self.filename = pathToString(filename) # Initialize VLC self._vlc_start() self.status = NOT_STARTED logAttrib(self, log, 'movie', filename)
def wav2flac(path, keep=True, level=5): """Lossless compression: convert .wav file (on disk) to .flac format. If `path` is a directory name, convert all .wav files in the directory. `keep` to retain the original .wav file(s), default `True`. `level` is compression level: 0 is fastest but larger, 8 is slightly smaller but much slower. """ flac_path = _getFlacPath() wav_files = [] path = pathToString(path) if path.endswith('.wav'): wav_files = [path] elif type(path) == str and os.path.isdir(path): wav_files = glob.glob(os.path.join(path, '*.wav')) if len(wav_files) == 0: logging.warn('failed to find .wav file(s) from %s' % path) return None flac_files = [] for wavname in wav_files: flacfile = wavname.replace('.wav', '.flac') flac_cmd = [ flac_path, "-%d" % level, "-f", "--totally-silent", "-o", flacfile, wavname ] _junk, se = core.shellCall(flac_cmd, stderr=True) if se or not os.path.isfile(flacfile): # just try again # ~2% incidence when recording for 1s, 650+ trials # never got two in a row; core.wait() does not help logging.warn('Failed to convert to .flac; trying again') _junk, se = core.shellCall(flac_cmd, stderr=True) if se: logging.error(se) if not keep: os.unlink(wavname) flac_files.append(flacfile) if len(wav_files) == 1: return flac_files[0] else: return flac_files
def run(self, filename, sec, sampletype=0, buffering=16, chnl=0, chnls=2): filename = pathToString(filename) self.running = True # chnl from psychopy.backend_pyo.get_input_devices() inputter = pyo.Input(chnl=chnl, mul=1) self.recorder = pyo.Record(inputter, filename, chnls=chnls, fileformat=0, sampletype=sampletype, buffering=buffering) # handles recording offset pyo.Clean_objects(sec, self.recorder).start() threading.Timer(sec, self._stop).start() # set running flag False
def _record(self, sec, filename='', block=True, log=True): filename = pathToString(filename) while self.recorder.running: pass self.duration = float(sec) # for duration estimation, high precision: self.onset = core.getTime() # use time for unique log and filename, 1 sec precision self.fileOnset = core.getAbsTime() ms = "%.3f" % (core.getTime() - int(core.getTime())) if log and self.autoLog: msg = '%s: Record: onset %d, capture %.3fs' logging.data(msg % (self.loggingId, self.fileOnset, self.duration)) if not filename: onsettime = '-%d' % self.fileOnset + ms[1:] self.savedFile = onsettime.join( os.path.splitext(self.wavOutFilename)) else: self.savedFile = os.path.abspath(filename) if not self.savedFile.endswith('.wav'): self.savedFile += '.wav' t0 = core.getTime() self.recorder.run(self.savedFile, self.duration, **self.options) self.rate = sound.backend.pyoSndServer.getSamplingRate() if block: core.wait(self.duration, 0) if log and self.autoLog: msg = '%s: Record: stop. %.3f, capture %.3fs (est)' logging.exp(msg % (self.loggingId, core.getTime(), core.getTime() - t0)) while self.recorder.running: core.wait(.001, 0) else: if log and self.autoLog: msg = '%s: Record: return immediately, no blocking' logging.exp(msg % (self.loggingId)) return self.savedFile
def _record(self, sec, filename='', block=True, log=True): filename = pathToString(filename) while self.recorder.running: pass self.duration = float(sec) # for duration estimation, high precision: self.onset = core.getTime() # use time for unique log and filename, 1 sec precision self.fileOnset = core.getAbsTime() ms = "%.3f" % (core.getTime() - int(core.getTime())) if log and self.autoLog: msg = '%s: Record: onset %d, capture %.3fs' logging.data(msg % (self.loggingId, self.fileOnset, self.duration)) if not filename: onsettime = '-%d' % self.fileOnset + ms[1:] self.savedFile = onsettime.join( os.path.splitext(self.wavOutFilename)) else: self.savedFile = os.path.abspath(filename) if not self.savedFile.endswith('.wav'): self.savedFile += '.wav' t0 = core.getTime() self.recorder.run(self.savedFile, self.duration, **self.options) self.rate = backend_pyo.pyoSndServer.getSamplingRate() if block: core.wait(self.duration, 0) if log and self.autoLog: msg = '%s: Record: stop. %.3f, capture %.3fs (est)' logging.exp( msg % (self.loggingId, core.getTime(), core.getTime() - t0)) while self.recorder.running: core.wait(.001, 0) else: if log and self.autoLog: msg = '%s: Record: return immediately, no blocking' logging.exp(msg % (self.loggingId)) return self.savedFile
def readWavFile(filename): """Return (data, sampleRate) as read from a wav file, expects int16 data. """ filename = pathToString(filename) try: sampleRate, data = wavfile.read(filename) except Exception: if os.path.exists(filename) and os.path.isfile(filename): core.wait(0.01, 0) try: sampleRate, data = wavfile.read(filename) except Exception: msg = 'Failed to open wav sound file "%s"' raise SoundFileError(msg % filename) if data.dtype != 'int16': msg = 'expected `int16` data in .wav file %s' raise AttributeError(msg % filename) if len(data.shape) == 2 and data.shape[1] == 2: data = data.transpose() data = data[0] # left channel only? depends on how the file was made return data, sampleRate
def wav2flac(path, keep=True, level=5): """Lossless compression: convert .wav file (on disk) to .flac format. If `path` is a directory name, convert all .wav files in the directory. `keep` to retain the original .wav file(s), default `True`. `level` is compression level: 0 is fastest but larger, 8 is slightly smaller but much slower. """ flac_path = _getFlacPath() wav_files = [] path = pathToString(path) if path.endswith('.wav'): wav_files = [path] elif type(path) == str and os.path.isdir(path): wav_files = glob.glob(os.path.join(path, '*.wav')) if len(wav_files) == 0: logging.warn('failed to find .wav file(s) from %s' % path) return None flac_files = [] for wavname in wav_files: flacfile = wavname.replace('.wav', '.flac') flac_cmd = [flac_path, "-%d" % level, "-f", "--totally-silent", "-o", flacfile, wavname] _junk, se = core.shellCall(flac_cmd, stderr=True) if se or not os.path.isfile(flacfile): # just try again # ~2% incidence when recording for 1s, 650+ trials # never got two in a row; core.wait() does not help logging.warn('Failed to convert to .flac; trying again') _junk, se = core.shellCall(flac_cmd, stderr=True) if se: logging.error(se) if not keep: os.unlink(wavname) flac_files.append(flacfile) if len(wav_files) == 1: return flac_files[0] else: return flac_files
def loadMovie(self, filename, log=True): """Load a movie from file Parameters ---------- filename : str The name of the file or URL, including path if necessary. log : bool Log this event. Notes ----- * Due to VLC oddness, `.duration` is not correct until the movie starts playing. """ self._filename = pathToString(filename) # open the media using a new player self._openMedia() self.status = NOT_STARTED logAttrib(self, log, 'movie', filename)
def loadMovie(self, filename, log=None): """Load a movie from file :Parameters: filename: string The name of the file, including path if necessary Brings up a warning if avbin is not found on the computer. After the file is loaded MovieStim.duration is updated with the movie duration (in seconds). """ filename = pathToString(filename) try: self._movie = pyglet.media.load(filename, streaming=True) except Exception as e: # pyglet.media.riff is N/A if avbin is available, and then # actual exception would get masked with a new one for unknown # (sub)module riff, thus catching any exception and tuning msg # up if it has to do anything with avbin estr = str(e) msg = '' if "avbin" in estr.lower(): msg = ("\nIt seems that avbin was not installed correctly." "\nPlease fetch/install it from " "http://code.google.com/p/avbin/.") emsg = "Caught exception '%s' while loading file '%s'.%s" raise IOError(emsg % (estr, filename, msg)) self._player.queue(self._movie) self.duration = self._movie.duration while self._player.source != self._movie: next(self._player) self.status = NOT_STARTED self._player.pause() # start 'playing' on the next draw command self.filename = filename logAttrib(self, log, 'movie', filename)
def __init__(self, win, filename="", movieLib=u'ffpyplayer', units='pix', size=None, pos=(0.0, 0.0), ori=0.0, anchor="center", flipVert=False, flipHoriz=False, color=(1.0, 1.0, 1.0), # remove? colorSpace='rgb', opacity=1.0, contrast=1, volume=1.0, name='', loop=False, autoLog=True, depth=0.0, noAudio=False, interpolate=True, autoStart=True): # # check if we have the VLC lib # if not haveFFPyPlayer: # raise ImportError( # 'Cannot import package `ffpyplayer`, therefore `FFMovieStim` ' # 'cannot be used this session.') # what local vars are defined (these are the init params) for use self._initParams = dir() self._initParams.remove('self') super(MovieStim, self).__init__( win, units=units, name=name, autoLog=False) # drawing stuff self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = pos self.ori = ori self.size = size self.depth = depth self.opacity = opacity self.anchor = anchor self.colorSpace = colorSpace self.color = color # playback stuff self._filename = pathToString(filename) self._volume = volume self._noAudio = noAudio # cannot be changed self.loop = loop self._recentFrame = None self._autoStart = autoStart # OpenGL data self.interpolate = True self._texFilterNeedsUpdate = True self._metadata = NULL_MOVIE_METADATA self._pixbuffId = GL.GLuint(0) self._textureId = GL.GLuint(0) # get the player interface for the desired `movieLib` and instance it self._player = getMoviePlayer(movieLib)(self) # load a file if provided, otherwise the user must call `setMovie()` self._filename = pathToString(filename) if self._filename: # load a movie if provided self.loadMovie(self._filename)
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(MovieStim2, self).__init__(win, units=units, name=name, autoLog=False) # check for pyglet if win.winType != 'pyglet': logging.error( 'Movie stimuli can only be used with a pyglet window') core.quit() self._retracerate = win._monitorFrameRate if self._retracerate is None: self._retracerate = win.getActualFrameRate() if self._retracerate is None: logging.warning("FrameRate could not be supplied by psychopy; " "defaulting to 60.0") self._retracerate = 60.0 self.filename = pathToString(filename) self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.depth = depth self.opacity = float(opacity) self.volume = volume self._av_stream_time_offset = 0.145 self._no_audio = noAudio self._vframe_callback = vframe_callback self.interpolate = interpolate self.useTexSubImage2D = True self._texID = None self._video_stream = cv2.VideoCapture() self._reset() self.loadMovie(self.filename) self.setVolume(volume) self.nDroppedFrames = 0 self.aspectRatio = self._video_width/float(self._video_height) # size if size is None: self.size = numpy.array([self._video_width, self._video_height], float) elif isinstance(size, (int, float, int)): # treat size as desired width, and calc a height # that maintains the aspect ratio of the video. self.size = numpy.array([size, size/self.aspectRatio], 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 {} = {}".format(self.name, self))
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=None, loop=False, autoLog=None, depth=0.0, ): """ :Parameters: filename : a string giving the relative or absolute path to the movie. Can be any movie that AVbin can read (e.g. mpeg, DivX) 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 1.0, and 0.0 is silence, see pyglet.media.Player 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(MovieStim, self).__init__(win, units=units, name=name, autoLog=False) self._verticesBase *= numpy.array([[-1, 1]]) # unflip if not havePygletMedia: msg = ("pyglet.media is needed for MovieStim and could not be" " imported.\nThis can occur for various reasons;" " - psychopy.visual was imported too late (after a lib" " that uses scipy)" " - no audio output is enabled (no audio card or no " "speakers attached)" " - avbin is not installed") raise ImportError(msg) self._movie = None # the actual pyglet media object self._player = pyglet.media.ManagedSoundPlayer() self._player.volume = volume try: self._player_default_on_eos = self._player.on_eos except Exception: # pyglet 1.1.4? self._player_default_on_eos = self._player._on_eos self.filename = pathToString(filename) self.duration = None self.loop = loop if loop and pyglet.version >= '1.2': logging.error("looping of movies is not currently supported " "for pyglet >= 1.2 (only for version 1.1.4)") self.loadMovie(self.filename) self.format = self._movie.video_format self.pos = numpy.asarray(pos, float) self.depth = depth self.flipVert = flipVert self.flipHoriz = flipHoriz self.opacity = float(opacity) self.status = NOT_STARTED # size if size is None: self.size = numpy.array([self.format.width, self.format.height], float) else: self.size = val2array(size) self.ori = ori self._updateVertices() if win.winType != 'pyglet': logging.error('Movie stimuli can only be used with a ' 'pyglet window') core.quit() # 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)))
def setImage(self, filename=None, log=None): """Usually you can use 'stim.attribute = value' syntax instead, but use this method if you need to suppress the log message. """ filename = pathToString(filename) setAttribute(self, 'image', filename, log)
def saveAsText(self, fileName, stimOut=None, dataOut=('n', 'all_mean', 'all_std', 'all_raw'), delim=None, matrixOnly=False, appendFile=True, summarised=True, fileCollisionMethod='rename', encoding='utf-8-sig'): """ Write a text file with the data and various chosen stimulus attributes :Parameters: fileName: will have .tsv appended and can include path info. stimOut: the stimulus attributes to be output. To use this you need to use a list of dictionaries and give here the names of dictionary keys that you want as strings dataOut: a list of strings specifying the dataType and the analysis to be performed,in the form `dataType_analysis`. The data can be any of the types that you added using trialHandler.data.add() and the analysis can be either 'raw' or most things in the numpy library, including; 'mean','std','median','max','min'... The default values will output the raw, mean and std of all datatypes found delim: allows the user to use a delimiter other than tab ("," is popular with file extension ".csv") matrixOnly: outputs the data with no header row or extraInfo attached appendFile: will add this output to the end of the specified file if it already exists fileCollisionMethod: Collision method passed to :func:`~psychopy.tools.fileerrortools.handleFileCollision` encoding: The encoding to use when saving a the file. Defaults to `utf-8-sig`. """ fileName = pathToString(fileName) if stimOut is None: stimOut = [] if self.thisTrialN < 1 and self.thisRepN < 1: # if both are < 1 we haven't started if self.autoLog: logging.info('TrialHandler.saveAsText called but no trials' ' completed. Nothing saved') return -1 dataArray = self._createOutputArray(stimOut=stimOut, dataOut=dataOut, matrixOnly=matrixOnly) # set default delimiter if none given if delim is None: delim = genDelimiter(fileName) # create the file or send to stdout fileName = genFilenameFromDelimiter(fileName, delim) with openOutputFile(fileName=fileName, append=appendFile, fileCollisionMethod=fileCollisionMethod, encoding=encoding) as f: # loop through lines in the data matrix for line in dataArray: for cellN, entry in enumerate(line): # surround in quotes to prevent effect of delimiter if delim in str(entry): f.write(u'"%s"' % str(entry)) else: f.write(str(entry)) if cellN < (len(line) - 1): f.write(delim) f.write("\n") # add an EOL at end of each line if (fileName is not None) and (fileName != 'stdout') and self.autoLog: logging.info('saved data to %s' % f.name)
def __init__(self, win, filename="", units='pix', size=None, pos=(0.0, 0.0), anchor="center", 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(MovieStim2, self).__init__(win, units=units, name=name, autoLog=False) # check for pyglet if win.winType != 'pyglet': logging.error( 'Movie stimuli can only be used with a pyglet window') core.quit() self._retracerate = win._monitorFrameRate if self._retracerate is None: self._retracerate = win.getActualFrameRate() if self._retracerate is None: logging.warning("FrameRate could not be supplied by psychopy; " "defaulting to 60.0") self._retracerate = 60.0 self.filename = pathToString(filename) self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.anchor = anchor self.depth = depth self.opacity = float(opacity) self.volume = volume self._av_stream_time_offset = 0.145 self._no_audio = noAudio self._vframe_callback = vframe_callback self.interpolate = interpolate self.useTexSubImage2D = True self._texID = None self._video_stream = cv2.VideoCapture() self._reset() self.loadMovie(self.filename) self.setVolume(volume) self.nDroppedFrames = 0 self.aspectRatio = self._video_width / float(self._video_height) # size if size is None: self.size = numpy.array([self._video_width, self._video_height], float) elif isinstance(size, (int, float, int)): # treat size as desired width, and calc a height # that maintains the aspect ratio of the video. self.size = numpy.array([size, size / self.aspectRatio], 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 {} = {}".format(self.name, self))
def __init__(self, name='mic', filename='', saveDir='', sampletype=0, buffering=16, chnl=0, stereo=True, autoLog=True): """ :Parameters: name : Stem for the output file, also used in logging. filename : optional file name to use; default = 'name-onsetTimeEpoch.wav' saveDir : Directory to use for output .wav files. If a saveDir is given, it will return 'saveDir/file'. If no saveDir, then return abspath(file) sampletype : bit depth pyo recording option: 0=16 bits int, 1=24 bits int; 2=32 bits int buffering : pyo argument chnl : which audio input channel to record (default=0) stereo : how many channels to record (default True, stereo; False = mono) """ if not haveMic: raise MicrophoneError('Need to call microphone.switchOn()' ' before AudioCapture or AdvancedCapture') self.name = name self.saveDir = saveDir filename = pathToString(filename) if filename: self.wavOutFilename = filename else: self.wavOutFilename = os.path.join(self.saveDir, name + '.wav') if not self.saveDir: self.wavOutFilename = os.path.abspath(self.wavOutFilename) else: if not os.path.isdir(self.saveDir): os.makedirs(self.saveDir, 0o770) self.onset = None # becomes onset time, used in filename self.savedFile = False # becomes saved file name self.status = NOT_STARTED # for Builder component # pyo server good to go? if not pyo.serverCreated(): raise AttributeError('pyo server not created') if not pyo.serverBooted(): raise AttributeError('pyo server not booted') self.autoLog = autoLog self.loggingId = self.__class__.__name__ if self.name: self.loggingId += ' ' + self.name if type(chnl) != int: try: chnl = int(chnl) except (TypeError, ValueError): raise TypeError( "AudioCapture argument 'chnl' needs to be an int but received {}" .format(repr(chnl))) # the recorder object needs to persist, or else get bus errors: self.recorder = self._Recorder() self.options = { 'sampletype': sampletype, 'buffering': buffering, 'chnl': chnl, 'chnls': 1 + int(stereo == True) }
def saveAsExcel(self, fileName, sheetName='rawData', stimOut=None, dataOut=('n', 'all_mean', 'all_std', 'all_raw'), matrixOnly=False, appendFile=True, fileCollisionMethod='rename'): """ Save a summary data file in Excel OpenXML format workbook (:term:`xlsx`) for processing in most spreadsheet packages. This format is compatible with versions of Excel (2007 or greater) and and with OpenOffice (>=3.0). It has the advantage over the simpler text files (see :func:`TrialHandler.saveAsText()` ) that data can be stored in multiple named sheets within the file. So you could have a single file named after your experiment and then have one worksheet for each participant. Or you could have one file for each participant and then multiple sheets for repeated sessions etc. The file extension `.xlsx` will be added if not given already. :Parameters: fileName: string the name of the file to create or append. Can include relative or absolute path sheetName: string the name of the worksheet within the file stimOut: list of strings the attributes of the trial characteristics to be output. To use this you need to have provided a list of dictionaries specifying to trialList parameter of the TrialHandler and give here the names of strings specifying entries in that dictionary dataOut: list of strings specifying the dataType and the analysis to be performed, in the form `dataType_analysis`. The data can be any of the types that you added using trialHandler.data.add() and the analysis can be either 'raw' or most things in the numpy library, including 'mean','std','median','max','min'. e.g. `rt_max` will give a column of max reaction times across the trials assuming that `rt` values have been stored. The default values will output the raw, mean and std of all datatypes found. appendFile: True or False If False any existing file with this name will be overwritten. If True then a new worksheet will be appended. If a worksheet already exists with that name a number will be added to make it unique. fileCollisionMethod: string Collision method passed to :func:`~psychopy.tools.fileerrortools.handleFileCollision` This is ignored if ``append`` is ``True``. """ fileName = pathToString(fileName) if stimOut is None: stimOut = [] if self.thisTrialN < 1 and self.thisRepN < 1: # if both are < 1 we haven't started if self.autoLog: logging.info('TrialHandler.saveAsExcel called but no ' 'trials completed. Nothing saved') return -1 # NB this was based on the limited documentation (1 page wiki) for # openpyxl v1.0 if not haveOpenpyxl: raise ImportError('openpyxl is required for saving files in' ' Excel (xlsx) format, but was not found.') # return -1 # create the data array to be sent to the Excel file dataArray = self._createOutputArray(stimOut=stimOut, dataOut=dataOut, matrixOnly=matrixOnly) if not fileName.endswith('.xlsx'): fileName += '.xlsx' # create or load the file if appendFile and os.path.isfile(fileName): wb = load_workbook(fileName) newWorkbook = False else: if not appendFile: # the file exists but we're not appending, will be overwritten fileName = handleFileCollision(fileName, fileCollisionMethod) wb = Workbook() # create new workbook wb.properties.creator = 'PsychoPy' + psychopy.__version__ newWorkbook = True if newWorkbook: ws = wb.worksheets[0] ws.title = sheetName else: ws = wb.create_sheet() ws.title = sheetName # loop through lines in the data matrix for lineN, line in enumerate(dataArray): if line is None: continue for colN, entry in enumerate(line): if entry is None: entry = '' try: # if it can convert to a number (from numpy) then do it val = float(entry) except Exception: val = u"{}".format(entry) ws.cell(column=colN+1, row=lineN+1, value=val) wb.save(filename=fileName)
def __init__(self, win, filename="", units='pix', size=None, pos=(0.0, 0.0), anchor="center", 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): # 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 = pathToString(filename) self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.anchor = anchor self.depth = depth self.opacity = opacity self.interpolate = interpolate self.noAudio = noAudio self._audioStream = None self.useTexSubImage2D = True if noAudio: # to avoid dependency problems in silent movies self.sound = None else: from psychopy import sound self.sound = sound # set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created %s = %s" % (self.name, str(self))) 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()
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=None, loop=False, autoLog=None, depth=0.0,): """ :Parameters: filename : a string giving the relative or absolute path to the movie. Can be any movie that AVbin can read (e.g. mpeg, DivX) 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 1.0, and 0.0 is silence, see pyglet.media.Player 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(MovieStim, self).__init__( win, units=units, name=name, autoLog=False) self._verticesBase *= numpy.array([[-1, 1]]) # unflip if not havePygletMedia: msg = ("pyglet.media is needed for MovieStim and could not be" " imported.\nThis can occur for various reasons;" " - psychopy.visual was imported too late (after a lib" " that uses scipy)" " - no audio output is enabled (no audio card or no " "speakers attached)" " - avbin is not installed") raise ImportError(msg) self._movie = None # the actual pyglet media object self._player = pyglet.media.ManagedSoundPlayer() self._player.volume = volume try: self._player_default_on_eos = self._player.on_eos except Exception: # pyglet 1.1.4? self._player_default_on_eos = self._player._on_eos self.filename = pathToString(filename) self.duration = None self.loop = loop if loop and pyglet.version >= '1.2': logging.error("looping of movies is not currently supported " "for pyglet >= 1.2 (only for version 1.1.4)") self.loadMovie(self.filename) self.format = self._movie.video_format self.pos = numpy.asarray(pos, float) self.depth = depth self.flipVert = flipVert self.flipHoriz = flipHoriz self.opacity = float(opacity) self.status = NOT_STARTED # size if size is None: self.size = numpy.array([self.format.width, self.format.height], float) else: self.size = val2array(size) self.ori = ori self._updateVertices() if win.winType != 'pyglet': logging.error('Movie stimuli can only be used with a ' 'pyglet window') core.quit() # 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)))
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), # remove? colorSpace='rgb', opacity=1.0, volume=1.0, name='', loop=False, autoLog=True, depth=0.0, noAudio=False, interpolate=True, autoStart=True): # what local vars are defined (these are the init params) for use # by __repr__ self._initParams = dir() self._initParams.remove('self') super(VlcMovieStim, self).__init__(win, units=units, name=name, autoLog=False) # check for pyglet if win.winType != 'pyglet': logging.error('Movie stimuli can only be used with a pyglet window') core.quit() # drawing stuff self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) # original size to keep BaseVisualStim happy self._origSize = numpy.asarray((128, 128,), float) # Defer setting size until after the video is loaded to use it's native # size instead of the one set by the user. self._useFrameSizeFromVideo = size is None if not self._useFrameSizeFromVideo: self.size = numpy.asarray(size, float) self.depth = depth self.opacity = float(opacity) # playback stuff self._filename = pathToString(filename) self._volume = volume self._noAudio = noAudio # cannot be changed self._currentFrame = -1 self._loopCount = 0 self.loop = loop # video pixel and texture buffer variables, setup later self.interpolate = interpolate # use setter self._textureId = GL.GLuint() self._pixbuffId = GL.GLuint() # VLC related attributes self._instance = None self._player = None self._manager = None self._stream = None self._videoWidth = 0 self._videoHeight = 0 self._frameRate = 0.0 self._vlcInitialized = False self._pixelLock = threading.Lock() # semaphore for VLC pixel transfer self._framePixelBuffer = None # buffer pointer to draw to self._videoFrameBufferSize = None self._streamEnded = False # spawn a VLC instance for this class instance # self._createVLCInstance() # load a movie if provided if self._filename: self.loadMovie(self._filename) self.setVolume(volume) self.nDroppedFrames = 0 self._autoStart = autoStart self.ori = ori # set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created {} = {}".format(self.name, self))
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(VlcMovieStim, self).__init__(win, units=units, name=name, autoLog=False) # check for pyglet if win.winType != 'pyglet': logging.error( 'Movie stimuli can only be used with a pyglet window') core.quit() self._retracerate = win._monitorFrameRate if self._retracerate is None: self._retracerate = win.getActualFrameRate() if self._retracerate is None: logging.warning("FrameRate could not be supplied by psychopy; " "defaulting to 60.0") self._retracerate = 60.0 self.filename = pathToString(filename) self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.size = numpy.asarray(size, float) self.depth = depth self.opacity = float(opacity) self.volume = volume self.no_audio = noAudio self.interpolate = interpolate self._texture_id = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texture_id)) self._pause_time = 0 self._vlc_clock = Clock() self._vlc_initialized = False self._reset() self.loadMovie(self.filename) self.setVolume(volume) self.nDroppedFrames = 0 self.ori = ori # set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created {} = {}".format(self.name, self))
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 = pathToString(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 if noAudio: # to avoid dependency problems in silent movies self.sound = None else: from psychopy import sound self.sound = sound 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)))
def saveAsExcel(self, fileName, sheetName='rawData', stimOut=None, dataOut=('n', 'all_mean', 'all_std', 'all_raw'), matrixOnly=False, appendFile=True, fileCollisionMethod='rename'): """ Save a summary data file in Excel OpenXML format workbook (:term:`xlsx`) for processing in most spreadsheet packages. This format is compatible with versions of Excel (2007 or greater) and and with OpenOffice (>=3.0). It has the advantage over the simpler text files (see :func:`TrialHandler.saveAsText()` ) that data can be stored in multiple named sheets within the file. So you could have a single file named after your experiment and then have one worksheet for each participant. Or you could have one file for each participant and then multiple sheets for repeated sessions etc. The file extension `.xlsx` will be added if not given already. :Parameters: fileName: string the name of the file to create or append. Can include relative or absolute path sheetName: string the name of the worksheet within the file stimOut: list of strings the attributes of the trial characteristics to be output. To use this you need to have provided a list of dictionaries specifying to trialList parameter of the TrialHandler and give here the names of strings specifying entries in that dictionary dataOut: list of strings specifying the dataType and the analysis to be performed, in the form `dataType_analysis`. The data can be any of the types that you added using trialHandler.data.add() and the analysis can be either 'raw' or most things in the numpy library, including 'mean','std','median','max','min'. e.g. `rt_max` will give a column of max reaction times across the trials assuming that `rt` values have been stored. The default values will output the raw, mean and std of all datatypes found. appendFile: True or False If False any existing file with this name will be overwritten. If True then a new worksheet will be appended. If a worksheet already exists with that name a number will be added to make it unique. fileCollisionMethod: string Collision method passed to :func:`~psychopy.tools.fileerrortools.handleFileCollision` This is ignored if ``append`` is ``True``. """ fileName = pathToString(fileName) if stimOut is None: stimOut = [] if self.thisTrialN < 1 and self.thisRepN < 1: # if both are < 1 we haven't started if self.autoLog: logging.info('TrialHandler.saveAsExcel called but no ' 'trials completed. Nothing saved') return -1 # NB this was based on the limited documentation (1 page wiki) for # openpyxl v1.0 if not haveOpenpyxl: raise ImportError('openpyxl is required for saving files in' ' Excel (xlsx) format, but was not found.') # return -1 # create the data array to be sent to the Excel file dataArray = self._createOutputArray(stimOut=stimOut, dataOut=dataOut, matrixOnly=matrixOnly) if not fileName.endswith('.xlsx'): fileName += '.xlsx' # create or load the file if appendFile and os.path.isfile(fileName): wb = load_workbook(fileName) newWorkbook = False else: if not appendFile: # the file exists but we're not appending, will be overwritten fileName = handleFileCollision(fileName, fileCollisionMethod) wb = Workbook() # create new workbook wb.properties.creator = 'PsychoPy' + psychopy.__version__ newWorkbook = True if newWorkbook: ws = wb.worksheets[0] ws.title = sheetName else: ws = wb.create_sheet() ws.title = sheetName # loop through lines in the data matrix for lineN, line in enumerate(dataArray): if line is None: continue for colN, entry in enumerate(line): if entry is None: entry = '' try: # if it can convert to a number (from numpy) then do it val = float(entry) except Exception: val = u"{}".format(entry) ws.cell(column=colN + 1, row=lineN + 1, value=val) wb.save(filename=fileName)
def setSound(self, value, secs=0.5, octave=4, hamming=True, log=True): """Set the sound to be played. Often this is not needed by the user - it is called implicitly during initialisation. Parameters ---------- value : ArrayLike, int or str If it's a number between 37 and 32767 then a tone will be generated at that frequency in Hz. It could be a string for a note ('A', 'Bfl', 'B', 'C', 'Csh'. ...). Then you may want to specify which octave.O r a string could represent a filename in the current location, or media location, or a full path combo. Or by giving an Nx2 numpy array of floats (-1:1). secs : float Duration of a tone if a note name is to `value`. octave : int Is only relevant if the value is a note name. Middle octave of a piano is 4. Most computers won't output sounds in the bottom octave (1) and the top octave (8) is generally painful. hamming : bool To indicate if the sound should be apodized (i.e., the onset and offset smoothly ramped up from down to zero). The function apodize uses a Hanning window, but arguments named 'hamming' are preserved so that existing code is not broken by the change from Hamming to Hanning internally. Not applied to sounds from files. """ # Re-init sound to ensure bad values will raise error during setting: self._snd = None # Coerces pathlib obj to string, else returns inputted value value = pathToString(value) try: # could be '440' meaning 440 value = float(value) except (ValueError, TypeError): # this is a string that can't be a number, eg, a file or note pass else: # we've been asked for a particular Hz if value < 37 or value > 20000: msg = 'Sound: bad requested frequency %.0f' raise ValueError(msg % value) self._setSndFromFreq(value, secs, hamming=hamming) if isinstance(value, basestring): if value.capitalize() in knownNoteNames: self._setSndFromNote(value.capitalize(), secs, octave, hamming=hamming) else: # try finding a file self.fileName = None for filePath in ['', mediaLocation]: p = path.join(filePath, value) if path.isfile(p): self.fileName = p break elif path.isfile(p + '.wav'): self.fileName = p = p + '.wav' break if self.fileName is None: msg = "setSound: could not find a sound file named " raise ValueError(msg + value) else: self._setSndFromFile(p) elif type(value) in [list, numpy.ndarray]: # create a sound from the input array/list self._setSndFromArray(numpy.array(value)) # did we succeed? if self._snd is None: pass # raise ValueError, "Could not make a "+value+" sound" else: if log and self.autoLog: logging.exp("Set %s sound=%s" % (self.name, value), obj=self) self.status = NOT_STARTED
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 = pathToString(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 if noAudio: # to avoid dependency problems in silent movies self.sound = None else: from psychopy import sound self.sound = sound # set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created %s = %s" % (self.name, str(self))) 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()
def saveAsText(self, fileName, stimOut=None, dataOut=('n', 'all_mean', 'all_std', 'all_raw'), delim=None, matrixOnly=False, appendFile=True, summarised=True, fileCollisionMethod='rename', encoding='utf-8'): """ Write a text file with the data and various chosen stimulus attributes :Parameters: fileName: will have .tsv appended and can include path info. stimOut: the stimulus attributes to be output. To use this you need to use a list of dictionaries and give here the names of dictionary keys that you want as strings dataOut: a list of strings specifying the dataType and the analysis to be performed,in the form `dataType_analysis`. The data can be any of the types that you added using trialHandler.data.add() and the analysis can be either 'raw' or most things in the numpy library, including; 'mean','std','median','max','min'... The default values will output the raw, mean and std of all datatypes found delim: allows the user to use a delimiter other than tab ("," is popular with file extension ".csv") matrixOnly: outputs the data with no header row or extraInfo attached appendFile: will add this output to the end of the specified file if it already exists fileCollisionMethod: Collision method passed to :func:`~psychopy.tools.fileerrortools.handleFileCollision` encoding: The encoding to use when saving a the file. Defaults to `utf-8`. """ fileName = pathToString(fileName) if stimOut is None: stimOut = [] if self.thisTrialN < 1 and self.thisRepN < 1: # if both are < 1 we haven't started if self.autoLog: logging.info('TrialHandler.saveAsText called but no trials' ' completed. Nothing saved') return -1 dataArray = self._createOutputArray(stimOut=stimOut, dataOut=dataOut, matrixOnly=matrixOnly) # set default delimiter if none given if delim is None: delim = genDelimiter(fileName) # create the file or send to stdout fileName = genFilenameFromDelimiter(fileName, delim) with openOutputFile(fileName=fileName, append=appendFile, fileCollisionMethod=fileCollisionMethod, encoding=encoding) as f: # loop through lines in the data matrix for line in dataArray: for cellN, entry in enumerate(line): # surround in quotes to prevent effect of delimiter if delim in str(entry): f.write(u'"%s"' % str(entry)) else: f.write(str(entry)) if cellN < (len(line) - 1): f.write(delim) f.write("\n") # add an EOL at end of each line if (fileName is not None) and (fileName != 'stdout') and self.autoLog: logging.info('saved data to %s' % f.name)