Skip to content

Commit

Permalink
refactor: move PitchSimulator to main package
Browse files Browse the repository at this point in the history
  • Loading branch information
SoulMelody committed Aug 6, 2024
1 parent 3f253cc commit 8fa7545
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

from libresvip.core.time_sync import TimeSynchronizer
from libresvip.model.base import Note
from libresvip.model.pitch_slide import PitchSlide
from libresvip.utils.search import find_last_index

from .pitch_slide import PitchSlide


@dataclasses.dataclass
class PitchSimulator:
Expand Down Expand Up @@ -74,16 +73,13 @@ def pitch_at_ticks(self, ticks: int) -> float:
def pitch_at_secs(self, secs: float) -> float:
index = find_last_index(self.pitch_tags, lambda tag: tag[0] <= secs)
if index == -1:
return self.pitch_tags[0][1] * 100
value = self.pitch_tags[0][1]
elif index == len(self.pitch_tags) - 1:
return self.pitch_tags[-1][1] * 100
value = self.pitch_tags[-1][1]
elif self.pitch_tags[index][1] == self.pitch_tags[index + 1][1]:
return self.pitch_tags[index][1] * 100
value = self.pitch_tags[index][1]
else:
ratio = self.slide.apply(
(secs - self.pitch_tags[index][0])
/ (self.pitch_tags[index + 1][0] - self.pitch_tags[index][0])
value = self.slide.inter_func( # type: ignore[assignment]
secs, self.pitch_tags[index], self.pitch_tags[index + 1]
)
return (
self.pitch_tags[index][1] * (1 - ratio) + self.pitch_tags[index + 1][1] * ratio
) * 100
return value * 100
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
from functools import partial
from typing import TYPE_CHECKING

from . import interpolation
from libresvip.utils.music_math import (
cosine_easing_in_out_interpolation,
cubic_interpolation,
sigmoid_interpolation,
)

if TYPE_CHECKING:
from collections.abc import Callable
Expand All @@ -14,19 +18,16 @@
class PitchSlide:
max_inter_time_in_secs: float
max_inter_time_percent: float
inter_func: Callable[[float], float]

def apply(self, value: float) -> float:
return self.inter_func(value)
inter_func: Callable[[float, tuple[float, float], tuple[float, float]], float]

@classmethod
def cosine_slide(cls) -> PitchSlide:
return cls(0.05, 0.1, interpolation.cosine_interpolation)
return cls(0.05, 0.1, cosine_easing_in_out_interpolation)

@classmethod
def cubic_slide(cls) -> PitchSlide:
return cls(0.05, 0.1, interpolation.cubic_interpolation)
return cls(0.05, 0.1, cubic_interpolation)

@classmethod
def sigmoid_slide(cls) -> PitchSlide:
return cls(0.075, 0.48, partial(interpolation.sigmoid_interpolation, k=5.5))
return cls(0.075, 0.48, partial(sigmoid_interpolation, k=5.5))
17 changes: 0 additions & 17 deletions libresvip/plugins/svp/interpolation.py

This file was deleted.

19 changes: 9 additions & 10 deletions libresvip/plugins/svp/param_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,21 @@ def value_at_ticks(self, ticks: int) -> float:
@dataclasses.dataclass
class CurveGenerator(ParamExpression):
base_value: int = dataclasses.field(init=False)
interpolation: Callable[[float], float] = dataclasses.field(init=False)
interpolation: Callable[[float, tuple[float, float], tuple[float, float]], float] = (
dataclasses.field(init=False)
)
point_list: list[Point] = dataclasses.field(init=False)
_point_list: dataclasses.InitVar[Iterable[Point]]
_interpolation: dataclasses.InitVar[Callable[[float], float]]
_interpolation: dataclasses.InitVar[
Callable[[float, tuple[float, float], tuple[float, float]], float]
]
_base_value: dataclasses.InitVar[int] = 0
interval: Optional[portion.Interval] = None

def __post_init__(
self,
_point_list: Iterable[Point],
_interpolation: Callable[[float], float],
_interpolation: Callable[[float, tuple[float, float], tuple[float, float]], float],
_base_value: int = 0,
) -> None:
self.point_list = []
Expand Down Expand Up @@ -146,11 +150,7 @@ def value_at_ticks(self, ticks: int) -> float:
return self.point_list[0].y
if index == len(self.point_list) - 1:
return self.point_list[-1].y
r = self.interpolation(
(ticks - self.point_list[index].x)
/ (self.point_list[index + 1].x - self.point_list[index].x)
)
return (1 - r) * self.point_list[index].y + r * self.point_list[index + 1].y
return self.interpolation(ticks, self.point_list[index], self.point_list[index + 1])

def get_converted_curve(self, step: int) -> list[Point]:
result: list[Point] = []
Expand All @@ -174,8 +174,7 @@ def get_converted_curve(self, step: int) -> list[Point]:
)
else:
for p in range(prev_point.x + step, current_point.x, step):
r = self.interpolation((p - prev_point.x) / (current_point.x - prev_point.x))
v = round((1 - r) * prev_point.y + r * current_point.y)
v = round(self.interpolation(p, prev_point, current_point))
result.append(Point(p, v))
prev_point = current_point
result.extend((Point(prev_point.x, prev_point.y), Point.end_point(prev_point.y)))
Expand Down
4 changes: 2 additions & 2 deletions libresvip/plugins/svp/synthv_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
TimeSignature,
Track,
)
from libresvip.model.pitch_simulator import PitchSimulator
from libresvip.model.pitch_slide import PitchSlide
from libresvip.utils.audio import audio_track_info
from libresvip.utils.music_math import (
clamp,
Expand Down Expand Up @@ -44,8 +46,6 @@
synthv_language_presets,
)
from .phoneme_utils import default_phone_marks, number_of_phones, sv_g2p
from .pitch_simulator import PitchSimulator
from .pitch_slide import PitchSlide

if TYPE_CHECKING:
from libresvip.model.point import Point
Expand Down
22 changes: 15 additions & 7 deletions libresvip/plugins/svp/synthv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,16 @@
Track,
)
from libresvip.model.point import Point
from libresvip.utils.music_math import clamp, db_to_float, ratio_to_db
from libresvip.utils.music_math import (
clamp,
cosine_easing_in_out_interpolation,
cubic_interpolation,
db_to_float,
linear_interpolation,
ratio_to_db,
)
from libresvip.utils.search import find_index

from . import interpolation
from .constants import TICK_RATE
from .interval_utils import position_to_ticks
from .model import (
Expand Down Expand Up @@ -69,13 +75,15 @@ def actual_value_at(
return clip(mapping_func(compound_expr.value_at_ticks(ticks) / 1000))

@staticmethod
def parse_interpolation(mode: str) -> Callable[[float], float]:
def parse_interpolation(
mode: str,
) -> Callable[[float, tuple[float, float], tuple[float, float]], float]:
if mode == "cosine":
return interpolation.cosine_interpolation
return cosine_easing_in_out_interpolation
elif mode == "cubic":
return interpolation.cubic_interpolation
return cubic_interpolation
else:
return interpolation.linear_interpolation
return linear_interpolation

def parse_audio_offset(self, offset: int) -> int:
if offset >= 0:
Expand Down Expand Up @@ -105,7 +113,7 @@ def parse_param_curve(
self,
sv_curve: SVParamCurve,
mapping_func: Callable[[float], int],
base_value: float = 0.0,
base_value: Optional[float] = None,
master_curve: Optional[SVParamCurve] = None,
) -> ParamCurve:
if base_value is None:
Expand Down
28 changes: 24 additions & 4 deletions libresvip/utils/music_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,31 +79,51 @@ def clamp(
def linear_interpolation(x: float, start: tuple[float, float], end: tuple[float, float]) -> float:
x0, y0 = start
x1, y1 = end
return y0 + (x - x0) * (y1 - y0) / (x1 - x0)
r = (x - x0) / (x1 - x0)
return y0 + (y1 - y0) * r


def cosine_easing_in_interpolation(
x: float, start: tuple[float, float], end: tuple[float, float]
) -> float:
x0, y0 = start
x1, y1 = end
return y1 + (y0 - y1) * math.cos((x - x0) / (x1 - x0) * math.pi / 2)
r = (x - x0) / (x1 - x0)
return y0 + (y1 - y0) * (1 - math.cos(r * math.pi / 2))


def cosine_easing_out_interpolation(
x: float, start: tuple[float, float], end: tuple[float, float]
) -> float:
x0, y0 = start
x1, y1 = end
return y0 + (y0 - y1) * math.cos((x - x0) / (x1 - x0) * math.pi / 2 + math.pi / 2)
r = (x - x0) / (x1 - x0)
return y0 + (y1 - y0) * math.cos(r * math.pi / 2)


def cosine_easing_in_out_interpolation(
x: float, start: tuple[float, float], end: tuple[float, float]
) -> float:
x0, y0 = start
x1, y1 = end
return (y0 + y1) / 2 + (y0 - y1) * math.cos((x - x0) / (x1 - x0) * math.pi) / 2
r = (x - x0) / (x1 - x0)
return y0 + (y1 - y0) * (1 - math.cos(r * math.pi)) / 2


def cubic_interpolation(x: float, start: tuple[float, float], end: tuple[float, float]) -> float:
x0, y0 = start
x1, y1 = end
r = (x - x0) / (x1 - x0)
return y0 + (y1 - y0) * ((3 - 2 * r) * r**2)


def sigmoid_interpolation(
x: float, start: tuple[float, float], end: tuple[float, float], k: float
) -> float:
x0, y0 = start
x1, y1 = end
r = (x - x0) / (x1 - x0)
return y0 + (y1 - y0) / (1 + math.exp(k * (-2 * r + 1)))


def db_to_float(db: float, using_amplitude: bool = True) -> float:
Expand Down

0 comments on commit 8fa7545

Please sign in to comment.