Source code for rubato.utils.computation.noise

"""
A modified implementation of the OpenSimplex2 algorithm.
"""
from . import Math
from .. import InitError


# THIS IS A STATIC CLASS
[docs]class Noise: """ A utility for generating simple smooth noise, based on OpenSimplex2. """ seed: int = 0 """The seed for the random noise. Setting to a fixed value will result in the same noise every time.""" _PRIME_X = 0x5205402B9270C86F _PRIME_Y = 0x598CD327003817B5 _PRIME_Z = 0x5BCC226E9FA0BACB _PRIME_W = 0x56CC5227E58F554B _HASH_MULTIPLIER = 0x53A3F72DEEC546F5 _ROOT2OVER2 = 0.7071067811865476 _SKEW_2D = 0.366025403784439 _UNSKEW_2D = -0.21132486540518713 _N_GRADS_2D_EXPONENT = 7 _N_GRADS_2D = 1 << _N_GRADS_2D_EXPONENT _NORMALIZER_2D = 0.01001634121365712 _RSQUARED_2D = 0.5 _GRADIENTS_2D = [] def __init__(self) -> None: raise InitError(self)
[docs] @classmethod def noise(cls, x: float) -> float: """ Creates noise from 1 dimensional input. This is identical to :func:`noise2(x, 0) <rubato.utils.noise.Noise.noise2>`. Args: x (float): the x coordinate of noise. Returns: float: the random noise value. """ return cls.noise2(x, 0)
[docs] @classmethod def noise2(cls, x: float, y: float) -> float: """ Creates noise from 2 dimensional input. Args: x (float): the x coordinate of noise. y (float): the y coordinate of noise. Returns: float: the random noise value. """ s = cls._SKEW_2D * (x + y) xs = x + s ys = y + s return cls._noise2_base(cls.seed, xs, ys)
@classmethod def _noise2_base(cls, seed: int, xs: float, ys: float) -> float: xsb = Math.floor(xs) ysb = Math.floor(ys) xi = xs - xsb yi = ys - ysb xsbp = xsb * cls._PRIME_X ysbp = ysb * cls._PRIME_Y t = (xi + yi) * cls._UNSKEW_2D dx0 = xi + t dy0 = yi + t value = 0 a0 = cls._RSQUARED_2D - dx0 * dx0 - dy0 * dy0 if a0 > 0: value = (a0 * a0) * (a0 * a0) * cls._grad2(seed, xsbp, ysbp, dx0, dy0) a1 = (2 * (1 + 2 * cls._UNSKEW_2D) * (1 / cls._UNSKEW_2D + 2)) * t + ((-2 * (1 + 2 * cls._UNSKEW_2D) * (1 + 2 * cls._UNSKEW_2D)) + a0) if a1 > 0: dx1 = dx0 - (1 + 2 * cls._UNSKEW_2D) dy1 = dy0 - (1 + 2 * cls._UNSKEW_2D) value += (a1 * a1) * (a1 * a1) * cls._grad2(seed, xsbp + cls._PRIME_X, ysbp + cls._PRIME_Y, dx1, dy1) if dy0 > dx0: dx2 = dx0 - cls._UNSKEW_2D dy2 = dy0 - (cls._UNSKEW_2D + 1) a2 = cls._RSQUARED_2D - dx2 * dx2 - dy2 * dy2 if a2 > 0: value += (a2 * a2) * (a2 * a2) * cls._grad2(seed, xsbp, ysbp + cls._PRIME_Y, dx2, dy2) else: dx2 = dx0 - (cls._UNSKEW_2D + 1) dy2 = dy0 - cls._UNSKEW_2D a2 = cls._RSQUARED_2D - dx2 * dx2 - dy2 * dy2 if a2 > 0: value += (a2 * a2) * (a2 * a2) * cls._grad2(seed, xsbp + cls._PRIME_X, ysbp, dx2, dy2) return value @classmethod def _grad2(cls, seed: int, xsvp: int, ysvp: int, dx: float, dy: float) -> float: hash_val = seed ^ xsvp ^ ysvp hash_val *= cls._HASH_MULTIPLIER hash_val ^= hash_val >> (64 - cls._N_GRADS_2D_EXPONENT + 1) gi = int(hash_val) & ((cls._N_GRADS_2D - 1) << 1) return cls._GRADIENTS_2D[gi | 0] * dx + cls._GRADIENTS_2D[gi | 1] * dy # below is the generator code for the gradients _gradient2 = [ 0.38268343236509, 0.923879532511287, 0.923879532511287, 0.38268343236509, 0.923879532511287, -0.38268343236509, 0.38268343236509, -0.923879532511287, -0.38268343236509, -0.923879532511287, -0.923879532511287, -0.38268343236509, -0.923879532511287, 0.38268343236509, -0.38268343236509, 0.923879532511287, 0.130526192220052, 0.99144486137381, 0.608761429008721, 0.793353340291235, 0.793353340291235, 0.608761429008721, 0.99144486137381, 0.130526192220051, 0.99144486137381, -0.130526192220051, 0.793353340291235, -0.60876142900872, 0.608761429008721, -0.793353340291235, 0.130526192220052, -0.99144486137381, -0.130526192220052, -0.99144486137381, -0.608761429008721, -0.793353340291235, -0.793353340291235, -0.608761429008721, -0.99144486137381, -0.130526192220052, -0.99144486137381, 0.130526192220051, -0.793353340291235, 0.608761429008721, -0.608761429008721, 0.793353340291235, -0.130526192220052, 0.99144486137381, ] for _gradient_i in range(len(_gradient2)): _gradient2[_gradient_i] = _gradient2[_gradient_i] / _NORMALIZER_2D _gradient_j = 0 for _gradient_i in range(_N_GRADS_2D * 2): if _gradient_j == len(_gradient2): _gradient_j = 0 _GRADIENTS_2D.append(_gradient2[_gradient_j]) _gradient_j += 1