Esempio n. 1
0
def f520(m: OsuMap):

    bpms = SvSequence([(b, 1000000) for b in buzzes[::2]]).writeAsBpm(OsuBpm)
    bpms.extend(SvSequence([(b, REF_BPM * 0.75)
                            for b0, b1 in zip(buzzes[::2], buzzes[1::2])
                            for b in np.arange(b0 + 1, b1, 2)]).writeAsBpm(OsuBpm, metronome=999))

    m.bpms.extend(bpms)
Esempio n. 2
0
    def test(self):
        # Rescale Test
        seq = SvSequence([0, 1, 2])
        seq.rescale(0, 1000, inplace=True)

        self.assertAlmostEqual(seq[0].offset, 0)
        self.assertAlmostEqual(seq[1].offset, 500)
        self.assertAlmostEqual(seq[2].offset, 1000)
Esempio n. 3
0
    def copyTo(seq: SvSequence, offsets: List[float]) -> SvPkg:
        """ Copies self to specified offsets

        :param seq: The SvSequence To Copy
        :param offsets: Offsets in float
        :return: Returns a List of SvSequences, flatten-able by SvSequence.combine()
        """
        return SvPkg([
            seq.deepcopy().addOffset(offset - seq.firstOffset())
            for offset in offsets
        ])
Esempio n. 4
0
    def testSv(self):
        # Complex BPM Points
        osu = OsuMap.readFile(OSU_CARAVAN)

        seq = SvSequence()
        seq.readSvFromMap(osu)

        for sv, sv0 in zip(seq.writeAsSv(OsuSv, volume=0)[:50], osu.svs):
            assert isinstance(sv, OsuSv)
            self.assertAlmostEqual(sv0.multiplier, sv.multiplier)
            self.assertEqual(0, sv.volume)
Esempio n. 5
0
    def testTrueSv(self):
        # Complex BPM Points
        osu = OsuMap.readFile(OSU_CARAVAN)

        seq = SvSequence()
        seq.readTrueSvFromMap(osu, 140)

        # Just need to check the first 50, others should be ok.
        for sv in seq.writeAsSv(OsuSv, volume=0)[:50]:
            assert isinstance(sv, OsuSv)
            self.assertAlmostEqual(1, sv.multiplier, delta=0.01)
            self.assertEqual(0, sv.volume)
Esempio n. 6
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)
Esempio n. 7
0
 def testMixed(self):
     # Quick Init Mixed
     seq = SvSequence([
         100, (200, 2.0, True), (400, 3.0),
         SvObj(offset=800, multiplier=5.0, fixed=True)
     ])
     self.assertEqual(len(seq), 4)
Esempio n. 8
0
    def fit(seq: SvSequence, offsets: List[float]) -> SvPkg:
        """ Repeats the Sequence such that it repeats from offset to offset, scaled correctly. Always sorts offsets

        Example::

            Input Sequence
            OFFSETS 100 150 200
            SEQ     1.5 0.5 1.0

            Input Offsets
            OFFSETS 100 200 300     500     700

            Output
            SEQ 1        SEQ 2        SEQ 3        SEQ 4
            ---------------------------------------------------
            OFFSET SV  | OFFSET SV  | OFFSET SV  | OFFSET SV  |
            100    1.5 | 200    1.5 | 300    1.5 | 500    1.5 |
            150    0.5 | 250    0.5 | 400    0.5 | 600    0.5 |
            200    1.0 | 300    1.0 | 500    1.0 | 700    1.0 |

        :param seq: The sequence to fit
        :param offsets: The offsets to fit to.
        """
        offsets_ = sorted(offsets)
        seqs = []
        for firstOffset, lastOffset in zip(offsets_[:-1], offsets_[1:]):
            seqs.append(
                seq.moveStartTo(firstOffset,
                                inplace=False).rescale(firstOffset,
                                                       lastOffset))

        return SvPkg(seqs)
Esempio n. 9
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)
Esempio n. 10
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)
Esempio n. 11
0
    def combine(self,
                combineMethod: CombineMethod = CombineMethod.IGNORE,
                combineMethodWindow: float = 1.0,
                combinePriorityLast: bool = True) -> SvSequence:
        """ Combines multiple sequences together

        Can specify to keep earliest SV if overlapping.

        :param combineMethod: The method to use to combine. See SvSequence.CombineMethod
        :param combineMethodWindow: The millisecond window to check if offsets are of the same offset. Can be 0 for\
            exact comparison
        :param combinePriorityLast: If True, this means that the later SVs will overlap the earlier ones. Recommended\
            for current API
        :return: Returns a stable sorted combine
        """

        if combineMethod == self.CombineMethod.IGNORE:
            return SvSequence([x for y in self
                               for x in y]).sorted(inplace=False)
        elif combineMethod == self.CombineMethod.DROP_BY_POINT:
            newSeq = SvSequence([x for y in self
                                 for x in y]).sorted(inplace=False)
            if combinePriorityLast: newSeq.reverse()
            # We loop through the list, if the next offset is similar to current, we delete the next one
            # else we move to the next element
            i = 0
            while i < len(newSeq) - 1:
                if newSeq[i + 1].offset - combineMethodWindow <= newSeq[i].offset <= \
                        newSeq[i + 1].offset + combineMethodWindow:
                    del newSeq[i + 1]
                else:
                    i += 1

            return newSeq.sorted() if combinePriorityLast else newSeq
        else:  # Combine Method == DROP_BY_BOUND
            newSeq = self[0].sorted()
            if combinePriorityLast: newSeq.reverse()
            seqEnd = newSeq.lastOffset()
            for seq in self[1:]:
                addSeq = seq.after(offset=seqEnd,
                                   includeEnd=False,
                                   inplace=False)
                newSeq += addSeq
                seqEnd = addSeq.lastOffset()
            return newSeq.sorted() if combinePriorityLast else newSeq
Esempio n. 12
0
    def test(self):
        # Test Cross
        seq = 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.3)
        ])
        seq.crossWith(seq2, inplace=True)

        self.assertAlmostEqual(seq[0].multiplier, 0.5)
        self.assertAlmostEqual(seq[1].multiplier, 20.0)
        self.assertAlmostEqual(seq[2].multiplier, 30.0)
        self.assertAlmostEqual(seq[3].multiplier, 10.0)
Esempio n. 13
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))
Esempio n. 14
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)
Esempio n. 15
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)
Esempio n. 16
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
Esempio n. 17
0
    def repeat(seq: SvSequence, times: int, gap: float = 0) -> SvPkg:
        """ Repeats the Sequence by copying the the sequence to the end.

        Always includes current sequence.

        Consider::

            <---> repeated 3 times.

            <--->
                <--->
                    <--->

        :param seq: The SvSequence To Repeat
        :param times: Number of times to repeat
        :param gap: The gap between each repeat
        """
        first, last = seq.firstLastOffset()
        duration = last - first
        return SvPkg.copyTo(
            seq=seq,
            offsets=[first + (duration + gap) * i for i in range(times)])
Esempio n. 18
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
Esempio n. 19
0
 def testGeneric(self):
     seq = SvSequence([0, (500, 1.5, True), 1000])
     seq.normalizeTo(inplace=True)
     self.assertAlmostEqual(seq[0].multiplier, 0.5)
Esempio n. 20
0
 def testBadMax(self):
     # Norm Test
     seq = SvSequence([0, (500, 0.5, True), 1000])
     self.assertRaises(AssertionError, seq.normalizeTo, inplace=True, maxAllowable=1.2)
Esempio n. 21
0
 def testBadMin(self):
     seq = SvSequence([0, (500, 2.1, True), 1000])
     self.assertRaises(AssertionError, seq.normalizeTo, inplace=True, minAllowable=0)
Esempio n. 22
0
 def testIgnoreFixed(self):
     seq = SvSequence([0, (500, 1.5, True), 1000])
     seq.normalizeTo(inplace=True, ignoreFixed=True)
     self.assertAlmostEqual(seq[0].multiplier, 0.8)
     self.assertAlmostEqual(seq[1].multiplier, 1.2)
Esempio n. 23
0
 def testComplex(self):
     seq = SvSequence([0, (500, 1.5, True), (700, 0.75, True), (800, 1.5, False), 1000])
     seq.normalizeTo(inplace=True)
     self.assertAlmostEqual(seq[0].multiplier, 0.78125)
     self.assertAlmostEqual(seq[3].multiplier, 1.171875)
Esempio n. 24
0
 def test(self):
     # Quick Init Mixed
     seq = SvSequence([100, 200, 60, 400])
     seq.rescale(300, 800, inplace=True)
Esempio n. 25
0
 def crossMutualWith(this: SvSequence, other: SvSequence) -> SvPkg:
     """ Crosses with each other, returning 2 sequences that can be combined with SvPkg. """
     return SvPkg([
         this.crossWith(other=other, inplace=False),
         other.crossWith(other=this, inplace=False)
     ])