Esempio n. 1
0
    def decompress(self):
        """Decompress the stimulus.

        This will decompress the stimulus.
        The surface will now be read from memory again.
        Depending on the size of the stimulus, this method may take some time
        to compute!

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = Clock._cpu_time()
        if self.is_compressed:
            self._surface = pygame.image.load(
                self._compression_filename).convert_alpha()
            self._is_compressed = False

            if self._logging:
                expyriment._active_exp._event_file_log(
                            "Stimulus,decompressed,{0}".format(self.id), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 2
0
    def flip(self, booleans):
        """Flip the stimulus.

        This is a surface operation. After this, a surface will be present!

        Parameters
        ----------
        booleans : (bool, bool)
            booleans to flip or not

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "flip()"))
        self.unload(keep_surface=True)
        self._set_surface(pygame.transform.flip(self._get_surface(),
                                                  booleans[0], booleans[1]))
        if self._logging:
            expyriment._active_exp._event_file_log(
            "Stimulus,flipped,{0}, booleans={1}".format(self.id, booleans), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 3
0
    def move(self, offset):
        """Moves the stimulus in 2D space.

        When using OpenGL, this can take longer then 1ms!

        Parameters
        ----------
        offset : list, optional
            translation along x and y axis

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = Clock._cpu_time()
        moved = False
        x = offset[0]
        y = offset[1]
        if x > 0 or x < 0:
            self._position[0] = self._position[0] + x
            moved = True
        if y > 0 or y < 0:
            self._position[1] = self._position[1] + y
            moved = True
        if moved and self._ogl_screen is not None:
            self._ogl_screen.refresh_position()
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 4
0
    def compress(self):
        """"Compress the stimulus.

        This will create a temporary file on the disk where the surface of the
        stimululs is written to.
        The surface will now be read from the disk to free memory.
        Compressed stimuli cannot do surface operations!
        Preloading comressed stimuli is possible and highly recommended.
        Depending on the size of the stimulus, this method may take some time
        to compute!

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = Clock._cpu_time()
        if self.is_compressed is False:
            if self._compression_filename is None:
                fid, self._compression_filename = tempfile.mkstemp(
                    dir=defaults.tempdir, suffix=".tga")
                os.close(fid)
            pygame.image.save(self._get_surface(), self._compression_filename)
            self._is_compressed = True
            self._surface = None

            if self._logging:
                expyriment._active_exp._event_file_log(
                                "Stimulus,compressed,{0}".format(self.id), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 5
0
    def clear_surface(self):
        """Clear the stimulus surface.

        Surfaces are automatically created after any surface operation
        (presenting, plotting, rotating, scaling, flipping etc.) and preloading.
        If the stimulus was preloaded, this method unloads the stimulus.
        This method is functionally equivalent with unload(keep_surface=False).

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if self.is_preloaded:
            self.unload(keep_surface=False)
        self._is_compressed = False
        self._set_surface(None)
        if self._logging:
            expyriment._active_exp._event_file_log(
                            "Stimulus,surface cleared,{0}".format(self.id), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 6
0
    def send(self, code=None, duration=None):
        """Send a marker.

        This sends a marker via the specified interface.
        If a duration is given, a 0 will be sent automatically after each
        code.

        Note for EEG/MEG systems:
        If the system is receiving the markers on a parallel port, the
        duration between sending a code an the subsequent 0 should be at least
        1000/samplerate!

        Parameters
        ----------
        code : int, optional
            a specific code
        durartion : int, optional
            duration (in ms) for sending a 0 after a code

        """

        if not code:
            code = self.default_code
        if not duration:
            duration = self.default_duration
        self._interface.send(code)
        if duration:
            start = Clock._cpu_time()
            while (Clock._cpu_time() - start) * 1000 < duration:
                pass
        self._interface.send(0)
        if self._logging:
            expyriment._active_exp._event_file_log(
                                        "MarkerOutput,sent,{0}".format(code))
Esempio n. 7
0
    def rotate(self, degree):
        """Rotate the stimulus.

        This is a surface operation. After this, a surface will be present!
        Rotating goes along with a quality loss. Thus, rotating an already
        rotated stimulus is not a good idea.

        Parameters
        ----------
        degree : int
            degree to rotate counterclockwise

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "rotate()"))
        self.unload(keep_surface=True)
        self._set_surface(pygame.transform.rotate(self._get_surface(),
                                                  degree))
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,rotated,{0}, degree={1}".format(self.id, degree))
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 8
0
    def wait(self, codes=None, duration=None, no_clear_buffer=False,
             bitwise_comparison=False, check_for_control_keys=True):
        """Wait for responses defined as codes.

        Notes
        -----
        If bitwise_comparision = True, the function performs a bitwise
        comparison (logical and) between codes and received input and waits
        until a certain bit pattern is set.

        This will also by default check for control keys (quit and pause).
        Thus, keyboard events will be cleared from the cue and cannot be
        received by a Keyboard().check() anymore!

        Parameters
        ----------
        codes : int or list, optional
            bit pattern to wait for
            if codes is not set (None) the function returns for any
            event that differs from the baseline
        duration : int, optional
            maximal time to wait in ms
        no_clear_buffer : bool, optional
            do not clear the buffer (default = False)
        bitwise_comparison : bool, optional
            make a bitwise comparison (default = False)
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        key : int
            key code (or None) that quitted waiting
        rt : int
            reaction time

        """

        start = Clock._cpu_time()
        rt = None
        if not no_clear_buffer:
            self.clear()
        while True:
            expyriment._active_exp._execute_wait_callback()
            if duration is not None:
                if int((Clock._cpu_time() - start) * 1000) > duration:
                    return None, None
            found = self.check(codes, bitwise_comparison)
            if found is not None:
                rt = int((Clock._cpu_time() - start) * 1000)
                break
            if check_for_control_keys:
                if Keyboard.process_control_keys():
                    break
        if self._logging:
            expyriment._active_exp._event_file_log(
                                "{0},received,{1},wait".format(
                                                self.__class__.__name__,
                                                found))
        return found, rt
Esempio n. 9
0
    def blur(self, level):
        """Blur the stimulus.

        This blurs the stimulus, by scaling it down and up by the factor of
        'level'.

        Parameters
        ----------
        level : int
            level of bluring

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        self.scale((1.0 / level, 1.0 / level))
        self.scale((level, level))
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,blured,{0}, level={1}".format(self.id, level), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 10
0
    def save(self):
        """Save file to disk."""

        start = Clock._cpu_time()
        if self._buffer != []:
            with open(self._fullpath, 'a') as f:
                f.write("".join(self._buffer))
            self._buffer = []
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 11
0
    def save(self):
        """Save the new data to data-file.

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = Clock._cpu_time()
        if len(self._subject_info) > 0 or len(self._experiment_info) > 0  \
                        or self._variable_names_changed:
            # Re-write header and varnames
            tmpfile_name = "{0}/{1}".format(self.directory, uuid.uuid4())
            os.rename(self._fullpath, tmpfile_name)
            fl = open(self._fullpath, 'w+')
            tmpfl = open(tmpfile_name, 'r')
            section = None
            while True:
                line = tmpfl.readline()
                if not line:
                    break
                if line.startswith(self.comment_char + "e"):
                    section = "e"
                elif line.startswith(self.comment_char + "s"):
                    section = "s"
                else:
                    if section == "e":  # Previous line was last #e
                        if len(self._experiment_info) > 0:
                            fl.write("".join(self._experiment_info))
                            self._experiment_info = []
                        section = None
                    elif section == "s":  # Previous line was last #s
                        if len(self._subject_info) > 0:
                            fl.write("".join(self._subject_info))
                            self._subject_info = []
                        section = None

                        # Re-write variable names after #s-section
                        fl.write(self.variable_names + defaults.outputfile_eol)
                        self._variable_names_changed = False
                        line = '' # Skip old varnames
                fl.write(line)
            tmpfl.close()
            fl.close()

            os.remove(tmpfile_name)
            self._subject_info = []
            self._experiment_info = []

        if self._buffer != []:
            OutputFile.save(self)
            if self._logging:
                expyriment._active_exp._event_file_log("Data,saved")

        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 12
0
    def wait(self, events, duration=None):
        """Wait for (a) certain event(s).

        Events to wait for are in the form of a list with 4 elements and do
        not include a timestamp: [status, data1, data2, data3]

        Parameters
        ----------
        events : int or list
            event(s) to wait for
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        evt : int
            found event
        rt : int
            reaction timein ms

        """

        start = Clock._cpu_time()
        rt = None
        _event = None
        self.clear()
        if type(events) is list and \
           len(events) == 4 and \
           type(events[0]) is int and \
           type(events[1]) is int and \
           type(events[2]) is int and \
           type(events[3]) is int:
            events = [events]
        done = False
        while not done:
            expyriment._active_exp._execute_wait_callback()
            event = self.read(1)
            if event is not None and event[0][0] in events:
                rt = int((Clock._cpu_time() - start) * 1000)
                _event = event[0][0]
                done = True
                break
            if Keyboard.process_control_keys():
                done = True
                break
            if duration:
                if int((Clock._cpu_time() - start) * 1000) >= duration:
                    done = True
                    break

            time.sleep(0.0005)

        if self._logging:
            expyriment._active_exp._event_file_log(
                "MIDI In ({0}),received,{1},wait".format(self.id, _event), 2)
        return _event, rt
Esempio n. 13
0
    def preload(self, inhibit_ogl_compress=False):
        """Preload the stimulus to memory.

        This will prepare the stimulus for a fast presentation.
        In OpenGL mode this method creates an OpenGL texture based on the
        surface of the stimulus.
        When OpenGL is switched off, this method will create a surface if it
        doesn't exists yet.
        If stimuli are not preloaded manually, this will happen
        automatically during presentation. However, stimulus presentation will
        take some time then!

        Always preload your stimuli when a timing acurate presentation is
        needed!

        Parameters
        ----------
        inhibit_ogl_compress : bool, optional
            inhibits OpenGL stimuli to be automatically compressed
            (default=False)

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if not expyriment._active_exp.is_initialized:
            message = "Can't preload stimulus. Expyriment needs to be \
initilized before preloading a stimulus."
            raise RuntimeError(message)
        self._was_compressed_before_preload = self.is_compressed
        if not self.is_preloaded:
            if expyriment._active_exp.screen.open_gl:
                self._ogl_screen = _LaminaPanelSurface(
                    self._get_surface(),
                    position=self.position)
                if not inhibit_ogl_compress:
                    self.compress()
            else:
                self.decompress()
                self._set_surface(self._get_surface())
            self._is_preloaded = True
        if self._logging:
            expyriment._active_exp._event_file_log(
                                "Stimulus,preloaded,{0}".format(self.id), 2)

        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 14
0
    def present(self, clear=True, update=True):
        """Present the stimulus on the screen.

        This clears and updates the screen automatically.
        When not preloaded, depending on the size of the stimulus, this method
        can take some time to compute!

        Parameters
        ----------
        clear : bool, optional
            if True the screen will be cleared automatically
            (default = True)
        update : bool, optional
            if False the screen will be not be updated automatically
            (default = True)

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        if not expyriment._active_exp.is_initialized or\
                             expyriment._active_exp.screen is None:
            raise RuntimeError("Cannot not find a screen!")

        start = Clock._cpu_time()
        preloading_required = not(self.is_preloaded)

        if clear:
            expyriment._active_exp.screen.clear()
        if preloading_required:
            # Check if stimulus has surface
            keep_surface = self.has_surface
            self.preload(inhibit_ogl_compress=True)

        if expyriment._active_exp.screen.open_gl:
            self._ogl_screen.display()
        else:
            screen = expyriment._active_exp.screen.surface
            rect = pygame.Rect((0, 0), self.surface_size)
            screen_size = screen.get_size()
            rect.center = [self.position[0] + screen_size[0] / 2,
                           - self.position[1] + screen_size[1] / 2]
            screen.blit(self._get_surface(), rect)
        if self._logging:
            expyriment._active_exp._event_file_log("Stimulus,presented,{0}"\
                                   .format(self.id), 1)
        if update:
            expyriment._active_exp.screen.update()
        if preloading_required:
            self.unload(keep_surface=keep_surface)

        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 15
0
    def scale(self, factors):
        """Scale the stimulus.

        This is a surface operation. After this, a surface will be present!
        Negative scaling values will flip the stimulus.
        Scaling goes along with a quality loss. Thus, scaling an already
        scaled stimulus is not a good idea.

        Parameters
        ----------
        factors : (int, int) or float
            tuple representing the x and y factors to scale or a single number.
            In the case of a single number x and y scaling will be the
            identical (i.e., proportional scaling)

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "scale()"))
        self.unload(keep_surface=True)
        flip = [False, False]
        if type(factors) in [types.IntType, types.FloatType]:
            factors = [factors, factors]
        else:
            factors = list(factors)
        if factors[0] < 0:
            flip[0] = True
            factors[0] = abs(factors[0])
        if factors[1] < 0:
            flip[1] = True
            factors[1] = abs(factors[1])
        self._set_surface(pygame.transform.smoothscale(
            self._get_surface(),
            (int(round(self.surface_size[0] * factors[0])),
             int(round(self.surface_size[1] * factors[1])))))
        if True in flip:
            self.flip(flip)
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,sclaed,{0}, factors={1}".format(self.id, factors), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 16
0
    def unload(self, keep_surface=False):
        """Unload the stimulus from memory.

        This will unload preloaded stimuli.
        In OpenGL mode, this method will remove the reference to the OpenGL
        texture and the surface (when 'keep_surface' is False).
        When OpenGL is switched off, the reference to the surface will be
        removed (when 'keep_surface' is False).

        Parameters
        ----------
        keep_surface : bool, optional
            keep the surface after unload (default=False)

        Returns
        -------
        time : int
            the time it took to execute this method

        See Also
        --------
        clear_surface.

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if expyriment._active_exp.screen.open_gl:
            self._ogl_screen = None
            if self.is_preloaded and not self._was_compressed_before_preload \
                and keep_surface:
                self.decompress()
        else: # Pygame surface
            if self.is_preloaded and self._was_compressed_before_preload \
                and keep_surface:
                self.compress()
        if self.is_preloaded and self._logging:
            expyriment._active_exp._event_file_log("Stimulus,unloaded,{0}"\
                                       .format(self.id), 2)
        if not keep_surface:
            self._is_compressed = False
            self._surface = None
            if self._logging:
                expyriment._active_exp._event_file_log("Stimulus,surface cleared,{0}"\
                                       .format(self.id), 2)

        self._is_preloaded = False
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 17
0
    def wait_press(self, buttons=None, duration=None):
        """Wait for gamepad button press.

        Returns the found button and the reaction time.

        Parameters
        ----------
        buttons : int or list, optional
            specific buttons to wait for
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        button : int
            button _id of the pressed button
        rt : int
            reaction time in ms

        """

        start = Clock._cpu_time()
        rt = None
        _button = None
        self.clear()
        if buttons is None:
            buttons = range(self.get_numbuttons())
        if type(buttons) is not list:
            buttons = [buttons]
        done = False
        while not done:
            expyriment._active_exp._execute_wait_callback()
            for button in buttons:
                if self.get_button(button):
                    _button = button
                    rt = int((Clock._cpu_time() - start) * 1000)
                    done = True
                    break
                if _button is not None or Keyboard.process_control_keys():
                    done = True
                    break
                if duration:
                    if int((Clock._cpu_time() - start) * 1000) >= duration:
                        done = True
                        break

            time.sleep(0.0005)

        if self._logging:
            expyriment._active_exp._event_file_log("Gamepad,received,{0},wait_press".format(_button))
        return _button, rt
Esempio n. 18
0
    def scramble(self, grain_size):
        """Scramble the stimulus.

        Attention: If the surface size is not a multiple of the grain size,
        you may loose some pixels on the edge.

        Parameters
        ----------
        grain_size : int or (int, int)
            size of a grain (use tuple of integers for different width & height)

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if type(grain_size) is int:
            grain_size = [grain_size, grain_size]
        # Make Rect list
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "scramble()"))
        s = self.surface_size
        source = []
        for r in range(s[1] / int(grain_size[1])):
            for c in range(s[0] / int(grain_size[0])):
                xy = (c * int(grain_size[0]), r * int(grain_size[1]))
                source.append(pygame.Rect(xy, grain_size))
        # Make copy and shuffle
        dest = copy.deepcopy(source)
        random.shuffle(dest)
        # Create a new surface
        tmp_surface = pygame.surface.Surface(
            s, pygame.SRCALPHA).convert_alpha()
        for n, s in enumerate(source):
            tmp_surface.blit(self._get_surface(), dest[n], s)
        self._set_surface(tmp_surface)

        if self._logging:
            expyriment._active_exp._event_file_log(
                            "Stimulus,scrambled,{0}, grain_size={1}".format(
                                     self.id, grain_size), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 19
0
    def create_mask(self):
        """Creates a new visual mask.

        Notes
        -----
        CAUTION: Depending on the size of the stimulus, this method may take
        some time to execute.

        Returns
        -------
        time  : int
            the time it took to execute this method in ms

        """

        start = Clock._cpu_time()
        was_preloaded = self.is_preloaded
        if was_preloaded:
            self.unload()

        s = (self._size[0] + 4 * self.smoothing,
             self._size[1] + 4 * self.smoothing) #somewhat larger mask 
        im = Image.new("RGB", s)
        draw = ImageDraw.Draw(im)
        draw.rectangle([(0, 0), s], outline=self.background_colour,
                       fill=self.background_colour)

        n_dots_x = int(s[0] / self.dot_size[0]) + 1
        n_dots_y = int(s[1] / self.dot_size[1]) + 1
        dots = range(n_dots_x * n_dots_y)
        shuffle(dots)
        for d in dots[:int(len(dots) * self.dot_percentage / 100)]:
            y = (d / n_dots_x) * self.dot_size[1]
            x = (d % n_dots_x) * self.dot_size[0]
            draw.rectangle([(x, y),
                            (x + self.dot_size[0], y + self.dot_size[1])],
                           outline=self.dot_colour, fill=self.dot_colour)

        for x in range(self.smoothing):
            im = im.filter(ImageFilter.BLUR).filter(ImageFilter.SMOOTH_MORE)

        #crop image and save
        c = (im.size[0] / 2, im.size[1] / 2)
        box = (c[0] - self._size[0] / 2, c[1] - self._size[1] / 2,
               c[0] + self._size[0] / 2, c[1] + self._size[1] / 2)
        im = im.crop(box)
        im.save(self._filename, format="png")

        if was_preloaded:
            self.preload()
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 20
0
    def wait_char(self, char, duration=None, check_for_control_keys=True):
        """Wait for character(s) (optionally for a certain amount of time).

        This function will wait for one or more characters and returns the
        found character as well as the reaction time.
        (This function clears the event queue!)

        Parameters
        ----------
        char : int or list
            a specific character or list of characters to wait for
        duration : int, optional
            maximal time to wait in ms
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        found : char
            pressed charater
        rt : int
            reaction time in ms

        """

        start = Clock._cpu_time()
        rt = None
        found_char = None
        self.clear()
        if type(char) is not list:
            char = [char]
        pygame.event.pump()
        done = False
        while not done:
            expyriment._active_exp._execute_wait_callback()
            for event in pygame.event.get():
                if check_for_control_keys and Keyboard.process_control_keys(event):
                    done = True
                elif event.type == pygame.KEYDOWN:
                    if event.unicode in char:
                        rt = int((Clock._cpu_time() - start) * 1000)
                        found_char = event.unicode
                        done = True
            if duration and not done:
                done = int((Clock._cpu_time() - start) * 1000) >= duration
            time.sleep(0.0005)
        if self._logging:
            expyriment._active_exp._event_file_log(
                        "Keyboard,received,{0},wait_char".format(found_char))
        return found_char, rt
Esempio n. 21
0
    def add_noise(self, grain_size, percentage, colour):
        """Add visual noise on top of the stimulus.

        This function might take very long for large stimuli.

        Parameters
        ----------
        grain_size : int
            size of the grains for the noise
        percentage : int
            percentage of covered area
        colour : (int, int, int)
            colour (RGB) of the noise

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """
        import _rectangle
        start = Clock._cpu_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "add_noise()"))
        self.unload(keep_surface=True)
        number_of_pixel_x = int(self.surface_size[0] / grain_size) + 1
        number_of_pixel_y = int(self.surface_size[1] / grain_size) + 1
        seq = range(number_of_pixel_x * number_of_pixel_y)
        random.seed()
        random.shuffle(seq)

        for idx in seq[:int(len(seq) * (percentage) / 100.0)]:
            x = (idx % number_of_pixel_x) * grain_size
            x = int(self.surface_size[0] / 2 - grain_size / 2 - x)
            y = (idx / number_of_pixel_x) * grain_size
            y = int(self.surface_size[1] / 2 - grain_size / 2 - y)
            dot = _rectangle.Rectangle((grain_size, grain_size), (x, y), colour)
            dot.plot(self)
        if self._logging:
            expyriment._active_exp._event_file_log(
                    "Stimulus,noise added,{0}, grain_size={1}, percentage={2}"\
                        .format(self.id, grain_size, percentage))
        return int((Clock._cpu_time() - start) * 1000)
    def __init__(self, position, direction, speed, lifetime, extra_age=0, north_up_clockwise=True, is_target=False):
        """Create a MovingPosition

        Parameters
        ----------
        position : (int, int)
            start position
        direction : int, float (0-360)
            movement direction in degrees
        speed : int
            the moving speed in pixel per second
        lifetime : int
            the time the object lives in milliseconds
        extra_age : int, optional
            the object can have already an age when creating or resetting
            (default=0)
        north_up_clockwise : bool, optional
            if true (default) all directional information refer to an
            north up and clockwise system
            otherwise 0 is right, counterclockwise (default=True)
        is_target : bool
            target position

        """
        self._start_position = list(position)
        self.lifetime = lifetime
        self.extra_age = extra_age  # add extra age for shorter lifetime
        self.is_target = is_target
        self._speed = speed
        self._north_up_clockwise = (north_up_clockwise,)
        self._direction = direction
        self._update_movement_vector()
        self._clock = Clock()
Esempio n. 23
0
    def _test2():
        info = """This will test if stimulus presentation can be synchronized to the refreshrate of the screen.
A good result is a fast, constant and smooth flickering without any distortions (e.g. horizontal stripes, tearing).
The estimated refreshrate should resemble your actual screen refreshrate (common refreshrates are between 40 and 240 Hz).

[Press RETURN to continue]"""

        text = stimuli.TextScreen("Stimulus presentation test (2)", info)
        text.present()
        exp.keyboard.wait([constants.K_RETURN])
        black = stimuli.BlankScreen(colour=constants.C_BLACK)
        black.preload()
        white = stimuli.BlankScreen(colour=constants.C_WHITE)
        white.preload()
        times = []
        black.present()
        for _x in range(100):
            start = Clock._cpu_time()
            black.present()
            times.append(Clock._cpu_time() - start)
            start = Clock._cpu_time()
            white.present()
            times.append(Clock._cpu_time() - start)
        refresh_rate = 1000 / (statistics.mean(times) * 1000)
        info = """Your estimated refresh rate is {0} Hz.

[Press RETURN to continue]
""".format(refresh_rate)
        text = stimuli.TextScreen("Results", info)
        text.present()
        exp.keyboard.wait([constants.K_RETURN])
        text = stimuli.TextScreen(
            "Was the flickering fast, constant and smooth, without any distortions?",
            "[Press Y or N]")
        text.present()
        key, _rt = exp.keyboard.wait([constants.K_y,
                                      constants.K_n])
        if key == constants.K_y:
            response2 = "Yes"
        elif key == constants.K_n:
            response2 = "No"

        return refresh_rate, response2
    def __init__(self,
                 position,
                 direction,
                 speed,
                 lifetime,
                 extra_age=0,
                 north_up_clockwise=True,
                 is_target=False):
        """Create a MovingPosition

        Parameters
        ----------
        position : (int, int)
            start position
        direction : int, float (0-360)
            movement direction in degrees
        speed : int
            the moving speed in pixel per second
        lifetime : int
            the time the object lives in milliseconds
        extra_age : int, optional
            the object can have already an age when creating or resetting
            (default=0)
        north_up_clockwise : bool, optional
            if true (default) all directional information refer to an
            north up and clockwise system
            otherwise 0 is right, counterclockwise (default=True)
        is_target : bool
            target position

        """
        self._start_position = list(position)
        self.lifetime = lifetime
        self.extra_age = extra_age  # add extra age for shorter lifetime
        self.is_target = is_target
        self._speed = speed
        self._north_up_clockwise = north_up_clockwise,
        self._direction = direction
        self._update_movement_vector()
        self._clock = Clock()
    def present_and_wait_keyboard(self,
                                  background_stimulus=None,
                                  check_keys=None,
                                  change_parameter=(None, None),
                                  duration=None,
                                  button_box=None):
        """Present the random dot kinematogram and wait for keyboard press.

        Parameters:
        -----------
        background_stimulus : Expyriment stimulus, optional
            optional stimulus to be plotted in the background
            (default=None)
        check_keys : int or list, optional
            a specific key or list of keys to check
        change_parameter : tuple (int, int), optional, default = (None, None)
            [step size (target dot ratio), step interval (ms)]
            if both parameter are defined (not None), target dot ratio changes
            accordingly while presentation
        duration: int, optional
            maximum duration to wait for keypress
        button_box: expyriment io.ButtonBox object, optional
            if not the keyboard but a button_box should be used
            (e.g. io.StreamingButtonBox)

        """
        from expyriment import _active_exp
        RT = Clock()
        if button_box is None:
            button_box = _active_exp.keyboard
        button_box.clear()
        self.reset_all_ages(randomize_ages=True)
        last_change_time = RT.stopwatch_time
        while (True):
            if None not in change_parameter:
                if RT.stopwatch_time >= change_parameter[1] + last_change_time:
                    last_change_time = RT.stopwatch_time
                    self.target_dot_ratio = self.target_dot_ratio + \
                                    change_parameter[0]
            self.make_frame(background_stimulus=background_stimulus).present()

            if isinstance(button_box, Keyboard):
                key = button_box.check(keys=check_keys)
            else:
                _active_exp.keyboard.process_control_keys()
                key = button_box.check(codes=check_keys)

            if key is not None:
                break
            if duration is not None and RT.stopwatch_time >= duration:
                return (None, None)
        return key, RT.stopwatch_time
Esempio n. 26
0
    def plot(self, stimulus):
        """Plot the stimulus on the surface of another stimulus.

        Use this to plot more than one stimulus and to present them at the
        same time afterwards by presenting the stimulus on which they were
        plotted on.

        Parameters
        ----------
        stimulus : expyriment stimulus
            stimulus to whose surface should be plotted

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = Clock._cpu_time()
        if not stimulus._set_surface(stimulus._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "plot()"))
        stimulus.unload(keep_surface=True)
        self._parent = stimulus
        rect = pygame.Rect((0, 0), self.surface_size)
        stimulus_surface_size = stimulus.surface_size
        rect.center = [self.position[0] + stimulus_surface_size[0] / 2,
                       - self.position[1] + stimulus_surface_size[1] / 2]
        stimulus._get_surface().blit(self._get_surface(), rect)
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,plotted,{0},{1}".format(self.id, stimulus.id), 2)
        return int((Clock._cpu_time() - start) * 1000)
Esempio n. 27
0
    def wait(self, code=None, bitwise_comparison=False):
        """Wait for a trigger.

        Returns the code received and the reaction time [code, rt].

        If bitwise_comparison = True, the function performs a bitwise
        comparison (logical and) between code and received input and waits
        until a certain bit pattern is set.

        Parameters
        code -- a specific code to wait for (int) (optional)
        bitwise_comparison -- make a bitwise comparison (default=False)

        """

        start = Clock._cpu_time()
        found = None
        rt = None
        if code is None:
            code = self._default_code
        self.interface.clear()
        while True:
            expyriment._active_exp._execute_wait_callback()
            read = self.interface.poll()
            if read is not None:
                if code is None: #return for every event
                    rt = int((Clock._cpu_time() - start) * 1000)
                    found = read
                    break
                elif compare_codes(read, code, bitwise_comparison):
                    rt = int((Clock._cpu_time() - start) * 1000)
                    found = read
                    break
            if Keyboard.process_control_keys():
                    break
        if self._logging:
            expyriment._active_exp._event_file_log(
                            "TriggerInput,received,{0},wait".format(found))
        return found, rt
def client(server_ip):
    # t : test connect
    # q : quit client
    # space : enter

    control.set_develop_mode(True)
    control.defaults.audiosystem_autostart = False
    exp = control.initialize()

    udp_connection = UDPConnection()
    print(udp_connection)

    if not udp_connection.connect_peer(server_ip):
        print("error connecting to peer")
        exit()

    stimuli.TextScreen(
        "connected to " + udp_connection.peer_ip,
        "\nSPACE: send text\nT: trigger test\nQ: quit").present()

    c = Clock()

    while True:
        key = exp.keyboard.check()
        if key == ord("q"):
            break
        elif key == misc.constants.K_SPACE:
            text = io.TextInput().get()
            stimuli.BlankScreen().present()
            print("send: {} {}".format(c.time, text))
            udp_connection.send(text)
        elif key == ord("t"):
            times = []
            for cnt in range(20):
                stimuli.TextLine("ping test " + str(cnt)).present()
                c.reset_stopwatch()
                ok, time = udp_connection.ping(timeout=1)
                print("answer received in {} ms".format(c.stopwatch_time))
                times.append(time)
                c.wait(100)
            stimuli.BlankScreen().present()
            print(times)

        feedback = udp_connection.poll()
        if feedback is not None:
            print("received: {} {}".format(c.time, feedback))

    udp_connection.unconnect_peer()
Esempio n. 29
0
    def __init__(self,
                 port,
                 baudrate=None,
                 bytesize=None,
                 parity=None,
                 stopbits=None,
                 timeout=None,
                 xonxoff=None,
                 rtscts=None,
                 dsrdtr=None,
                 input_history=None,
                 os_buffer_size=None,
                 clock=None):
        """Create a serial port input and output.

        The port argument will accept the number of the port (e.g. 0 for COM1)
        as well as a string describing the full port location ("COM1" or
        "/dev/ttyS0").

        Notes
        -----
        An input_history can be used to overcome the size limitation of the
        receive buffer of the operating system. An input_history consists of a
        misc.ByteBuffer instance.
        In order to not miss any input, the serial port has to be updated
        regularly (i.e. calling read_input() or clear() before the receive
        buffer will be full). If the receive buffer size is set correctly, a
        warning will be given, when the input_history was not updated fast
        enough.
        Importantly, the fuller the receive buffer is, the longer clearing
        and polling will take (this can be more than 1 ms!), since all the
        bytes have to be transfered to the input_history.

        Parameters
        ----------
        port : int or str
            port to use
        baudrate : int, optional
        bytesize : int, optional
        parity : str, optional
            parity:'E'=even, 'O'=odd, 'N'=none
        stopbits : int, optional
        timeout : int, optional
            the timeout for read(): -1=block
        xonxoff : int, optional
        rtscts : int, optional
        dsrdtr : int, optional
        input_history : bool, optional
            True if an input_history should be used
        os_buffer_size : int, optional
            the size of the receive input_history provided by the operating
            system in bytes
        clock : misc.Clock, optional
            an experimental clock
                            (optional)

        """

        import types
        if type(serial) is not types.ModuleType:
            message = """SerialPort can not be initialized.
The Python package 'pySerial' is not installed."""
            raise ImportError(message)

        if float(serial.VERSION) < 2.5:
            raise ImportError(
                "Expyriment {0} ".format(__version__) +
                "is not compatible with PySerial {0}.".format(serial.VERSION) +
                "\nPlease install PySerial 2.5 or higher.")

        Input.__init__(self)
        Output.__init__(self)
        if baudrate is None:
            baudrate = defaults.serialport_baudrate
        if bytesize is None:
            bytesize = defaults.serialport_bytesize
        if parity is None:
            parity = defaults.serialport_parity
        if stopbits is None:
            stopbits = defaults.serialport_stopbits
        if timeout is None:
            timeout = defaults.serialport_timeout
        if timeout == -1:
            timeout = None
        if xonxoff is None:
            xonxoff = defaults.serialport_xonxoff
        if rtscts is None:
            rtscts = defaults.serialport_rtscts
        if dsrdtr is None:
            dsrdtr = defaults.serialport_dsrdtr
        if clock is not None:
            self._clock = clock
        else:
            if expyriment._active_exp.is_initialized:
                self._clock = expyriment._active_exp.clock
            else:
                self._clock = Clock()
        if input_history is None:
            input_history = defaults.serialport_input_history
        if input_history is True:
            self._input_history = ByteBuffer(
                name="SerialPortBuffer (Port {0})".format(repr(port)),
                clock=self._clock)
        else:
            self._input_history = False
        if os_buffer_size is None:
            os_buffer_size = defaults.serialport_os_buffer_size
        self._os_buffer_size = os_buffer_size

        self._serial = serial.Serial(port, baudrate, bytesize, parity,
                                     stopbits, timeout, xonxoff, rtscts,
                                     dsrdtr)
        if not self._serial.isOpen():
            raise IOError("Could not open serial port")

        atexit.register(self.close)
Esempio n. 30
0
# space : enter


control.set_develop_mode(True)
exp = control.initialize()

udp_connection = UDPConnection()
print udp_connection

if not udp_connection.connect_peer("192.168.1.1"):  # 41.89.98.24
    print "error connecting to peer"
    exit()

stimuli.TextLine("connected to " + udp_connection.peer_ip).present()

c = Clock()

# #udp.send("maximum: 72")
##udp.send("measurement: 25")
##udp.send("filename: test")
##udp.send("report: 5")
##print "--> ", c.time, "done"
##udp.send("done")
##feedback = udp.poll()
##while feedback is None:
##    feedback = udp.poll()
##print "<-- ", c.time,  feedback
##
##print "--> ", c.time, "start"
##udp.send("start")
##feedback = udp.poll()
Esempio n. 31
0
    def wait(self, keys=None, duration=None, wait_for_keyup=False,
             check_for_control_keys=True):
        """Wait for keypress(es) (optionally for a certain amount of time).

        This function will wait for a keypress and returns the found key as
        well as the reaction time.
        (This function clears the event queue!)

        Parameters
        ----------
        keys : int or list, optional
            a specific key or list of keys to wait for
        duration : int, optional
            maximal time to wait in ms
        wait_for_keyup : bool, optional
            if True it waits for key-up
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        """

        if android is not None:
            android.show_keyboard()
        start = Clock._cpu_time()
        rt = None
        found_key = None
        self.clear()
        if keys is None:
            keys = self.default_keys
        if keys is not None and type(keys) is not list:
            keys = [keys]
        if wait_for_keyup:
            target_event = pygame.KEYUP
        else:
            target_event = pygame.KEYDOWN
        pygame.event.pump()
        done = False
        while not done:
            expyriment._active_exp._execute_wait_callback()
            for event in pygame.event.get():
                if check_for_control_keys and Keyboard.process_control_keys(event):
                    done = True
                elif event.type == target_event:
                    if keys is not None:
                        if event.key in keys:
                            rt = int((Clock._cpu_time() - start) * 1000)
                            found_key = event.key
                            done = True
                    else:
                        rt = int((Clock._cpu_time() - start) * 1000)
                        found_key = event.key
                        done = True
            if duration and not done:
                done = int((Clock._cpu_time() - start) * 1000) >= duration
            time.sleep(0.0005)
        if self._logging:
            expyriment._active_exp._event_file_log("Keyboard,received,{0},wait"\
                                              .format(found_key))
        if android is not None:
            android.hide_keyboard()
        return found_key, rt
class MovingPosition(object):
    def __init__(self,
                 position,
                 direction,
                 speed,
                 lifetime,
                 extra_age=0,
                 north_up_clockwise=True,
                 is_target=False):
        """Create a MovingPosition

        Parameters
        ----------
        position : (int, int)
            start position
        direction : int, float (0-360)
            movement direction in degrees
        speed : int
            the moving speed in pixel per second
        lifetime : int
            the time the object lives in milliseconds
        extra_age : int, optional
            the object can have already an age when creating or resetting
            (default=0)
        north_up_clockwise : bool, optional
            if true (default) all directional information refer to an
            north up and clockwise system
            otherwise 0 is right, counterclockwise (default=True)
        is_target : bool
            target position

        """
        self._start_position = list(position)
        self.lifetime = lifetime
        self.extra_age = extra_age  # add extra age for shorter lifetime
        self.is_target = is_target
        self._speed = speed
        self._north_up_clockwise = north_up_clockwise,
        self._direction = direction
        self._update_movement_vector()
        self._clock = Clock()

    @property
    def is_dead(self):
        """Return True is lifetime of the object is over"""
        return (self.age >= self.lifetime)

    @property
    def age(self):
        """Return the age of a dot"""
        return self._clock.stopwatch_time + self.extra_age

    def reset_age(self, randomize_age=False):
        """Reset the age to zero (born at current time) or if randomize_age=True, age will randomized."""
        if randomize_age:
            self.extra_age = int(random.random() * self.lifetime)
        self._clock.reset_stopwatch()

    def is_outside(self, the_range):
        """Return True the object is outside the range from (0,0)"""
        pos = self.position
        return (math.hypot(pos[0], pos[1]) >= the_range)

    @property
    def north_up_clockwise(self):
        """getter for north up and clockwise"""
        return self._north_up_clockwise

    @property
    def position(self):
        """The current position (depends on time).
        Note: This property changes continuously over time, since the
        position is moving.

        """
        return (self._start_position[0] +
                self._clock.stopwatch_time * self._movement_vector[0],
                self._start_position[1] +
                self._clock.stopwatch_time * self._movement_vector[1])

    @property
    def direction(self):
        """Getter for direction."""
        return self._direction

    @property
    def speed(self):
        """Getter for speed."""
        return self._speed

    @direction.setter
    def direction(self, x):
        self._direction = x
        self._update_movement_vector()

    @speed.setter
    def speed(self, x):
        """speed in pix per second"""
        self._speed = x
        self._update_movement_vector()

    def _update_movement_vector(self):
        if self._north_up_clockwise:
            direction = 450 - self._direction
        else:
            direction = self._direction
        angle = direction * (math.pi) / 180
        speed = self._speed / float(1000)
        self._movement_vector = (speed * math.cos(angle),
                                 speed * math.sin(angle))
Esempio n. 33
0
            for i, w in enumerate(f.split()):
                if not w in maptext:
                    maptext[w] = stimuli.TextLine(w)
                    maptext[w].preload()
                events.put((onset + i * WORD_DURATION, 'text', w, maptext[w]))
            events.put((onset + (i + 1) * WORD_DURATION, 'blank', 'blank', bs))

#%

expyriment.control.start()

wm.present()
kb.wait_char('t')  # wait for scanner TTL
fs.present()  # clear screen, presenting fixation cross

a = Clock()

while not (events.empty()):
    onset, stype, id, stim = events.get()
    print('event {} {} @ {}'.format(stype, id, onset))
    if a.time > onset:
        print('...delayed @ {}'.format(a.time))  # TODO
    while a.time < (onset - 10):
        a.wait(10)
        k = kb.check()
        if k is not None:
            print('keypressed: {} @ {}'.format(k, a.time))
            exp.data.add([a.time, k])

    stim.present()
class MovingPosition(object):
    def __init__(self, position, direction, speed, lifetime, extra_age=0, north_up_clockwise=True, is_target=False):
        """Create a MovingPosition

        Parameters
        ----------
        position : (int, int)
            start position
        direction : int, float (0-360)
            movement direction in degrees
        speed : int
            the moving speed in pixel per second
        lifetime : int
            the time the object lives in milliseconds
        extra_age : int, optional
            the object can have already an age when creating or resetting
            (default=0)
        north_up_clockwise : bool, optional
            if true (default) all directional information refer to an
            north up and clockwise system
            otherwise 0 is right, counterclockwise (default=True)
        is_target : bool
            target position

        """
        self._start_position = list(position)
        self.lifetime = lifetime
        self.extra_age = extra_age  # add extra age for shorter lifetime
        self.is_target = is_target
        self._speed = speed
        self._north_up_clockwise = (north_up_clockwise,)
        self._direction = direction
        self._update_movement_vector()
        self._clock = Clock()

    @property
    def is_dead(self):
        """Return True is lifetime of the object is over"""
        return self.age >= self.lifetime

    @property
    def age(self):
        """Return the age of a dot"""
        return self._clock.stopwatch_time + self.extra_age

    def reset_age(self, randomize_age=False):
        """Reset the age to zero (born at current time) or if randomize_age=True, age will randomized."""
        if randomize_age:
            self.extra_age = int(random.random() * self.lifetime)
        self._clock.reset_stopwatch()

    def is_outside(self, the_range):
        """Return True the object is outside the range from (0,0)"""
        pos = self.position
        return math.hypot(pos[0], pos[1]) >= the_range

    @property
    def north_up_clockwise(self):
        """getter for north up and clockwise"""
        return self._north_up_clockwise

    @property
    def position(self):
        """The current position (depends on time).
        Note: This property changes continuously over time, since the
        position is moving.

        """
        return (
            self._start_position[0] + self._clock.stopwatch_time * self._movement_vector[0],
            self._start_position[1] + self._clock.stopwatch_time * self._movement_vector[1],
        )

    @property
    def direction(self):
        """Getter for direction."""
        return self._direction

    @property
    def speed(self):
        """Getter for speed."""
        return self._speed

    @direction.setter
    def direction(self, x):
        self._direction = x
        self._update_movement_vector()

    @speed.setter
    def speed(self, x):
        """speed in pix per second"""
        self._speed = x
        self._update_movement_vector()

    def _update_movement_vector(self):
        if self._north_up_clockwise:
            direction = 450 - self._direction
        else:
            direction = self._direction
        angle = direction * (math.pi) / 180
        speed = self._speed / float(1000)
        self._movement_vector = (speed * math.cos(angle), speed * math.sin(angle))