def test_press_interval_mean(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu')
        replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr')

        map_data = ManiaActionData.get_action_data(beatmap)
        replay_data = ManiaActionData.get_action_data(replay)

        # osu!topus should have played all notes perfectly (1 ms press intervals)
        score_data = ManiaScoreData.get_score_data(map_data, replay_data)
    def test_scoring_completeness(self):
        # Check if the score processor went through and recorded all of the timings
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\Various Artists - I Like This Chart, LOL vol. 2 (Fullereneshift) [LENK64 - Crazy Slav Dancers (HD) (Marathon)].osu')
        replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\abraker - Various Artists - I Like This Chart, LOL vol. 2 [LENK64 - Crazy Slav Dancers (HD) (Marathon)] (2021-07-10) OsuMania.osr')

        map_data = ManiaActionData.get_action_data(beatmap)
        replay_data = ManiaActionData.get_action_data(replay)
        score_data = ManiaScoreData.get_score_data(map_data, replay_data)

        map_score_xor = np.setxor1d(score_data['map_t'].values, ManiaActionData.press_times(map_data))  # Hits that are not present in either
        map_score_xor = np.intersect1d(map_score_xor, ManiaActionData.press_times(map_data))            # Hits that are present in map but not score
        self.assertEqual(len(map_score_xor), 0, f'Timings mising: {map_score_xor}')
Example #3
0
    def test_detect_hold_notes(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\chords_250ms.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        mask = ManiaMapMetrics.detect_hold_notes(action_data)
        self.assertTrue(np.all(mask == 0))

        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # TODO: test functionality more thourouly
        mask = ManiaMapMetrics.detect_hold_notes(action_data)
        self.assertTrue(np.any(mask == 1))  # There are definitely hold notes in that map
    def test_tap_offset_stdev(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu')
        replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr')

        map_data = ManiaActionData.get_action_data(beatmap)
        replay_data = ManiaActionData.get_action_data(replay)

        # osu!topus should have played all notes perfectly (0 std dev)
        score_data = ManiaScoreData.get_score_data(map_data, replay_data)

        # Include only hits
        score_data = score_data[score_data['type'] == ManiaScoreData.TYPE_HITP]
        tap_offset_stdev = ManiaScoreData.tap_offset_stdev(score_data)
        self.assertEqual(tap_offset_stdev, 0)
        def test(replay1_filename, replay2_filename, press_release):
            replay1 = ReplayIO.open_replay(replay1_filename)
            replay2 = ReplayIO.open_replay(replay2_filename)

            map_data = ManiaActionData.get_action_data(beatmap)
            score_data1 = ManiaScoreData.get_score_data(map_data, ManiaActionData.get_action_data(replay1))
            score_data2 = ManiaScoreData.get_score_data(map_data, ManiaActionData.get_action_data(replay2))

            hit_type  = ManiaScoreData.TYPE_HITP  if press_release == 1 else ManiaScoreData.TYPE_HITR
            miss_type = ManiaScoreData.TYPE_MISSP if press_release == 1 else ManiaScoreData.TYPE_MISSR

            for c in range(score_data1.shape[1]):
                score_col1 = score_data1.loc[c]
                score_col2 = score_data2.loc[c]

                num_hits1 = score_col1['type'].values[score_col1['type'].values == hit_type].shape[0]
                num_miss1 = score_col1['type'].values[score_col1['type'].values == miss_type].shape[0]

                num_hits2 = score_col2['type'].values[score_col2['type'].values == hit_type].shape[0]
                num_miss2 = score_col2['type'].values[score_col2['type'].values == miss_type].shape[0]

                hitp_t1 = score_col1['map_t'].values[score_col1['type'].values == hit_type]
                miss_t1 = score_col1['map_t'].values[score_col1['type'].values == miss_type]
                notes_t1 = np.concatenate((hitp_t1, miss_t1), axis=None).astype(int)  # All note timings in score 1
                notes_t1 = np.sort(notes_t1)

                hitp_t2 = score_col2['map_t'].values[score_col2['type'].values == hit_type]
                miss_t2 = score_col2['map_t'].values[score_col2['type'].values == miss_type]
                notes_t2 = np.concatenate((hitp_t2, miss_t2), axis=None).astype(int)  # All note timings in score 2
                notes_t2 = np.sort(notes_t2)

                notes_count1 = np.zeros(max(np.max(notes_t1), np.max(notes_t2)) + 1)
                notes_count2 = np.zeros(max(np.max(notes_t1), np.max(notes_t2)) + 1)

                notes_count1[:np.max(notes_t1)+1] = np.bincount(notes_t1)  # Integer histogram for timings of score 1
                notes_count2[:np.max(notes_t2)+1] = np.bincount(notes_t2)  # Integer histogram for timings of score 2
                notes_mismatch = np.arange(max(np.max(notes_t1), np.max(notes_t2)) + 1)[notes_count1 != notes_count2]

                replay1_name = replay1_filename[replay1_filename.rfind("\\") + 1:]
                replay2_name = replay2_filename[replay2_filename.rfind("\\") + 1:]

                self.assertEqual(num_hits1 + num_miss1, num_hits2 + num_miss2,
                    f'\n\tReplays: {replay1_name}    {replay2_name}\n'
                    f'\tTest for {"Press" if press_release == 1 else "Release"}\n'
                    f'\tOne of two maps have missing or extra scoring points at column {c}\n'
                    f'\tScore 1 hits & misses: {num_hits1} + {num_miss1} = {num_hits1 + num_miss1}    score 2 hits & misses: {num_hits2} + {num_miss2} = {num_hits2 + num_miss2}\n'
                    f'\tNote timings mismatched: {notes_mismatch}   score 1 occurences: {notes_count1[notes_count1 != notes_count2]}    score 2 occurences: {notes_count2[notes_count1 != notes_count2]}\n'
                )
    def test_perfect_score(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu')
        replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr')

        map_data = ManiaActionData.get_action_data(beatmap)
        replay_data = ManiaActionData.get_action_data(replay)

        # osu!topus should have played all notes perfectly (0 offset)
        score_data = ManiaScoreData.get_score_data(map_data, replay_data)

        score_types = score_data['type'].values
        self.assertEqual(len(score_types[score_types == ManiaScoreData.TYPE_MISSP]), 0)
        self.assertEqual(len(score_types[score_types == ManiaScoreData.TYPE_MISSR]), 0)

        # Mania auto releases hold notes 1 ms early
        offsets = (score_data['replay_t'] - score_data['map_t']).values
        self.assertEqual(len(offsets[~((offsets == 0) | (offsets == -1))]), 0)
    def test_tap_offset_mean_max(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu')
        replay = ReplayIO.open_replay('unit_tests\\replays\\mania\\osu!topus! - DJ Genericname - Dear You [S.Star\'s 4K HD+] (2019-05-29) OsuMania.osr')

        timings = replay.get_time_data()
        timings[0] += ManiaScoreData.pos_hit_range - 1

        map_data = ManiaActionData.get_action_data(beatmap)
        replay_data = ManiaActionData.get_action_data(replay)

        # osu!topus should have played all notes perfectly (0 mean + 150 ms offset)
        score_data = ManiaScoreData.get_score_data(map_data, replay_data)

        # Include only hits
        score_data = score_data[score_data['type'] == ManiaScoreData.TYPE_HITP]
        tap_offset_mean = ManiaScoreData.tap_offset_mean(score_data)
        self.assertEqual(tap_offset_mean, ManiaScoreData.pos_hit_range - 1)
Example #8
0
    def test_detect_inverse(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\chords_250ms.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        inverse_mask = ManiaMapMetrics.detect_inverse(action_data)
        self.assertTrue(np.all(inverse_mask == 0))

        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\inverse_test.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        inverse_mask = ManiaMapMetrics.detect_inverse(action_data)
        self.assertFalse(np.all(inverse_mask == 0))

        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\sr_testing\\high_sr_low_diff_norm_hp\\3L - Endless Night x1.25 (Skorer) [Endless Longs Notes !!].osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        inverse_mask = ManiaMapMetrics.detect_inverse(action_data)
        self.assertFalse(np.all(inverse_mask == 0))
    def test_release_times(self):
        # This map has notes every 250ms
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\1k_10x_0.25_chords.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # Notes occur every 500 ms + 1 ms for release
        release_times = ManiaActionData.release_times(action_data[ManiaActionData.IDX_COL == 0, :])
        for timing, i in zip(release_times, range(0, 500*10, 500)):
            self.assertEqual(timing, i + 1, 'Timings do not match')
        def test_keys(keys, lh, rh):
            beatmap = BeatmapIO.open_beatmap(f'unit_tests\\maps\\mania\\test\\{keys}k_10x_0.25_chords.osu')
            action_data = ManiaActionData.get_action_data(beatmap)

            left_hand, right_hand = ManiaActionData.split_by_hand(action_data, left_handed=True)
            self.assertEqual(ManiaActionData.num_keys(left_hand),  lh, 'Left hand has wrong number of keys')
            self.assertEqual(ManiaActionData.num_keys(right_hand), rh, 'Right hand has wrong number of keys')

            lh, rh = rh, lh
            left_hand, right_hand = ManiaActionData.split_by_hand(action_data, left_handed=False)
            self.assertEqual(ManiaActionData.num_keys(left_hand),  lh, 'Left hand has wrong number of keys')
            self.assertEqual(ManiaActionData.num_keys(right_hand), rh, 'Right hand has wrong number of keys')
 def test_keys(keys):
     beatmap = BeatmapIO.open_beatmap(f'unit_tests\\maps\\mania\\test\\{keys}k_10x_0.25_chords.osu')
     action_data = ManiaActionData.get_action_data(beatmap)
     self.assertEqual(ManiaActionData.num_keys(action_data), keys, 'Calculated wrong number of keys')
Example #12
0
    def test_detect_chords(self):
        # Two single notes, one occuring after another
        action_data = np.asarray([
            [ 100, 101, 0 ],
            [ 200, 201, 1 ],
        ])

        mask = ManiaMapMetrics.detect_chords(action_data)
        self.assertTrue(np.all((mask == [0, 0]) == 1))

        # Two single notes, both occuring at same time
        action_data = np.asarray([
            [ 100, 101, 0 ],
            [ 100, 101, 1 ],
        ])

        mask = ManiaMapMetrics.detect_chords(action_data)
        self.assertTrue(np.all((mask == [1, 1]) == 1))

        # Two single notes occuring at same time + a jack after
        action_data = np.asarray([
            [ 100, 101, 0 ],
            [ 100, 101, 1 ],
            [ 200, 201, 1 ],
        ])

        mask = ManiaMapMetrics.detect_chords(action_data)
        self.assertTrue(np.all((mask == [1, 1, 0]) == 1))

        # Two single notes occuring at same time + a jack before
        action_data = np.asarray([
            [ 200, 201, 0 ],
            [ 200, 201, 1 ],
            [ 100, 101, 1 ],
        ])

        mask = ManiaMapMetrics.detect_chords(action_data)
        self.assertTrue(np.all((mask == [1, 1, 0]) == 1))

        # Stair case
        action_data = np.asarray([
            [ 100, 101, 0 ],
            [ 200, 201, 1 ],
            [ 300, 301, 2 ],
        ])

        mask = ManiaMapMetrics.detect_chords(action_data)
        self.assertTrue(np.all((mask == [0, 0, 0]) == 1))

        # 3 note chord
        action_data = np.asarray([
            [ 100, 101, 0 ],
            [ 100, 101, 1 ],
            [ 100, 101, 3 ],
        ])

        mask = ManiaMapMetrics.detect_chords(action_data)
        self.assertTrue(np.all((mask == [1, 1, 1]) == 1))

        # Alternation
        action_data = np.asarray([
            [ 100, 101, 0 ],
            [ 100, 101, 2 ],
            [ 200, 201, 1 ],
            [ 200, 201, 3 ],
            [ 300, 301, 0 ],
            [ 300, 301, 2 ],
        ])

        mask = ManiaMapMetrics.detect_chords(action_data)
        self.assertTrue(np.all((mask == [0, 0, 0, 0, 0, 0]) == 1))

        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\chords_250ms.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # TODO: test functionality
        chord_mask = ManiaMapMetrics.detect_chords(action_data)
        print(action_data[chord_mask])
Example #13
0
    def test_calc_note_intervals(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\chords_250ms.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # TODO: test functionality
        note_intervals = ManiaMapMetrics.calc_note_intervals(action_data, 0)
    def test_get_actions_between(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\8k_mixed_timing_jacks.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # TODO: test functionality
        ManiaActionData.get_actions_between(action_data, 0, 100)
Example #15
0
    def test_data_to_anti_press_durations(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\chords_250ms.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # TODO: test functionality
        anti_press_durations = ManiaMapMetrics.anti_press_durations(action_data)
        def test_map(map_path):
            beatmap = BeatmapIO.open_beatmap(map_path)
            map_data = ManiaActionData.get_action_data(beatmap)

            dt = np.diff(map_data[:, ManiaActionData.IDX_STIME])
            self.assertTrue(all(dt >= 0), 'Map data is not order by note starting times')
    def test_get_idx_sort(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\8k_mixed_timing_jacks.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # TODO: test functionality
        ManiaActionData.get_idx_col_sort(action_data)
Example #18
0
    def test_detect_presses_during_holds(self):
        # Two long notes that are pressed and released at mutually exclusive times
        action_data = np.asarray([
            [ 100, 200, 0 ],
            [ 300, 400, 1 ],
        ])

        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
        self.assertTrue(np.all(mask == 0))

        # Two long notes that are pressed and released at mutually exclusive times, 
        # but press of one happens when the other is released
        action_data = np.asarray([
            [ 100, 200, 0 ],
            [ 200, 300, 1 ],
        ])

        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
        self.assertTrue(np.all(mask == 0))

        # Two long notes that are pressed and release at same time
        action_data = np.asarray([
            [ 100, 200, 0 ],
            [ 100, 200, 1 ],
        ])

        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
        self.assertTrue(np.all(mask == 0))

        # Two long notes, where one is pressed before the other, but released at same time
        action_data = np.asarray([
            [ 50,  200, 0 ],
            [ 100, 200, 1 ],
        ])

        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
        self.assertFalse(np.all(mask == 0))

        # Two long notes that are pressed at same time, but one is released before another
        action_data = np.asarray([
            [ 100, 150, 0 ],
            [ 100, 200, 1 ],
        ])

        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
        self.assertTrue(np.all(mask == 0))

        # Two long notes where one is pressed and released before another
        action_data = np.asarray([
            [ 100, 150, 0 ],
            [ 120, 200, 1 ],
        ])

        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
        self.assertFalse(np.all(mask == 0))

        # Two long notes where one is pressed and released while holding another
        action_data = np.asarray([
            [ 100, 300, 0 ],
            [ 150, 250, 1 ],
        ])

        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
        self.assertFalse(np.all(mask == 0))

        # Crash test
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\chords_250ms.osu')
        action_data = ManiaActionData.get_action_data(beatmap)
        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)

        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\playable\\DJ Genericname - Dear You (Taiwan-NAK) [S.Star\'s 4K HD+].osu')
        action_data = ManiaActionData.get_action_data(beatmap)
        mask = ManiaMapMetrics.detect_presses_during_holds(action_data)
Example #19
0
    def test_max_press_rate_per_col(self):
        beatmap = BeatmapIO.open_beatmap('unit_tests\\maps\\mania\\test\\chords_250ms.osu')
        action_data = ManiaActionData.get_action_data(beatmap)

        # TODO: test functionality
        press_rate = ManiaMapMetrics.calc_max_press_rate_per_col(action_data)