Пример #1
0
    def draw_markers(self):

        # The paint of markers in between white keys
        white_white_paint = skia.Paint(
            AntiAlias=True,
            Color=skia.Color4f(
                *self.global_colors["marker_color_between_two_white"], 1),
            Style=skia.Paint.kStroke_Style,
            StrokeWidth=1,
        )

        current_center = 0

        # Check if prev and this key is white, keeps track of a current_center, create rect to draw and draw
        for index, key_index in enumerate(self.piano_keys.keys()):
            key = self.piano_keys[key_index]
            if not index == 0:
                prevkey = self.piano_keys[key_index - 1]
                if (prevkey.is_white) and (key.is_white):
                    current_center += self.tone_width
                    rect = skia.Rect(current_center - self.semitone_width, 0,
                                     current_center - self.semitone_width,
                                     self.mmvskia_main.context.height)
                    self.mmvskia_main.skia.canvas.drawRect(
                        rect, white_white_paint)
                else:
                    current_center += self.semitone_width

        # Ask each key to draw their CENTERED marker
        for key_index in self.piano_keys.keys():
            self.piano_keys[key_index].draw_marker()
    def draw_markers(self):

        c = 0.35
        white_white_color = skia.Color4f(c, c, c, 1)

        white_white_paint = skia.Paint(
            AntiAlias=True,
            Color=white_white_color,
            Style=skia.Paint.kStroke_Style,
            StrokeWidth=1,
        )

        current_center = 0

        for index, key_index in enumerate(self.piano_keys.keys()):
            key = self.piano_keys[key_index]
            if not index == 0:
                prevkey = self.piano_keys[key_index - 1]
                if (prevkey.is_white) and (key.is_white):
                    current_center += self.tone_width
                    rect = skia.Rect(current_center - self.semitone_width, 0,
                                     current_center + 1 - self.semitone_width,
                                     self.vectorial.context.height)
                    self.skia.canvas.drawRect(rect, white_white_paint)
                else:
                    current_center += self.semitone_width

        for key_index in self.piano_keys.keys():
            self.piano_keys[key_index].draw_marker()
Пример #3
0
 def get_image(self):
 #===================
     # Draw image to fit tile set's pixel rectangle
     surface = skia.Surface(int(self.__scaling[0]*self.__size[0] + 0.5),
                            int(self.__scaling[1]*self.__size[1] + 0.5))
     canvas = surface.getCanvas()
     canvas.clear(skia.Color4f(0xFFFFFFFF))
     self.__svg_drawing.draw_element(canvas, self.__bbox)
     log('Making image snapshot...')
     image = surface.makeImageSnapshot()
     return image.toarray(colorType=skia.kBGRA_8888_ColorType)
Пример #4
0
    def get_tile(self, tile):
    #========================
        surface = skia.Surface(*self.__tile_size)  ## In pixels...
        canvas = surface.getCanvas()
        canvas.clear(skia.Color4f(0xFFFFFFFF))
        canvas.translate(self.__pixel_offset[0] + (self.__tile_origin[0] - tile.x)*self.__tile_size[0],
                         self.__pixel_offset[1] + (self.__tile_origin[1] - tile.y)*self.__tile_size[1])
        quadkey = mercantile.quadkey(tile)
        self.__svg_drawing.draw_element(canvas, self.__tile_bboxes.get(quadkey))

        image = surface.makeImageSnapshot()
        return image.toarray(colorType=skia.kBGRA_8888_ColorType)
Пример #5
0
    def configure_color(self):

        # Marker color on sharp keys
        self.marker_color = skia.Color4f(
            *self.piano_roll.global_colors["marker_color_sharp_keys"], 0.1)

        # Marker color between two white keys
        self.marker_color_subtle_brighter = skia.Color4f(
            *self.piano_roll.global_colors["marker_color_between_two_white"],
            0.3)

        # Note is a sharp key, black idle, gray on press
        if "#" in self.name:
            self.color_active = skia.Color4f(
                *self.piano_roll.global_colors["sharp_key_pressed"], 1)
            self.color_idle = skia.Color4f(
                *self.piano_roll.global_colors["sharp_key_idle"], 1)
            self.is_white = False
            self.is_black = True

        # Note is plain key, white on idle, graw on press
        else:
            self.color_active = skia.Color4f(
                *self.piano_roll.global_colors["plain_key_pressed"], 1)
            self.color_idle = skia.Color4f(
                *self.piano_roll.global_colors["plain_key_idle"], 1)
            self.is_white = True
            self.is_black = False
    def parse_colors_dict(self, colors_dict):
        for key, value in colors_dict.items():
            if value is None:
                colors_dict[key] = None
                continue 
            
            if isinstance(value, dict):
                colors_dict[key] = self.parse_colors_dict(colors_dict = value)
                continue

            if isinstance(value[0], int):
                value = [v / 256 for v in value]

            colors_dict[key] = skia.Color4f(*value)
        return colors_dict
Пример #7
0
    def particles(self):

        print(f"Saving generated particle N=[", end="", flush=True)

        # Repeat for N images
        for i in range(self.n_images):

            # Reset canvas to transparent
            self.skia.reset_canvas()

            # How much nodes of gradients in this particle
            npoints = random.randint(1, 6)

            # Random scalars for each node, plus ending at zero
            scalars = [random.uniform(0.2, 1) for _ in range(npoints)] + [0]

            # Colors list
            colors = []

            # Iterate in decreasing order
            for scalar in reversed(sorted(scalars)):
                colors.append(skia.Color4f(1, 1, 1, scalar))

            # Create the skia paint with a circle at the center that ends on the edge
            paint = skia.Paint(Shader=skia.GradientShader.MakeRadial(
                center=(self.width / 2, self.height / 2),
                radius=self.width / 2,
                colors=colors,
            ))

            # Draw the particles
            self.canvas.drawPaint(paint)

            # # Save the image

            # Get the PIL image from the array of the canvas
            img = Image.fromarray(self.skia.canvas_array())

            # Pretty print
            if not i == self.n_images - 1:
                print(f"{i}, ", end="", flush=True)
            else:
                print(f"{i}]")

            # Save the particle to the output dir
            img.save(self.output_dir + f"/particle-{i}.png", quality=100)
    def draw(self, notes_playing):

        if self.is_black:
            away = (self.height * (0.33))
        else:
            away = 0

        coords = [
            self.center_x - (self.width / 2),
            self.resolution_height - self.height,
            self.center_x + (self.width / 2),
            self.resolution_height - away,
        ]

        self.active = self.note in notes_playing

        if self.active:
            color = self.color_active
        else:
            color = self.color_idle

        # Make the skia Paint and
        paint = skia.Paint(
            AntiAlias=True,
            Color=color,
            Style=skia.Paint.kFill_Style,
            StrokeWidth=2,
        )

        border = skia.Paint(
            AntiAlias=True,
            Color=skia.Color4f(0, 0, 0, 1),
            Style=skia.Paint.kStroke_Style,
            StrokeWidth=2,
        )

        # Rectangle border
        rect = skia.Rect(*coords)

        # Draw the border
        self.skia.canvas.drawRect(rect, paint)
        self.skia.canvas.drawRect(rect, border)
Пример #9
0
    def draw(self, notes_playing):

        # If the note is black we leave a not filled spot on the bottom, this is the ratio of it
        away = (self.height * (0.33)) if self.is_black else 0

        # Based on the away, center, width, height etc, get the coords of this piano key
        coords = [
            self.center_x - (self.width / 2),
            self.resolution_height - self.height,
            self.center_x + (self.width / 2),
            self.resolution_height - away,
        ]

        # Is the note active
        self.active = self.note in notes_playing

        # Get the color based on if the note is active or not
        color = self.color_active if self.active else self.color_idle

        # Make the skia Paint and
        key_paint = skia.Paint(
            AntiAlias=True,
            Color=color,
            Style=skia.Paint.kFill_Style,
            StrokeWidth=2,
        )

        # The border of the key
        key_border = skia.Paint(
            AntiAlias=True,
            Color=skia.Color4f(0, 0, 0, 1),
            Style=skia.Paint.kStroke_Style,
            StrokeWidth=2,
        )

        # Rectangle border
        rect = skia.Rect(*coords)

        # Draw the border
        self.mmvskia_main.skia.canvas.drawRect(rect, key_paint)
        self.mmvskia_main.skia.canvas.drawRect(rect, key_border)
    def configure_color(self):

        c = min(self.background_color + (40 / 255), 1)
        self.marker_color = skia.Color4f(c, c, c, 0.1)

        c = min(self.background_color + (60 / 255), 1)
        self.marker_color_subtle_brighter = skia.Color4f(c, c, c, 0.3)

        # Note is a sharp key, black idle, gray on press
        if "#" in self.name:
            self.color_active = skia.Color4f(0, 0, 0, 1)
            self.color_idle = skia.Color4f(0.2, 0.2, 0.2, 1)
            self.is_white = False
            self.is_black = True
        else:
            self.color_active = skia.Color4f(0.7, 0.7, 0.7, 1)
            self.color_idle = skia.Color4f(1, 1, 1, 1)
            self.is_white = True
            self.is_black = False
Пример #11
0
    def build(self, fitted_ffts: dict, frequencies: list, config: dict,
              effects):
        debug_prefix = "[MMVSkiaMusicBarsCircle.build]"

        # We first store the coordinates to draw and their respective paints, draw afterwards
        data = {}

        # # TODO: This code was originally set to have "linear" or "symmetric" modes, I think
        # # we should keep symmetric mode only, that's my opinion

        # Loop on both channels
        for channel in (["l", "r"]):

            # Init blank channel of list of coordinates and paints
            data[channel] = {
                "coordinates": [],
                "paints": [],
            }

            # The FFT of this channel from the dictionary
            this_channel_fft = fitted_ffts[channel]

            # Length of the FFT
            NFFT = len(this_channel_fft)

            # For each magnite of the FFT and their respective index
            for index, magnitude in enumerate(this_channel_fft):

                # This is symmetric, so half a rotation divided by how much bars
                # Remember we're in Radians, pi radians is 180 degrees (half an rotation)
                angle_between_two_bars = math.pi / NFFT

                # We have to start from half a distance between bars and end on a full rotation minus a bars distance
                # depending on the channel we're in
                if channel == "l":
                    theta = self.mmv.functions.value_on_line_of_two_points(
                        Xa=0,
                        Ya=(math.pi / 2) + (angle_between_two_bars / 2),
                        Xb=NFFT,
                        Yb=(math.pi / 2) + math.pi +
                        (angle_between_two_bars / 2),
                        get_x=index,
                    )

                elif channel == "r":
                    theta = self.mmv.functions.value_on_line_of_two_points(
                        Xa=0,
                        Ya=(math.pi / 2) - (angle_between_two_bars / 2),
                        Xb=NFFT,
                        Yb=(math.pi / 2) - math.pi -
                        (angle_between_two_bars / 2),
                        get_x=index,
                    )

                # Scale the magnitude according to the resolution
                magnitude *= self.mmv.context.resolution_ratio_multiplier

                # Calculate our flatten scalar as explained previously
                flatten_scalar = self.mmv.functions.value_on_line_of_two_points(
                    Xa=20,
                    Ya=self.fft_20hz_multiplier,
                    Xb=20000,
                    Yb=self.fft_20khz_multiplier,
                    get_x=frequencies[0][index])

                # The actual size of the music bar
                size = (magnitude) * (flatten_scalar) * (
                    self.bar_magnitude_multiplier)

                # Hard crop maximum limit
                if size > self.maximum_bar_size:
                    size = self.maximum_bar_size

                # We send an r, theta just in case we want to do something with it later on
                data[channel]["coordinates"].append([
                    (self.minimum_bar_size + size) * effects["size"],
                    theta,
                ])

                # If a bar has a high magnitude, set the stroke width to be higher
                if self.bigger_bars_on_magnitude:

                    # Calculate how much to add
                    bigger_bars_on_magnitude = (
                        magnitude /
                        self.bigger_bars_on_magnitude_add_magnitude_divided_by)

                    # Scale according to the resolution
                    bigger_bars_on_magnitude /= self.mmv.context.resolution_ratio_multiplier
                else:
                    bigger_bars_on_magnitude = 0

                # # Coloring

                # Radial colors
                if self.color_preset == "colorful":

                    # Rotate the colors a bit on each step
                    color_shift_on_angle = theta

                    if self.color_rotates:
                        color_shift_on_angle += (self.mmv.core.this_step /
                                                 self.color_rotate_speed)

                    # Define the color of the bars
                    colors = [
                        abs(math.sin((color_shift_on_angle / 2))),
                        abs(
                            math.sin((color_shift_on_angle +
                                      ((1 / 3) * 2 * math.pi)) / 2)),
                        abs(
                            math.sin((color_shift_on_angle +
                                      ((2 / 3) * 2 * math.pi)) / 2)),
                    ] + [0.89]  # not full opacity

                    # Make a skia color with the colors list as argument
                    color = skia.Color4f(*colors)

                    # Make the skia Paint and
                    this_bar_paint = skia.Paint(
                        AntiAlias=True,
                        Color=color,
                        Style=skia.Paint.kStroke_Style,
                        StrokeWidth=8 *
                        self.mmv.context.resolution_ratio_multiplier +
                        bigger_bars_on_magnitude,
                    )

                if self.color_preset == "white":

                    # Define the color of the bars
                    colors = [1.0, 1.0, 1.0, 0.89]

                    # Make a skia color with the colors list as argument
                    color = skia.Color4f(*colors)

                    # Make the skia Paint and
                    this_bar_paint = skia.Paint(
                        AntiAlias=True,
                        Color=color,
                        Style=skia.Paint.kStroke_Style,
                        StrokeWidth=8 *
                        self.mmv.context.resolution_ratio_multiplier +
                        bigger_bars_on_magnitude,
                    )

                # Store it on a list do draw in the end
                data[channel]["paints"].append(this_bar_paint)

        # Our list of coordinates and paints, invert the right channel for drawing the path in the right direction
        # Not reversing it will yield "symmetric" bars along the diagonal
        coordinates = data["l"]["coordinates"] + [
            x for x in reversed(data["r"]["coordinates"])
        ]
        paints = data["l"]["paints"] + [
            x for x in reversed(data["r"]["paints"])
        ]

        # # # # # # # # # # # # These two code blocks are deprecated, not sure if they'll be used in a config # # # # # # # # # # # #

        # Filled background
        if False:  # self.config["draw_background"]

            path = skia.Path()
            white_background = skia.Paint(
                AntiAlias=True,
                Color=skia.ColorWHITE,
                Style=skia.Paint.kFill_Style,
                StrokeWidth=3,
                ImageFilter=skia.ImageFilters.DropShadow(
                    3, 3, 5, 5, skia.ColorBLACK),
                MaskFilter=skia.MaskFilter.MakeBlur(skia.kNormal_BlurStyle,
                                                    1.0))

            more = 1.05

            self.polar.from_r_theta(coordinates[0][0] * more,
                                    coordinates[0][1])
            polar_offset = self.polar.get_rectangular_coordinates()

            path.moveTo(
                (self.center_x + polar_offset[0]),
                (self.center_y + polar_offset[1]),
            )

            for coord_index, coord in enumerate(coordinates):

                # TODO: implement this function in DataUtils for not repeating myself
                get_nearby = 4

                size_coordinates = len(coordinates)
                real_state = coordinates * 3

                nearby_coordinates = real_state[size_coordinates +
                                                (coord_index -
                                                 get_nearby):size_coordinates +
                                                (coord_index + get_nearby)]

                # [0, 1, 2, 3, 4] --> weights=
                #  3  4  5, 4, 3

                n = len(nearby_coordinates)

                weights = [n - abs((n / 2) - x) for x in range(n)]

                s = 0
                for index, item in enumerate(nearby_coordinates):
                    s += item[0] * weights[index]

                avg_coord = s / sum(weights)

                self.polar.from_r_theta(avg_coord * more, coord[1])

                polar_offset = self.polar.get_rectangular_coordinates()

                path.lineTo(
                    (self.center_x + polar_offset[0]),
                    (self.center_y + polar_offset[1]),
                )

            self.mmv.skia.canvas.drawPath(path, white_background)

        # Countour, stroke
        if False:  # self.config["draw_black_border"]

            more = 2

            path = skia.Path()

            black_stroke = skia.Paint(AntiAlias=True,
                                      Color=skia.ColorWHITE,
                                      Style=skia.Paint.kStroke_Style,
                                      StrokeWidth=6,
                                      ImageFilter=skia.ImageFilters.DropShadow(
                                          3, 3, 5, 5, skia.ColorWHITE),
                                      MaskFilter=skia.MaskFilter.MakeBlur(
                                          skia.kNormal_BlurStyle, 1.0))

            for coord_index, coord in enumerate(coordinates):

                get_nearby = 10

                size_coordinates = len(coordinates)
                real_state = coordinates * 3

                nearby_coordinates = real_state[size_coordinates +
                                                (coord_index -
                                                 get_nearby):size_coordinates +
                                                (coord_index + get_nearby)]

                n = len(nearby_coordinates)

                weights = [n - abs((n / 2) - x) for x in range(n)]

                s = 0
                for index, item in enumerate(nearby_coordinates):
                    s += item[0] * weights[index]

                avg_coord = s / sum(weights)

                self.polar.from_r_theta(
                    self.minimum_bar_size +
                    ((avg_coord - self.minimum_bar_size) * more), coord[1])
                polar_offset = self.polar.get_rectangular_coordinates()

                coords = [(self.center_x + polar_offset[0]),
                          (self.center_y + polar_offset[1])]

                if coord_index == 0:
                    path.moveTo(*coords)
                path.lineTo(*coords)

            self.mmv.skia.canvas.drawPath(path, black_stroke)

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

        # Draw the main bars according to their index and coordinate
        for index, coord in enumerate(coordinates):

            # Empty path for drawing the bars
            path = skia.Path()

            # Move to wanted center
            if self.bar_starts_from == "center":
                path.moveTo(self.center_x, self.center_y)

            # Move to the last bar end position
            elif self.bar_starts_from == "last":
                self.polar.from_r_theta(coordinates[index - 1][0],
                                        coordinates[index - 1][1])
                polar_offset = self.polar.get_rectangular_coordinates()
                path.moveTo(self.center_x + polar_offset[0],
                            self.center_y + polar_offset[1])

            else:
                raise RuntimeError(
                    debug_prefix,
                    f"Invalid bar_starts_from: [{self.bar_starts_from}]")

            # Get a polar coordinate point, convert to rectangular
            self.polar.from_r_theta(coord[0], coord[1])
            polar_offset = self.polar.get_rectangular_coordinates()

            # Move to the final desired point
            path.lineTo(
                self.center_x + polar_offset[0],
                self.center_y + polar_offset[1],
            )

            # Draw the path according to its index's paint
            self.mmv.skia.canvas.drawPath(path, paints[index])
Пример #12
0
    def build(self, config, effects):

        # Get "needed" variables
        total_steps = self.mmv.context.total_steps
        completion = self.functions.proportion(
            total_steps, 1,
            self.mmv.core.this_step)  # Completion from 0-1 means
        resolution_ratio_multiplier = self.mmv.context.resolution_ratio_multiplier

        # We push the bar downwards according to the avg amplitude for a nice shaky-blur effect
        offset_by_amplitude = self.mmv.core.modulators[
            "average_value"] * self.config[
                "shake_scalar"] * resolution_ratio_multiplier

        if self.config["position"] == "top":
            offset_by_amplitude *= (-1)

        # White full opacity color
        colors = [1, 1, 1, 1]

        # Make a skia color with the colors list as argument
        color = skia.Color4f(*colors)

        # Make the skia Paint and
        paint = skia.Paint(
            AntiAlias=True,
            Color=color,
            Style=skia.Paint.kStroke_Style,
            StrokeWidth=10 * resolution_ratio_multiplier,  # + (magnitude/4),
            # ImageFilter=skia.ImageFilters.DropShadow(3, 3, 5, 5, skia.ColorWHITE),
        )

        # The direction we're walking centered at origin, $\vec{AB} = A - B$
        path_vector = np.array(
            [self.end_x - self.start_x, self.end_y - self.start_y])

        # Proportion we already walked
        path_vector = path_vector * completion

        # Draw the main line starting at the start coordinates, push down by offset_by_amplitude
        path = skia.Path()
        path.moveTo(self.start_x, self.start_y + offset_by_amplitude)
        path.lineTo(self.start_x + path_vector[0],
                    self.start_y + path_vector[1] + offset_by_amplitude)
        self.mmv.skia.canvas.drawPath(path, paint)

        # Borders around image
        if True:
            # Distance away from s
            distance = 9 * resolution_ratio_multiplier

            colors = [1, 1, 1, 0.7]

            # Make a skia color with the colors list as argument
            color = skia.Color4f(*colors)

            # Make the skia Paint and
            paint = skia.Paint(
                AntiAlias=True,
                Color=color,
                Style=skia.Paint.kStroke_Style,
                StrokeWidth=2,
            )

            # Rectangle border
            border = skia.Rect(self.start_x - distance,
                               self.start_y - distance + offset_by_amplitude,
                               self.end_x + distance,
                               self.end_y + distance + offset_by_amplitude)

            # Draw the border
            self.mmv.skia.canvas.drawRect(border, paint)
Пример #13
0
    def polygons(self):

        print(f"Saving generated polygons background N=[", end="", flush=True)

        BASE_GRADIENT_LINEAR = True
        MUTATION = True
        LOW_POLY = True
        RANDOM = True
        GREYSCALE = False

        for i in range(self.n_images):

            if BASE_GRADIENT_LINEAR:

                if RANDOM:
                    color1 = skia.Color4f(random.uniform(0, 1),
                                          random.uniform(0, 1),
                                          random.uniform(0, 1), 1)
                    color2 = skia.Color4f(random.uniform(0, 1),
                                          random.uniform(0, 1),
                                          random.uniform(0, 1), 1)

                if GREYSCALE:
                    gradient1, gradient2 = random.uniform(0,
                                                          1), random.uniform(
                                                              0, 1)
                    color1 = skia.Color4f(gradient1, gradient1, gradient1, 1)
                    color2 = skia.Color4f(gradient2, gradient2, gradient2, 1)

                paint = skia.Paint(Shader=skia.GradientShader.MakeLinear(
                    points=[(random.randint(-self.width / 2, 0),
                             random.randint(-self.height / 2, 0)),
                            (self.width + random.randint(0, self.width / 2),
                             self.height +
                             random.randint(0, self.height / 2))],
                    colors=[color1, color2]))
                self.canvas.drawPaint(paint)
                colors = self.skia.canvas_array()

            if LOW_POLY:
                break_x = 20
                break_y = 15

                rectangle_widths = np.linspace(-self.width / 4,
                                               1.25 * self.width,
                                               num=break_x)
                rectangle_heights = np.linspace(-self.height / 4,
                                                1.25 * self.height,
                                                num=break_y)

                rectangle_width = self.width / break_x
                rectangle_height = self.height / break_y

                xx, yy = np.meshgrid(rectangle_widths, rectangle_heights)

                pairs = list(np.dstack([xx, yy]).reshape(-1, 2))

                if MUTATION:
                    for index in range(len(pairs)):
                        pairs[index][0] = pairs[index][0] + random.uniform(
                            0, rectangle_width)
                        pairs[index][1] = pairs[index][1] + random.uniform(
                            0, rectangle_height)

                # print(pairs)

                rectangle_points = []

                for index, point in enumerate(list(pairs)):
                    samerow = not ((index + 1) % break_x == 0)
                    # print(pairs[index], index, samerow)
                    try:
                        # If they are on the same height
                        if samerow:
                            rectangle_points.append([
                                list(pairs[index]),
                                list(pairs[index + break_x]),
                                list(pairs[index + break_x + 1]),
                                list(pairs[index + 1]),
                            ])
                    except IndexError:
                        pass

                for rectangle in rectangle_points:
                    average_x = int(sum([val[0] for val in rectangle]) / 4)
                    average_y = int(sum([val[1] for val in rectangle]) / 4)

                    # print(rectangle, average_x, average_y)

                    rectangle_color = colors[min(max(average_y, 0),
                                                 self.height - 1)][min(
                                                     max(average_x, 0),
                                                     self.width - 1)]
                    rectangle_color_fill = [x / 255 for x in rectangle_color]
                    rectangle_color_border = [
                        x / 255 - 0.05 for x in rectangle_color
                    ]

                    # print(rectangle_color)

                    # Make a skia color with the colors list as argument
                    color = skia.Color4f(*rectangle_color_fill)

                    # Make the skia Paint and
                    paint = skia.Paint(
                        AntiAlias=True,
                        Color=color,
                        Style=skia.Paint.kFill_Style,
                        StrokeWidth=2,
                    )

                    color = skia.Color4f(*rectangle_color_border)

                    border = skia.Paint(
                        AntiAlias=True,
                        Color=color,
                        Style=skia.Paint.kStroke_Style,
                        StrokeWidth=1,
                        # ImageFilter=skia.ImageFilters.DropShadow(3, 3, 5, 5, color)
                    )

                    path = skia.Path()
                    path.moveTo(*rectangle[0])

                    rectangle.append(rectangle[0])

                    for point in rectangle:
                        path.lineTo(*point)

                    self.canvas.drawPath(path, paint)
                    self.canvas.drawPath(path, border)

            # Save
            img = self.skia.canvas_array()

            # Pretty print
            if not i == self.n_images - 1:
                print(f"{i}, ", end="", flush=True)
            else:
                print(f"{i}]")

            img = Image.fromarray(img).convert('RGB')
            img.save(self.output_dir + f"/img{i}.jpg", quality=100)
Пример #14
0
    def next(self, depth=LOG_NO_DEPTH) -> None:
        debug_prefix = "[MMVSkiaImage.next]"
        ndepth = depth + LOG_NEXT_DEPTH

        # Next step
        self.current_step += 1

        if self.preludec["next"]["log_current_step"]:
            logging.debug(
                f"{ndepth}{debug_prefix} [{self.identifier}] Next step, current step = [{self.current_step}]"
            )

        # Animation has ended, this current_animation isn't present on path.keys
        if self.current_animation not in list(self.animation.keys()):
            self.is_deletable = True

            # Log we are marked to be deleted
            if self.preludec["next"]["log_became_deletable"]:
                logging.debug(
                    f"{ndepth}{debug_prefix} [{self.identifier}] Object is out of animation, marking to be deleted"
                )

            return

        # The animation we're currently playing
        this_animation = self.animation[self.current_animation]

        animation = this_animation["animation"]
        steps = animation[
            "steps"] * self.mmvskia_main.context.fps_ratio_multiplier  # Scale the interpolations

        # The current step is one above the steps we've been told, next animation
        if self.current_step >= steps + 1:
            self.current_animation += 1
            self.current_step = 0
            return

        # Reset offset, pending
        self.offset = [0, 0]
        self.image.pending = {}

        sg = time.time()

        self.image.reset_to_original_image()
        self._reset_effects_variables()

        position = this_animation["position"]
        path = position["path"]

        if "modules" in this_animation:

            modules = this_animation["modules"]

            self.is_vectorial = "vectorial" in modules

            # The video module must be before everything as it gets the new frame
            if "video" in modules:
                s = time.time()

                this_module = modules["video"]

                # We haven't set a video capture or it has ended
                if self.video is None:
                    self.video = cv2.VideoCapture(this_module["path"])

                # Can we read next frame? if not, go back to frame 0 for a loop
                ok, frame = self.video.read()
                if not ok:  # cry
                    self.video.set(cv2.CAP_PROP_POS_FRAMES, 0)
                    ok, frame = self.video.read()

                # CV2 utilizes BGR matrix, but we need RGB
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)

                self.image.load_from_array(frame)
                self.image.resize_to_resolution(width=this_module["width"],
                                                height=this_module["height"],
                                                override=True)

                if self.preludec["next"]["debug_timings"]:
                    logging.debug(
                        f"{depth}{debug_prefix} [{self.identifier}] Video module .next() took [{time.time() - s:.010f}]"
                    )

            if "rotate" in modules:
                s = time.time()

                this_module = modules["rotate"]
                rotate = this_module["object"]

                amount = rotate.next()
                amount = round(amount, self.ROUND)

                if not self.is_vectorial:
                    self.image.rotate(amount, from_current_frame=True)
                else:
                    self.rotate_value = amount

                if self.preludec["next"]["debug_timings"]:
                    logging.debug(
                        f"{depth}{debug_prefix} [{self.identifier}] Rotate module .next() took [{time.time() - s:.010f}]"
                    )

            if "resize" in modules:
                s = time.time()

                this_module = modules["resize"]
                resize = this_module["object"]

                # Where the vignetting intensity is pointing to according to our
                resize.next()
                self.size = resize.get_value()

                if not self.is_vectorial:

                    # If we're going to rotate, resize the rotated frame which is not the original image
                    offset = self.image.resize_by_ratio(
                        self.size, from_current_frame=True)

                    if this_module["keep_center"]:
                        self.offset[0] += offset[0]
                        self.offset[1] += offset[1]

                if self.preludec["next"]["debug_timings"]:
                    logging.debug(
                        f"{depth}{debug_prefix} [{self.identifier}] Resize module .next() took [{time.time() - s:.010f}]"
                    )

            # DONE
            if "blur" in modules:
                s = time.time()

                this_module = modules["blur"]
                blur = this_module["object"]

                blur.next()

                amount = blur.get_value()

                self.image_filters.append(
                    skia.ImageFilters.Blur(amount, amount))

                if self.preludec["next"]["debug_timings"]:
                    logging.debug(
                        f"{depth}{debug_prefix} [{self.identifier}] Blur module .next() took [{time.time() - s:.010f}]"
                    )

            if "fade" in modules:
                s = time.time()

                this_module = modules["fade"]
                fade = this_module["object"]

                fade.next()

                self.image.transparency(fade.get_value())

                if self.preludec["next"]["debug_timings"]:
                    logging.debug(
                        f"{depth}{debug_prefix} [{self.identifier}] Fade module .next() took [{time.time() - s:.010f}]"
                    )

            # Apply vignetting
            if "vignetting" in modules:
                s = time.time()

                this_module = modules["vignetting"]
                vignetting = this_module["object"]

                # Where the vignetting intensity is pointing to according to our
                vignetting.next()
                vignetting.get_center()
                next_vignetting = vignetting.get_value()

                # This is a somewhat fake vignetting, we just start a black point with full transparency
                # at the center and make a radial gradient that is black with no transparency at the radius
                self.mmvskia_main.skia.canvas.drawPaint({
                    'Shader':
                    skia.GradientShader.MakeRadial(
                        center=(vignetting.center_x, vignetting.center_y),
                        radius=next_vignetting,
                        colors=[
                            skia.Color4f(0, 0, 0, 0),
                            skia.Color4f(0, 0, 0, 1)
                        ])
                })

                if self.preludec["next"]["debug_timings"]:
                    logging.debug(
                        f"{depth}{debug_prefix} [{self.identifier}] Vignetting module .next() took [{time.time() - s:.010f}]"
                    )

            if "vectorial" in modules:
                s = time.time()

                this_module = modules["vectorial"]
                vectorial = this_module["object"]

                effects = {
                    "size": self.size,
                    "rotate": self.rotate_value,
                    "image_filters": self.image_filters,
                }

                # Visualizer blit itself into the canvas automatically
                vectorial.next(effects)

                if self.preludec["next"]["debug_timings"]:
                    logging.debug(
                        f"{depth}{debug_prefix} [{self.identifier}] Vectorial module .next() took [{time.time() - s:.010f}]"
                    )

            if self.preludec["next"]["debug_timings"]:
                logging.debug(
                    f"{depth}{debug_prefix} [{self.identifier}] Global .next() took [{time.time() - sg:.010f}]"
                )

        # Iterate through every position module
        for modifier in path:

            # # Override modules

            argument = [self.x, self.y] + self.offset

            # Move according to a Point (be stationary)
            if self.mmvskia_main.utils.is_matching_type(
                [modifier], [MMVSkiaModifierPoint]):
                # Attribute (x, y) to Point's x and y
                [self.x, self.y], self.offset = modifier.next(*argument)

            # Move according to a Line (interpolate current steps)
            if self.mmvskia_main.utils.is_matching_type([modifier],
                                                        [MMVSkiaModifierLine]):
                # Interpolate and unpack next coordinate
                [self.x, self.y], self.offset = modifier.next(*argument)

            # # Offset modules

            # Get next shake offset value
            if self.mmvskia_main.utils.is_matching_type(
                [modifier], [MMVSkiaModifierShake]):
                [self.x, self.y], self.offset = modifier.next(*argument)
Пример #15
0
 def skia(self):
     return skia.Color4f(self.r, self.g, self.b, self.a)
Пример #16
0
def test_Color4f_init(args):
    assert isinstance(skia.Color4f(*args), skia.Color4f)
Пример #17
0
def test_Color4f_getitem_setitem():
    color4f = skia.Color4f(0xFFFFFFFF)
    assert isinstance(color4f[0], float)
    color4f[0] = 1.0
    def run(self):

        # Calculate fps?
        if self.pyskt_context.show_debug:
            frame_times = [0] * 120
            frame = 0
            last_time_completed = time.time()

        # Link events to parsers
        glfw.set_window_size_callback(self.window,
                                      self.events.on_window_resize)
        glfw.set_mouse_button_callback(self.window, self.events.mouse_callback)
        glfw.set_scroll_callback(self.window, self.events.mouse_callback)
        glfw.set_key_callback(self.window, self.events.keyboard_callback)

        glfw.set_drop_callback(self.window, self.events.on_file_drop)

        scroll_text_x = self.pyskt_context.width // 2
        scroll_text_y = self.pyskt_context.height // 2
        wants_to_go = [scroll_text_x, scroll_text_y]

        threading.Thread(target=self.events_loop).start()

        # Loop until the user closes the window
        while not glfw.window_should_close(self.window):

            # Wait events if said to
            # if self.pyskt_context.wait_events:

            # Clear canvas
            self.canvas.clear(self.colors.background)

            # Get mouse position
            self.mouse_pos = glfw.get_cursor_pos(self.window)
            self.check_mouse_moved()

            if self.events.left_click:
                wants_to_go[0] -= self.events.scroll * 50
            else:
                wants_to_go[1] -= self.events.scroll * 50

            # We have now to recursively search through the components dictionary

            scroll_text_x = scroll_text_x + (wants_to_go[0] -
                                             scroll_text_x) * 0.3
            scroll_text_y = scroll_text_y + (wants_to_go[1] -
                                             scroll_text_y) * 0.3

            self.draw_utils.anchored_text(
                canvas=self.canvas,
                text="A Really long and centered text",
                x=scroll_text_x,
                y=scroll_text_y,
                anchor_x=0.5,
                anchor_y=0.5,
            )

            # Hover testing
            for _ in range(20):
                random.seed(_)

                xywh_rect = [
                    random.randint(0, 1000),
                    random.randint(0, 1000),
                    random.randint(0, 400),
                    random.randint(0, 400)
                ]

                # Rectangle border
                # rect = self.pyskt_processing.rectangle_x_y_w_h_to_coordinates(*xywh_rect)

                info = self.pyskt_processing.point_against_rectangle(
                    self.mouse_pos, xywh_rect)

                if info["is_inside"]:
                    paint = skia.Paint(
                        AntiAlias=True,
                        Color=skia.Color4f(1, 0, 1, 1),
                        Style=skia.Paint.kFill_Style,
                        StrokeWidth=2,
                    )
                else:
                    c = 1 - (info["distance"] / 1080)
                    paint = skia.Paint(
                        AntiAlias=True,
                        Color=skia.Color4f(c, c, c, 1),
                        Style=skia.Paint.kFill_Style,
                        StrokeWidth=2,
                    )

                # Draw the border
                self.canvas.drawRect(
                    skia.Rect(
                        *self.pyskt_processing.rectangle_x_y_w_h_to_skia_rect(
                            *xywh_rect)), paint)

            # # #

            # Show fps
            if self.pyskt_context.show_debug:
                frame_times[frame % 120] = time.time() - last_time_completed
                absolute_frame_times = [x for x in frame_times if not x == 0]
                fps = 1 / (sum(absolute_frame_times) /
                           len(absolute_frame_times))

                last_time_completed = time.time()
                frame += 1

                self.draw_utils.anchored_text(
                    canvas=self.canvas,
                    text=[f"{fps=:.1f}", f"mouse_pos={self.mouse_pos}"],
                    x=0,
                    y=0,
                    anchor_x=0,
                    anchor_y=0,
                    # kwargs
                    font=skia.Font(skia.Typeface('Arial'), 12),
                )

            # If any event doesn't return to "None" state
            self.events.reset_non_ending_states()

            # Flush buffer
            self.surface.flushAndSubmit()

            # Swap front and back buffers
            glfw.swap_buffers(self.window)

            # Poll for and process events
            glfw.poll_events()

        # End glfw
        glfw.terminate()
Пример #19
0
    def draw_note(self, velocity, start, end, channel, note, name):

        # Get the note colors for this channel, we receive a dict with "sharp" and "plain" keys
        note_colors = self.color_channels.get(channel,
                                              self.color_channels["default"])

        # Is a sharp key
        if "#" in name:
            width = self.semitone_width * 0.9
            color = skia.Color4f(*note_colors["sharp"], 1)

        # Plain key
        else:
            width = self.tone_width * 0.6
            color = skia.Color4f(*note_colors["plain"], 1)

        # Make the skia Paint
        note_paint = skia.Paint(
            AntiAlias=True,
            Color=color,
            Style=skia.Paint.kFill_Style,
            # Shader=skia.GradientShader.MakeLinear(
            #     points=[(0.0, 0.0), (self.mmvskia_main.context.width, self.mmvskia_main.context.height)],
            #     colors=[skia.Color4f(0, 0, 1, 1), skia.Color4f(0, 1, 0, 1)]),
            StrokeWidth=2,
        )

        # Border of the note
        note_border_paint = skia.Paint(
            AntiAlias=True,
            Color=skia.Color4f(*note_colors["border"], 1),
            Style=skia.Paint.kStroke_Style,
            # ImageFilter=skia.ImageFilters.DropShadow(3, 3, 5, 5, skia.ColorBLUE),
            # MaskFilter=skia.MaskFilter.MakeBlur(skia.kNormal_BlurStyle, 2.0),
            StrokeWidth=max(
                self.mmvskia_main.context.resolution_ratio_multiplier * 2, 1),
        )

        # Horizontal we have it based on the tones and semitones we calculated previously
        # this is the CENTER of the note
        x = self.keys_centers[note]

        # The Y is a proportion of, if full seconds of midi content, it's the viewport height itself,
        # otherwise it's a proportion to the processing time according to a start value in seconds
        y = self.functions.proportion(
            self.config["seconds_of_midi_content"],
            self.viewport_height,  #*2,
            self.mmvskia_main.context.current_time - start)

        # The height is just the proportion of, seconds of midi content is the maximum height
        # how much our key length (end - start) is according to that?
        height = self.functions.proportion(
            self.config["seconds_of_midi_content"], self.viewport_height,
            end - start)

        # Build the coordinates of the note
        # Note: We add and subtract half a width because X is the center
        # while we need to add from the viewport out heights on the Y
        coords = [
            x - (width / 2),
            y + (self.viewport_height) - height,
            x + (width / 2),
            y + (self.viewport_height),
        ]

        # Rectangle border of the note
        rect = skia.Rect(*coords)

        # Draw the note and border
        self.mmvskia_main.skia.canvas.drawRect(rect, note_paint)
        self.mmvskia_main.skia.canvas.drawRect(rect, note_border_paint)
Пример #20
0
 def __init__(self, pyskt_main, *args, **kwargs):
     self.pyskt_main = pyskt_main
     self.background = skia.Color4f(*[26 / 255] * 3 + [1])
Пример #21
0
def test_ColorFilter_filterColor4f(colorfilter):
    srcCS = skia.ColorSpace.MakeSRGB()
    dstCS = skia.ColorSpace.MakeSRGB()
    assert isinstance(
        colorfilter.filterColor4f(skia.Color4f(0xFF00FFFF), srcCS, dstCS),
        skia.Color4f)
    def draw(self, notes_playing):

        away_ratio = 0.33

        # If the note is black we leave a not filled spot on the bottom, this is the ratio of it
        away = (self.height * (away_ratio)) if self.is_black else 0

        # Based on the away, center, width, height etc, get the coords of this piano key
        coords = [
            self.center_x - (self.width / 2),
            self.resolution_height - self.height,
            self.center_x + (self.width / 2),
            self.resolution_height - away,
        ]

        white_or_back = "white" if self.is_white else "black"

        # Rectangle border
        key_rect = skia.RRect(skia.Rect(*coords),
            self.config["rounding"]["piano_keys"][white_or_back]["x"],
            self.config["rounding"]["piano_keys"][white_or_back]["y"]
        )

        # Is the note active
        self.active = self.note in notes_playing.keys()

        if self.config["piano_key_follows_note_color"]:
            if self.active:
                channel = notes_playing[self.note]
                color1 = self.colors[f"channel_{channel}"]["plain_1"]
                color2 = self.colors[f"channel_{channel}"]["plain_2"]
            else:
                color1 = self.color_idle_1
                color2 = self.color_idle_2

        else:
            # Get the color based on if the note is active or not
            color1 = self.color_active_1 if self.active else self.color_idle_1
            color2 = self.color_active_2 if self.active else self.color_idle_2
        
        # Make the skia Paint and
        key_paint = skia.Paint(
            AntiAlias = True,
            # Color = color1,
            Style = skia.Paint.kFill_Style,
            Shader = skia.GradientShader.MakeLinear(
                points = [(0.0, self.mmvskia_main.context.height), (self.mmvskia_main.context.width, self.mmvskia_main.context.height)],
                colors = [color1, color2]),
            StrokeWidth = 0,
        )

        # The border of the key
        key_border = skia.Paint(
            AntiAlias = True,
            Color = skia.Color4f(0, 0, 0, 1),
            Style = skia.Paint.kStroke_Style,
            StrokeWidth = 1,
        )

        # Make flat top
        if self.is_black:
            bleed = self.config["rounding"]["piano_keys"][white_or_back]["x"] / 8
            flat_top_key_rect = skia.Rect(coords[0], coords[1] - bleed, coords[2], (coords[3] - (coords[3] - coords[1]) / 4) - bleed)
            self.mmvskia_main.skia.canvas.drawRect(flat_top_key_rect, key_paint)

        # Draw the key (we'll draw on top of it later)
        self.mmvskia_main.skia.canvas.drawRRect(key_rect, key_paint)

        # Draw the 3d effect
        if (not self.active):

            # One fourth of the away ratio
            three_d_effect_away = away + (self.height * (away_ratio / 4))

            # The coordinates considering black key's away
            three_d_effect_coords = [
                self.center_x - (self.width / 2),
                self.resolution_height - three_d_effect_away,
                self.center_x + (self.width / 2),
                self.resolution_height - away,
            ]

            # The paint
            three_d_effect_paint = skia.Paint(
                AntiAlias = True,
                Color = self.color_3d_effect,
                Style = skia.Paint.kFill_Style,
                StrokeWidth = 0,
            )

            rect = skia.RRect(skia.Rect(*three_d_effect_coords), 8, 8)

            # Draw the rectangle
            self.mmvskia_main.skia.canvas.drawRRect(rect, three_d_effect_paint)

        # Draw the border
        if not self.is_black:
            self.mmvskia_main.skia.canvas.drawRRect(key_rect, key_border)
Пример #23
0
    def build(self, effects):

        # Clear the background
        self.mmvskia_main.skia.canvas.clear(
            skia.Color4f(*self.global_colors["background"], 1))

        # Draw the orientation markers
        if self.config["do_draw_markers"]:
            self.draw_markers()

        # # Get "needed" variables

        time_first_note = self.vectorial.midi.time_first_note

        # If user passed seconds offset then don't use automatic one from midi file
        if "seconds_offset" in self.config.keys():
            offset = self.config["seconds_offset"]
        else:
            offset = 0
            # offset = time_first_note # .. if audio is trimmed?

        # Offsetted current time at the piano key top most part
        current_time = self.mmvskia_main.context.current_time - offset

        # What keys we'll bother rendering? Check against the first note time offset
        # That's because current_time should be the real midi key not the offsetted one
        accept_minimum_time = current_time - self.config[
            "seconds_of_midi_content"]
        accept_maximum_time = current_time + self.config[
            "seconds_of_midi_content"]

        # What notes are playing? So we draw a darker piano key
        self.notes_playing = []

        # For each channel of notes
        for channel in self.vectorial.midi.timestamps.keys():

            # For each key message on the timestamps of channels (notes)
            for key in self.vectorial.midi.timestamps[channel]:

                # A "key" is a note if it's an integer
                if isinstance(key, int):

                    # This note play / stop times, for all notes [[start, end], [start, end] ...]
                    note = key
                    times = self.vectorial.midi.timestamps[channel][note][
                        "time"]
                    delete = []

                    # For each note index and the respective interval
                    for index, interval in enumerate(times):

                        # Out of bounds completely, we don't care about this note anymore.
                        # We mark for deletion otherwise it'll mess up the indexing
                        if interval[1] < accept_minimum_time:
                            delete.append(index)
                            continue

                        # Notes past this one are too far from being played and out of bounds
                        if interval[0] > accept_maximum_time:
                            break

                        # Is the current time inside the note? If yes, the note is playing
                        current_time_in_interval = (interval[0] < current_time
                                                    < interval[1])

                        # Append to playing notes
                        if current_time_in_interval:
                            self.notes_playing.append(note)

                        # Either way, draw the key
                        self.draw_note(
                            # TODO: No support for velocity yet :(
                            velocity=128,

                            # Vertical position (start / end)
                            start=interval[0],
                            end=interval[1],

                            # Channel for the color and note for the horizontal position
                            channel=channel,
                            note=note,

                            # Name so we can decide to draw a sharp or plain key
                            name=self.vectorial.midi.note_to_name(note),
                        )

                    # This is an interval we do not care about anymore
                    # as the end of the note is past the minimum time we accept a note being rendered
                    for index in reversed(delete):
                        del self.vectorial.midi.timestamps[channel][note][
                            "time"][index]

        self.draw_piano()
    def build(self, fitted_ffts: dict, frequencies: list, this_step: int,
              config: dict, effects):

        resolution_ratio_multiplier = self.vectorial.context.resolution_ratio_multiplier

        if self.config["mode"] == "symetric":

            data = {}

            for channel in (["l", "r"]):

                data[channel] = {
                    "coordinates": [],
                    "paints": [],
                }

                this_channel_fft = fitted_ffts[channel]
                npts = len(this_channel_fft)

                for index, magnitude in enumerate(this_channel_fft):

                    if channel == "l":
                        theta = (math.pi / 2) - ((index / npts) * math.pi)

                    elif channel == "r":
                        theta = (math.pi / 2) + ((index / npts) * math.pi)

                    magnitude = (magnitude / 720) * self.context.height

                    minimum_multiplier = 0.4
                    maximum_multiplier = 17

                    size = (magnitude) * self.functions.ax_plus_b_two_points(
                        x=frequencies[0][index],
                        end_x=20000,
                        zero_value=minimum_multiplier,
                        max_value=maximum_multiplier,
                    )

                    # size = (magnitude*6) * ( (( (maximum_multiplier - minimum_multiplier)*index) / len(this_channel_fft)) + minimum_multiplier )

                    # We send an r, theta just in case we want to do something with it later on
                    data[channel]["coordinates"].append([
                        # ( self.config["minimum_bar_size"] + magnitude*(2e6) ) * effects["size"],
                        (self.config["minimum_bar_size"] + size) *
                        effects["size"],
                        theta,
                    ])

                    # Rotate the colors a bit on each step
                    theta += this_step / 100

                    # Define the color of the bars
                    colors = [
                        abs(math.sin((theta / 2))),
                        abs(math.sin((theta + ((1 / 3) * 2 * math.pi)) / 2)),
                        abs(math.sin((theta + ((2 / 3) * 2 * math.pi)) / 2)),
                    ] + [0.7]  # Add full opacity

                    # Make a skia color with the colors list as argument
                    color = skia.Color4f(*colors)

                    # Make the skia Paint and
                    paint = skia.Paint(
                        AntiAlias=True,
                        Color=color,
                        Style=skia.Paint.kStroke_Style,
                        StrokeWidth=8 *
                        resolution_ratio_multiplier  # + (magnitude/4),
                    )

                    # Store it on a list do draw in the end
                    data[channel]["paints"].append(paint)

            # Our list of coordinates and paints, invert the right channel for drawing the path in the right direction
            # Not reversing it will yield "symetric" bars along the diagonal
            coordinates = data["l"]["coordinates"] + [
                x for x in reversed(data["r"]["coordinates"])
            ]
            paints = data["l"]["paints"] + [
                x for x in reversed(data["r"]["paints"])
            ]

            # Filled background
            if False:  # self.config["draw_background"]

                path = skia.Path()
                white_background = skia.Paint(
                    AntiAlias=True,
                    Color=skia.ColorWHITE,
                    Style=skia.Paint.kFill_Style,
                    StrokeWidth=3,
                    ImageFilter=skia.ImageFilters.DropShadow(
                        3, 3, 5, 5, skia.ColorBLACK),
                    MaskFilter=skia.MaskFilter.MakeBlur(
                        skia.kNormal_BlurStyle, 1.0))

                more = 1.05

                self.polar.from_r_theta(coordinates[0][0] * more,
                                        coordinates[0][1])
                polar_offset = self.polar.get_rectangular_coordinates()

                path.moveTo(
                    (self.center_x + polar_offset[0]),
                    (self.center_y + polar_offset[1]),
                )

                for coord_index, coord in enumerate(coordinates):

                    # TODO: implement this function in DataUtils for not repeating myself
                    get_nearby = 4

                    size_coordinates = len(coordinates)
                    real_state = coordinates * 3

                    nearby_coordinates = real_state[size_coordinates + (
                        coord_index - get_nearby):size_coordinates +
                                                    (coord_index + get_nearby)]

                    # [0, 1, 2, 3, 4] --> weights=
                    #  3  4  5, 4, 3

                    n = len(nearby_coordinates)

                    weights = [n - abs((n / 2) - x) for x in range(n)]

                    s = 0
                    for index, item in enumerate(nearby_coordinates):
                        s += item[0] * weights[index]

                    avg_coord = s / sum(weights)

                    self.polar.from_r_theta(avg_coord * more, coord[1])

                    polar_offset = self.polar.get_rectangular_coordinates()

                    path.lineTo(
                        (self.center_x + polar_offset[0]),
                        (self.center_y + polar_offset[1]),
                    )

                self.skia.canvas.drawPath(path, white_background)

            # Countour, stroke
            if False:  # self.config["draw_black_border"]

                more = 2

                path = skia.Path()

                black_stroke = skia.Paint(
                    AntiAlias=True,
                    Color=skia.ColorWHITE,
                    Style=skia.Paint.kStroke_Style,
                    StrokeWidth=6,
                    ImageFilter=skia.ImageFilters.DropShadow(
                        3, 3, 5, 5, skia.ColorWHITE),
                    MaskFilter=skia.MaskFilter.MakeBlur(
                        skia.kNormal_BlurStyle, 1.0))

                for coord_index, coord in enumerate(coordinates):

                    get_nearby = 10

                    size_coordinates = len(coordinates)
                    real_state = coordinates * 3

                    nearby_coordinates = real_state[size_coordinates + (
                        coord_index - get_nearby):size_coordinates +
                                                    (coord_index + get_nearby)]

                    n = len(nearby_coordinates)

                    weights = [n - abs((n / 2) - x) for x in range(n)]

                    s = 0
                    for index, item in enumerate(nearby_coordinates):
                        s += item[0] * weights[index]

                    avg_coord = s / sum(weights)

                    self.polar.from_r_theta(
                        self.config["minimum_bar_size"] +
                        ((avg_coord - self.config["minimum_bar_size"]) * more),
                        coord[1])
                    polar_offset = self.polar.get_rectangular_coordinates()

                    coords = [(self.center_x + polar_offset[0]),
                              (self.center_y + polar_offset[1])]

                    if coord_index == 0:
                        path.moveTo(*coords)
                    path.lineTo(*coords)

                self.skia.canvas.drawPath(path, black_stroke)

            # Draw the main bars
            for index, coord in enumerate(coordinates):

                more = 1

                path = skia.Path()
                path.moveTo(self.center_x, self.center_y)

                self.polar.from_r_theta(coord[0], coord[1])
                polar_offset = self.polar.get_rectangular_coordinates()

                path.lineTo(
                    (self.center_x + polar_offset[0]) * more,
                    (self.center_y + polar_offset[1]) * more,
                )

                self.skia.canvas.drawPath(path, paints[index])
    def draw_note(self, velocity, start, end, channel, note, name):

        color_channels = {
            0: {
                "plain": ImageColor.getcolor("#ffcc00", "RGB"),
                "sharp": ImageColor.getcolor("#ff9d00", "RGB"),
            },
            1: {
                "plain": ImageColor.getcolor("#00ff0d", "RGB"),
                "sharp": ImageColor.getcolor("#00a608", "RGB"),
            },
            2: {
                "plain": ImageColor.getcolor("#6600ff", "RGB"),
                "sharp": ImageColor.getcolor("#39008f", "RGB"),
            },
            3: {
                "plain": ImageColor.getcolor("#ff0000", "RGB"),
                "sharp": ImageColor.getcolor("#990000", "RGB"),
            },
            4: {
                "plain": ImageColor.getcolor("#00fffb", "RGB"),
                "sharp": ImageColor.getcolor("#00b5b2", "RGB"),
            },
            5: {
                "plain": ImageColor.getcolor("#ff006f", "RGB"),
                "sharp": ImageColor.getcolor("#a10046", "RGB"),
            },
            6: {
                "plain": ImageColor.getcolor("#aaff00", "RGB"),
                "sharp": ImageColor.getcolor("#75b000", "RGB"),
            },
            7: {
                "plain": ImageColor.getcolor("#e1ff00", "RGB"),
                "sharp": ImageColor.getcolor("#a9bf00", "RGB"),
            },
            8: {
                "plain": ImageColor.getcolor("#ff3300", "RGB"),
                "sharp": ImageColor.getcolor("#a82200", "RGB"),
            },
            9: {
                "plain": ImageColor.getcolor("#00ff91", "RGB"),
                "sharp": ImageColor.getcolor("#00b567", "RGB"),
            },
            10: {
                "plain": ImageColor.getcolor("#ff00aa", "RGB"),
                "sharp": ImageColor.getcolor("#c40083", "RGB"),
            },
            11: {
                "plain": ImageColor.getcolor("#c800ff", "RGB"),
                "sharp": ImageColor.getcolor("#8e00b5", "RGB"),
            },
            12: {
                "plain": ImageColor.getcolor("#00ff4c", "RGB"),
                "sharp": ImageColor.getcolor("#00c93c", "RGB"),
            },
            13: {
                "plain": ImageColor.getcolor("#ff8a8a", "RGB"),
                "sharp": ImageColor.getcolor("#bf6767", "RGB"),
            },
            14: {
                "plain": ImageColor.getcolor("#ffde7d", "RGB"),
                "sharp": ImageColor.getcolor("#c4aa5e", "RGB"),
            },
            15: {
                "plain": ImageColor.getcolor("#85ebff", "RGB"),
                "sharp": ImageColor.getcolor("#5ca7b5", "RGB"),
            },
            16: {
                "plain": ImageColor.getcolor("#ff7aa4", "RGB"),
                "sharp": ImageColor.getcolor("#bd5978", "RGB"),
            },
            "default": {
                "plain": ImageColor.getcolor("#dddddd", "RGB"),
                "sharp": ImageColor.getcolor("#ffffff", "RGB"),
            },
        }

        note_colors = color_channels.get(channel, color_channels["default"])

        if "#" in name:
            width = self.semitone_width * 0.9
            c = note_colors["sharp"]
            color = skia.Color4f(c[0] / 255, c[1] / 255, c[2] / 255, 1)

        else:
            width = self.tone_width * 0.6
            c = note_colors["plain"]
            color = skia.Color4f(c[0] / 255, c[1] / 255, c[2] / 255, 1)

        # Make the skia Paint and
        paint = skia.Paint(
            AntiAlias=True,
            Color=color,
            Style=skia.Paint.kFill_Style,
            # Shader=skia.GradientShader.MakeLinear(
            #     points=[(0.0, 0.0), (self.vectorial.context.width, self.vectorial.context.height)],
            #     colors=[skia.Color4f(0, 0, 1, 1), skia.Color4f(0, 1, 0, 1)]),
            StrokeWidth=2,
        )

        # c = ImageColor.getcolor("#d1ce1d", "RGB")
        c = (0, 0, 0)
        border = skia.Paint(
            AntiAlias=True,
            Color=skia.Color4f(c[0] / 255, c[1] / 255, c[2] / 255, 1),
            Style=skia.Paint.kStroke_Style,
            # ImageFilter=skia.ImageFilters.DropShadow(3, 3, 5, 5, skia.ColorBLUE),
            # MaskFilter=skia.MaskFilter.MakeBlur(skia.kNormal_BlurStyle, 2.0),
            StrokeWidth=max(
                self.vectorial.context.resolution_ratio_multiplier * 2, 1),
        )

        x = self.keys_centers[note]

        y = self.functions.proportion(
            self.seconds_of_midi_content,
            self.viewport_height,  #*2,
            self.vectorial.context.current_time - start)

        height = self.functions.proportion(self.seconds_of_midi_content,
                                           self.viewport_height, end - start)

        coords = [
            x - (width / 2),
            y + (self.viewport_height) - height,
            x + (width / 2),
            y + (self.viewport_height),
        ]

        # Rectangle border
        rect = skia.Rect(*coords)

        # Draw the border
        self.skia.canvas.drawRect(rect, paint)
        self.skia.canvas.drawRect(rect, border)
    def build(self, fftinfo, this_step, config, effects):

        c = self.background_color
        self.skia.canvas.clear(skia.Color4f(c, c, c, 1))
        self.seconds_of_midi_content = config["seconds-of-midi-content"]
        SECS_OFFSET = config["seconds-offset"]

        self.draw_markers()

        # Get "needed" variables
        current_time = self.vectorial.context.current_time + SECS_OFFSET
        resolution_ratio_multiplier = self.vectorial.context.resolution_ratio_multiplier

        # contents = self.datautils.dictionary_items_in_between(
        #     self.midi.timestamps,
        #     current_time - 2,
        #     current_time + self.seconds_of_midi_content * 2
        # )

        accept_minimum_time = current_time - self.seconds_of_midi_content
        accept_maximum_time = current_time + self.seconds_of_midi_content

        self.notes_playing = []

        for channel in self.midi.timestamps.keys():
            for key in self.midi.timestamps[channel]:
                if isinstance(key, int):

                    note = key
                    times = self.midi.timestamps[channel][note]["time"]
                    delete = []

                    for index, interval in enumerate(times):

                        # Out of bounds
                        if interval[1] < accept_minimum_time:
                            delete.append(index)
                            continue

                        if interval[0] > accept_maximum_time:
                            break

                        current_time_in_interval = (interval[0] < current_time
                                                    < interval[1])
                        accepted_render = (accept_minimum_time < current_time <
                                           accept_maximum_time)

                        if current_time_in_interval:
                            self.notes_playing.append(note)

                        if current_time_in_interval or accepted_render:
                            self.draw_note(
                                velocity=128,
                                start=interval[0] - SECS_OFFSET,
                                end=interval[1] - SECS_OFFSET,
                                channel=channel,
                                note=note,
                                name=self.midi.note_to_name(note),
                            )

                    for index in reversed(delete):
                        del self.midi.timestamps[channel][note]["time"][index]

        self.draw_piano()
Пример #27
0
 def skia(self):
     if skia:
         return skia.Color4f(self.r, self.g, self.b, self.a)
     else:
         raise Exception("Skia installation not found")
    def next(self, fftinfo: dict, this_step: int, skia_canvas=None) -> None:

        self.current_step += 1

        # Animation has ended, this current_animation isn't present on path.keys
        if self.current_animation not in list(self.animation.keys()):
            self.is_deletable = True
            return

        # The animation we're currently playing
        this_animation = self.animation[self.current_animation]

        animation = this_animation["animation"]
        steps = animation["steps"]

        # The current step is one above the steps we've been told, next animation
        if self.current_step == steps + 1:
            self.current_animation += 1
            self.current_step = 0
            return

        # Reset offset, pending
        self.offset = [0, 0]
        self.image.pending = {}

        self.image.reset_to_original_image()
        self._reset_effects_variables()

        position = this_animation["position"]
        path = position["path"]

        if "modules" in this_animation:

            modules = this_animation["modules"]

            self.is_vectorial = "vectorial" in modules

            # The video module must be before everything as it gets the new frame
            if "video" in modules:

                this_module = modules["video"]

                # We haven't set a video capture or it has ended
                if self.video is None:
                    self.video = cv2.VideoCapture(this_module["path"])

                # Can we read next frame? if not, go back to frame 0 for a loop
                ok, frame = self.video.read()
                if not ok:  # cry
                    self.video.set(cv2.CAP_PROP_POS_FRAMES, 0)
                    ok, frame = self.video.read()

                # CV2 utilizes BGR matrix, but we need RGB
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)

                shake = 0

                for modifier in position:
                    if self.mmv.utils.is_matching_type([modifier],
                                                       [MMVModifierShake]):
                        shake = modifier.distance

                width = self.mmv.context.width + (4 * shake)
                height = self.mmv.context.height + (4 * shake)

                self.image.load_from_array(frame)
                self.image.resize_to_resolution(width, height, override=True)

            if "rotate" in modules:
                this_module = modules["rotate"]
                rotate = this_module["object"]

                amount = rotate.next()
                amount = round(amount, self.ROUND)

                if not self.is_vectorial:
                    self.image.rotate(amount, from_current_frame=True)
                else:
                    self.rotate_value = amount

            if "resize" in modules:
                this_module = modules["resize"]
                resize = this_module["object"]

                # Where the vignetting intensity is pointing to according to our
                resize.next(fftinfo["average_value"])
                self.size = resize.get_value()

                if not self.is_vectorial:

                    # If we're going to rotate, resize the rotated frame which is not the original image
                    offset = self.image.resize_by_ratio(
                        self.size, from_current_frame=True)

                    if this_module["keep_center"]:
                        self.offset[0] += offset[0]
                        self.offset[1] += offset[1]

            # DONE
            if "blur" in modules:
                this_module = modules["blur"]
                blur = this_module["object"]

                blur.next(fftinfo["average_value"])

                amount = blur.get_value()

                self.image_filters.append(
                    skia.ImageFilters.Blur(amount, amount))

            if "fade" in modules:
                this_module = modules["fade"]
                fade = this_module["object"]

                fade.next(fftinfo["average_value"])

                self.image.transparency(fade.get_value())

            # Apply vignetting
            if "vignetting" in modules:
                this_module = modules["vignetting"]
                vignetting = this_module["object"]

                # Where the vignetting intensity is pointing to according to our
                vignetting.next(fftinfo["average_value"])
                vignetting.get_center()
                next_vignetting = vignetting.get_value()

                # This is a somewhat fake vignetting, we just start a black point with full transparency
                # at the center and make a radial gradient that is black with no transparency at the radius
                skia_canvas.canvas.drawPaint({
                    'Shader':
                    skia.GradientShader.MakeRadial(
                        center=(vignetting.center_x, vignetting.center_y),
                        radius=next_vignetting,
                        colors=[
                            skia.Color4f(0, 0, 0, 0),
                            skia.Color4f(0, 0, 0, 1)
                        ])
                })

            if "vectorial" in modules:
                this_module = modules["vectorial"]
                vectorial = this_module["object"]

                effects = {
                    "size": self.size,
                    "rotate": self.rotate_value,
                    "image_filters": self.image_filters,
                }

                # Visualizer blit itself into the canvas automatically
                vectorial.next(fftinfo, this_step, effects)

        # Iterate through every position module
        for modifier in path:

            # # Override modules

            argument = [self.x, self.y] + self.offset

            # Move according to a Point (be stationary)
            if self.mmv.utils.is_matching_type([modifier], [MMVModifierPoint]):
                # Attribute (x, y) to Point's x and y
                [self.x, self.y], self.offset = modifier.next(*argument)

            # Move according to a Line (interpolate current steps)
            if self.mmv.utils.is_matching_type([modifier], [MMVModifierLine]):
                # Interpolate and unpack next coordinate
                [self.x, self.y], self.offset = modifier.next(*argument)

            # # Offset modules

            # Get next shake offset value
            if self.mmv.utils.is_matching_type([modifier], [MMVModifierShake]):
                [self.x, self.y], self.offset = modifier.next(*argument)