예제 #1
0
    def test(self):

        t = SvPkg([SvSequence([SvObj(0, 1.0), SvObj(100, 2.0)]),
                   SvSequence([SvObj(100, 3.0), SvObj(200, 4.0)]),
                   SvSequence([SvObj(150, 5.0), SvObj(300, 6.0)])])\
            .combine(combineMethod=SvPkg.CombineMethod.DROP_BY_POINT, combineMethodWindow=1)

        self.assertEqual(len(t), 5)

        t.appendInit([(0, 1.0), SvObj(100, 2.0), (1000, 2.0, True), 1000])

        self.assertEqual(len(t), 9)
예제 #2
0
def f559(m: OsuMap):
    pkg = SvPkg([])

    for off0, off1 in zip(offsets[:-1], offsets[1:]):
        diff = off1 - off0
        pkg.append(
            SvSequence([(off0, diff * REF_BPM * 1.1), (off0 + 1, MIN_BPM),
                        (off1, REF_BPM)]))

    m.bpms.extend(
        pkg.combine(SvPkg.CombineMethod.DROP_BY_POINT,
                    combineMethodWindow=0,
                    combinePriorityLast=False).writeAsBpm(OsuBpm))
예제 #3
0
 def testCopy(self):
     # Test Copy
     seq = SvSequence([SvObj(0, 1.0), SvObj(100, 2.0)])
     seqCopy = SvPkg.copyTo(seq=seq, offsets=[
         100, 200, 300
     ]).combine(combineMethod=SvPkg.CombineMethod.DROP_BY_POINT)
     self.assertEqual(len(seqCopy), 4)
예제 #4
0
    def testFit(self):
        # Test Fitting
        seq = SvSequence([SvObj(0, 0.5), SvObj(50, 1.5), SvObj(100, 1.0)])
        seq = SvPkg.fit(seq, [0, 100, 200, 400, 600]).combine(
            SvPkg.CombineMethod.DROP_BY_POINT)

        self.assertEqual(len(seq), 9)
예제 #5
0
    def test(self):

        t = SvPkg([SvSequence([SvObj(0, 1.0), SvObj(100, 2.0)]),
                   SvSequence([SvObj(100, 3.0), SvObj(200, 4.0)]),
                   SvSequence([SvObj(150, 5.0), SvObj(300, 6.0)])])\
            .combine(combineMethod=SvPkg.CombineMethod.DROP_BY_POINT, combineMethodWindow=1)

        self.assertEqual(len(t), 5)

        t = SvPkg([SvSequence([SvObj(0, 1.0), SvObj(100, 2.0)]),
                   SvSequence([SvObj(100, 3.0), SvObj(200, 4.0)]),
                   SvSequence([SvObj(150, 5.0), SvObj(300, 6.0)])])\
            .combine(combineMethod=SvPkg.CombineMethod.DROP_BY_BOUND, combineMethodWindow=1)

        self.assertEqual(len(t), 4)

        t = SvPkg([SvSequence([SvObj(0, 1.0), SvObj(100, 2.0)]),
                   SvSequence([SvObj(100, 3.0), SvObj(200, 4.0)]),
                   SvSequence([SvObj(150, 5.0), SvObj(300, 6.0)])])\
            .combine(combineMethod=SvPkg.CombineMethod.IGNORE, combineMethodWindow=1)

        self.assertEqual(len(t), 6)
예제 #6
0
def svFuncSequencer(funcs: List[Union[float, Callable[[float], float], None]],
                    offsets: Union[List[float], float, None] = None,
                    repeats: int = 1,
                    repeatGap: float = 0,
                    startX: float = 0,
                    endX: float = 1):
    """ Sets up a sequence using functions.

    :param funcs: Funcs to generate values. \
        If List, values will be used directly. \
        If Callable, values will be called with the X. \
        If None, this will leave a gap in the sequence.
    :param offsets: Offsets to use on functions. \
        If List, offsets will be used to map the funcs. \
        If Float, all funcs are assumed to be separated by {float} ms. Starting from 0. \
        If None, all funcs are assumed to be separated by 1 ms. Starting from 0.
    :param repeats: The amount of repeats. This affects the increment of the X argument passed to the Callables. \
        If 0, only endX will be used.
    :param repeatGap: The gap between the repeats.
    :param startX: The starting X.
    :param endX: The ending X.
    """

    length = len(funcs)

    if offsets is None:
        offsets = list(range(0, length))
        # We use [:length] because sometimes arange will create too many for some reason (?)
    elif isinstance(offsets, (float, int)):
        offsets = list(arange(0, length * offsets, offsets))[:length]

    assert length == len(offsets)

    seq = SvSequence()

    for i, (offset, func) in enumerate(zip(offsets, funcs)):
        if isinstance(func, Callable): seq.appendInit([(offset, 0)])
        elif isinstance(func, (float, int)): seq.appendInit([(offset, func)])
        elif func is None: pass

    pkg = SvPkg.repeat(seq=seq, times=repeats, gap=repeatGap)

    nones = 0
    for funcI, func in enumerate(funcs):
        if func is None: nones += 1
        if isinstance(func, Callable):
            pkg.applyNth(func, funcI - nones, startX, endX)

    return pkg
예제 #7
0
    def test2(self):
        # Test Mutual Cross
        seq1 = SvSequence(
            [SvObj(0, 0.5),
             SvObj(100, 2.0),
             SvObj(200, 3.0),
             SvObj(400, 2.0)])
        seq2 = SvSequence([
            SvObj(50, 0.1),
            SvObj(100, 10.0),
            SvObj(250, 5.0),
            SvObj(500, 0.2)
        ])
        seq = SvPkg.crossMutualWith(seq1, seq2).combine(
            SvPkg.CombineMethod.DROP_BY_POINT)

        self.assertAlmostEqual(seq[0].multiplier, 0.5)
        self.assertAlmostEqual(seq[1].multiplier, 0.05)
        self.assertAlmostEqual(seq[2].multiplier, 20.0)
        self.assertAlmostEqual(seq[3].multiplier, 30.0)
        self.assertAlmostEqual(seq[4].multiplier, 15.0)
        self.assertAlmostEqual(seq[5].multiplier, 10.0)
        self.assertAlmostEqual(seq[6].multiplier, 0.4)
예제 #8
0
def svOsuMeasureLineA(firstOffset: float,
                      lastOffset: float,
                      funcs: List[Callable[[float], float]],
                      referenceBpm: float,
                      endBpm: float or None,
                      paddingSize: int = 10,
                      teleportBpm: float = 1e07,
                      stopBpm: float = 1e-05,
                      fillBpm: float or None = 1e-05,
                      startX: float = 0,
                      endX: float = 1) -> SvPkg:
    """ Generates Measure Line movement for osu! maps. Version 1.

    This is a beta function for svOsuMeasureLine, it may or may not work as expected.

    This handles multi functions a little bit better by stacking them in a single frame instead of flickering through
    them.

    Could be used for other VSRGs but if they support negative Scroll then it could be much easier.

    Sequence::

        S_{_}...F{_F}..._S_T,S_{_}...F{_F}..._S_T,S_{_}...F{_F}..._S_T,...

    :param firstOffset: The first Offset to start the function (x = startX)
    :param lastOffset: The last Offset to end the function (x = endX)
    :param funcs: The functions to use. startX <= x <= endX will be called, expecting a BPM as an output. \
        The more functions you have, the "laggier" it will be.
    :param referenceBpm: The bpm that is used to zero. Found by looking at BPM:XXX-XXX(Reference Bpm) in song select.
    :param paddingSize: The size of the padding, the larger the value, the lower the FPS
    :param teleportBpm: The bpm value for teleporting Bpms.
    :param stopBpm: The bpm value for stop Bpms. Cannot be 0.
    :param fillBpm: The bpm to use to fill such that the sequence ends on lastOffset. None for no fill.
    :param endBpm: The bpm to end the sequence with.
    :param startX: The starting X to use
    :param endX: The ending X to use
    """

    # Optimized value to make sure that 1.0 in input means at the top of the screen.
    # Not accurate for all scrolls and different hit positions.
    SCALING_FACTOR = 9311250 / referenceBpm

    # Append a y = 0 to get diff on first func
    funcs = [lambda x: 0, *funcs]
    funcDiff = []

    for funcI in range(
            len(funcs) -
            1):  # -1 due to the appended y = 0, -1 due to custom last func

        def f(x, i=funcI):
            sort = sorted([g(x) * SCALING_FACTOR for g in funcs])
            for s in range(len(sort)):
                sort[s] = max(0.0, sort[s])  # We eliminate all negative inputs

            out = [g2 - g1 for g1, g2 in zip(sort[:-1], sort[1:])][i]
            if out == 0: return FALLBACK_ZERO_BPM
            else: return out

        funcDiff.append(deepcopy(f))

    funcSeq = []
    funcSeq.extend([stopBpm, *[None for _ in range(paddingSize)], funcDiff[0]])
    for func in funcDiff[1:]:
        funcSeq.extend([None, func])
    funcSeq.extend([None, stopBpm, None, teleportBpm])

    msecPerFrame = len(funcSeq)

    duration = lastOffset - firstOffset
    frameCount = int(duration / msecPerFrame)

    pkg = svFuncSequencer(funcs=funcSeq,
                          offsets=1,
                          repeats=frameCount,
                          repeatGap=1,
                          startX=startX,
                          endX=endX)

    pkg = SvPkg(map(lambda x: x.addOffset(firstOffset), pkg))

    # Fill missing ending to fit to lastOffset
    if fillBpm is not None:
        seqLastOffset = firstOffset + frameCount * msecPerFrame
        pkg.append(
            SvSequence([
                (offset, fillBpm)
                for offset in range(int(seqLastOffset), int(lastOffset))
            ]))

    if endBpm is not None:
        pkg.append(SvSequence([(lastOffset, endBpm)]))

    return pkg