def get_offset(beatmap, start_index, end_index, replay_info, endtime, fps=60): replay_event = replay_info.play_data if endtime == -1: endtime = 5000 else: endtime = 0 start_time = replay_event[start_index][3] diffcalculator = DiffCalculator(beatmap.diff) timepreempt = diffcalculator.ar() # same as skip() code hitobjectindex = search_time(start_time, beatmap.hitobjects) to_time = min(beatmap.hitobjects[hitobjectindex]["time"] - timepreempt, start_time) osr_index = search_osrindex(to_time, replay_event) old = osr_index # simulate video draw code curtime = replay_event[osr_index][Replays.TIMES] interval = 1000 / fps while osr_index < start_index: curtime += interval tt, _ = nearer(curtime, replay_info, osr_index) osr_index += tt osr_index = max(0, osr_index - 1) offset = replay_event[osr_index][Replays.TIMES] endtime += replay_event[end_index][Replays.TIMES] + 100 logger.debug("\n\nOFFSET: %s", offset) return offset, endtime
def search_osrindex(to_time, replays): # pass_counter = 0 cur_index = 0 while cur_index <= len(replays) - 1 and replays[cur_index + 1][3] < to_time: cur_index += 1 logger.debug("cur_index %d", cur_index) return cur_index
def audioprc(my_info, beatmap, offset, endtime, mods, settings): nc = Mod.Nightcore in mods addmisssound = not (Mod.Relax in mods or Mod.Autopilot in mods) skin_path = settings.skin_path default_skinpath = settings.default_path beatmap_path = settings.beatmap audio_name = beatmap.general["AudioFilename"] ccc = time.time() try: audio_name = get_actual_audio_filename(audio_name, beatmap_path) song = Audio2p(*read(os.path.join(beatmap_path, audio_name), settings, volume=settings.settings["Song volume"] / 100, speed=settings.timeframe / 1000, changepitch=nc)) except FileNotFoundError: raise AudioNotFound() song.rate /= settings.timeframe / 1000 song.audio = apply_offset(song, settings.settings["Song delay"]) filenames = getfilenames(beatmap, settings.settings["Ignore beatmap hitsounds"]) setuphitsound(filenames, beatmap_path, skin_path, default_skinpath, settings) if not addmisssound: Hitsound.miss = Audio2p(1, np.zeros((0, 2), dtype=np.float32)) hitsoundm = HitsoundManager(beatmap) logger.debug("Done loading: %f", time.time() - ccc) for x in range(len(my_info)): hitsoundm.updatetimingpoint(my_info, x, song) hitsoundm.addhitsound(my_info, x, song) hitsoundm.addslidersound(my_info, x, song) hitsoundm.addspinnerhitsound(my_info, x, song) hitsoundm.addcombobreak(my_info, x, song) hitsoundm.addsectionsound(my_info, x, song) out = getoffset(offset, endtime, song) write(settings.temp + 'audio.mp3', round(song.rate * settings.timeframe / 1000), out)
def __init__(self, filename, settings, scale=1, delimiter="", rotate=0): self.settings = settings self.filename = filename self.scale = scale self.delimiter = delimiter self.frames = [] self.rotate = rotate self.n_frame = 0 self.unanimate = False self.imgfrom = None self.load(defaultpath=False) if self.unanimate and self.imgfrom == ImageFrom.BLANK: logger.debug("Loading default path YImagesss: %s", filename) self.frames = [] self.load(defaultpath=True)
def joinvideo(self): if self.data["Process"] >= 1: for i in range(self.data["Process"]): logger.debug(self.drawers[i].is_alive()) logger.debug(self.writers[i].is_alive()) self.drawers[i].join() logger.debug(f"Joined drawers {i}") self.writers[i].join( ) # temporary fixm might cause some infinite loop logger.debug(f"Joined writers {i}") conn1, conn2 = self.pipes[i] conn1.close() conn2.close() logger.debug(f"Closed conn {i}") self.drawers, self.writers, self.pipes = None, None, None
def checkmain(beatmap, replay_info, settings, tests=False): osr_index = 0 replay_event = replay_info.play_data diffmod(replay_info, beatmap.diff) hitobjectchecker = HitObjectChecker(beatmap, settings, replay_info, tests) break_index = 0 breakperiod = beatmap.breakperiods[break_index] in_break = int(replay_event[osr_index][Replays.TIMES]) in range( breakperiod["Start"], breakperiod["End"]) logger.debug("Start check") while osr_index < len(replay_event) - 3: k1, k2, m1, m2 = keys(replay_event[osr_index][Replays.KEYS_PRESSED]) if not in_break: f_k1, f_k2, f_m1, f_m2 = keys( replay_event[osr_index + 1][Replays.KEYS_PRESSED]) else: f_k1, f_k2, f_m1, f_m2 = False, False, False, False new_k1, new_k2 = f_k1 and not k1, f_k2 and not k2 new_m1, new_m2 = f_m1 and not m1, f_m2 and not m2 new_click = [new_k1, new_k2, new_m1, new_m2] hitobjectchecker.checkcursor(replay_event, new_click, osr_index + 1, in_break, breakperiod) osr_index += 1 breakperiod = beatmap.breakperiods[break_index] next_break = replay_event[osr_index][ Replays.TIMES] > breakperiod["End"] if next_break: break_index = min(break_index + 1, len(beatmap.breakperiods) - 1) breakperiod = beatmap.breakperiods[break_index] in_break = int(replay_event[osr_index][Replays.TIMES]) in range( breakperiod["Start"], breakperiod["End"]) logger.debug("check done") logger.log(1, "RETURN %r", hitobjectchecker.info[-1]) return hitobjectchecker.info
def search_updateindex(idd, resultinfo, component, to_time): if idd == -1: return len(resultinfo) - 1 cur_index = 0 while cur_index <= len(resultinfo) - 1 and resultinfo[cur_index].id != idd: cur_index += 1 # cur_index = max(0, cur_index - 1) if cur_index == 0: return 0 info = resultinfo[max(0, cur_index - 1)] component.scorecounter.set_score(resultinfo[cur_index].time, info.score, info.showscore) component.accuracy.set_acc(info.accuracy) component.combocounter.set_combo(info.combo) component.scorebar.set_hp(info.hp) component.scoreboard.setsetscore(info.score, info.combo) component.key1.set_freeze(resultinfo[cur_index].time, info.clicks[0]) component.key2.set_freeze(resultinfo[cur_index].time, info.clicks[1]) component.mouse1.set_freeze(resultinfo[cur_index].time, info.clicks[2]) component.mouse2.set_freeze(resultinfo[cur_index].time, info.clicks[3]) urindex = cur_index diff = 0 while diff < 5000: urindex -= 1 if urindex <= -1: break diff = info.time - resultinfo[urindex].time while urindex < cur_index: if type( resultinfo[urindex].more ).__name__ == "Circle" and resultinfo[urindex].hitresult is not None: if resultinfo[urindex].hitresult > 0: component.urbar.add_bar(resultinfo[urindex].more.deltat, resultinfo[urindex].hitresult) component.urbar.movearrow() urindex += 1 logger.debug("done") return cur_index
def __init__(self, scale, settings): self.score_images = [] scoreprefix = "-" score_x = scoreprefix + "x" score_percent = scoreprefix + "percent" score_dot = scoreprefix + "dot" for x in range(10): self.score_images.append(YImage(scoreprefix + str(x), settings, scale, prefix="ScorePrefix")) self.score_percent = YImage(score_percent, settings, scale, prefix="ScorePrefix") logger.debug(scale) # fierymod_v8_realest_ver[1] has very big score_percent.png but it doesn't show up in real osu # after some testing, if the image is >= 570px then it won't show up if self.score_percent.orig_cols >= int(570 * scale): self.score_percent.img = Image.new("RGBA", (self.score_percent.orig_cols, self.score_percent.orig_rows)) self.score_dot = YImage(score_dot, settings, scale, prefix="ScorePrefix") self.score_x = YImage(score_x, settings, scale, prefix="ScorePrefix") self.combo_images = [] for x in range(10): self.combo_images.append(YImage(scoreprefix + str(x), settings, scale, prefix="ComboPrefix")) self.combo_x = YImage(score_x, settings, scale, prefix="ComboPrefix")
def write(shared, conn, filename, settings, iii): asdfasdf = time.time() logger.debug("{}\n".format(filename)) logger.debug("Start write") if settings.codec.lower() in videoextensions: raise FourccIsNotExtension() buf = np.zeros((settings.height * settings.width * 3), dtype=np.uint8) writer = getwriter(filename, settings, buf) np_img = np.frombuffer(shared, dtype=np.uint8) np_img = np_img.reshape((settings.height, settings.width, 4)) buf = buf.reshape((settings.height, settings.width, 3)) timer = 0 timer2 = 0 timer3 = 0 a = 0 framecount = 1 logger.debug("start writing: %f", time.time() - asdfasdf) startwringtime = time.time() if iii: filewriter = open(os.path.join(settings.temp, "speed.txt"), "w") while a != 10: asdf = time.time() a = conn.recv() timer2 += time.time() - asdf if a == 1: asdf = time.time() cv2.cvtColor(np_img, cv2.COLOR_BGRA2RGB, dst=buf) conn.send(0) timer3 += time.time() - asdf asdf = time.time() if not settings.settings["Use FFmpeg video writer"]: writer.write(buf) else: writer.write() timer += time.time() - asdf framecount += 1 if iii and framecount % 200: deltatime = max(1, timer) filewriter.seek(0) # logger.log(1, "Writing progress {}, {}, {}, {}".format(framecount, deltatime, filename, startwringtime)) filewriter.write("{}\n{}\n{}\n{}".format(framecount, deltatime, filename, startwringtime)) filewriter.truncate() if iii: filewriter.write("done") filewriter.close() logger.debug("Release write") writer.release() logger.debug("End write") logger.debug("\nWriting done {}".format(filename)) logger.debug("Writing time: {}".format(timer)) logger.debug("Total time: {}".format(time.time() - asdfasdf)) logger.debug("Waiting time: {}".format(timer2)) logger.debug("Changing value time: {}".format(timer3))
def __init__(self, settings, diff, mod_combination, ur=None, bg=None, loadranking=True): skin = settings.skin_ini self.loadranking = loadranking check = DiffCalculator(diff) hd = Mod.Hidden in mod_combination fl = Mod.Flashlight in mod_combination if settings.settings["Automatic cursor size"]: circlescale = 4/diff["CircleSize"] settings.settings["Cursor size"] *= circlescale if ur is None: ur = [0, 0, 0] if bg is None: bg = [0, 0, ""] logger.debug('start preparing cursor') self.cursor, default = prepare_cursor(settings.scale * settings.settings["Cursor size"], settings) logger.debug('start preparing cursormiddle') self.cursormiddle, self.continuous = prepare_cursormiddle(settings.scale * settings.settings["Cursor size"], settings, default) logger.debug('start preparing cursortrail') self.cursor_trail = prepare_cursortrail(settings.scale * settings.settings["Cursor size"], self.continuous, settings) logger.debug('start preparing scoreentry') self.scoreentry = prepare_scoreentry(settings.scale, skin.colours["InputOverlayText"], settings) self.inputoverlayBG = prepare_inputoverlaybg(settings.scale, settings) self.key = prepare_inputoverlay(settings.scale, [255, 220, 20], 2, settings) self.mouse = prepare_inputoverlay(settings.scale, [220, 0, 220], 1, settings) logger.debug('start preparing scorenumber') self.scorenumbers = ScoreNumbers(settings.scale, settings) self.hitcirclenumber = prepare_hitcirclenumber(diff, settings.playfieldscale, settings) logger.debug('start preparing accuracy') self.accuracy = prepare_accuracy(self.scorenumbers) self.combocounter = prepare_combo(self.scorenumbers, settings) self.hitresult = prepare_hitresults(settings.scale, diff, settings) self.spinbonus = prepare_spinbonus(self.scorenumbers) self.scorecounter = prepare_scorecounter(self.scorenumbers) self.playinggrade = prepare_playinggrade(settings.scale * 0.75, settings) self.urbar = prepare_bar(settings.scale * settings.settings["Score meter size"], check.scorewindow) self.fpmanager = prepare_fpmanager(settings.playfieldscale, settings) logger.debug('start preparing circle') self.circle = prepare_circle(diff, settings.playfieldscale, settings, hd) self.slider = prepare_slider(diff, settings.playfieldscale, settings) self.spinner = prepare_spinner(settings.playfieldscale, settings) logger.debug('start preparing background') self.bg = prepare_background(os.path.join(settings.beatmap, bg[2]), settings) logger.debug('start preparing sections') self.sections = prepare_sections(settings.scale, settings) self.scorebarbg = prepare_scorebarbg(settings.scale, self.bg, settings) self.scorebar = prepare_scorebar(settings.scale, settings) self.arrowwarning = prepare_arrowwarning(settings.scale, settings) logger.debug('start preparing scoreboard') self.scoreboardscore = prepare_scoreboardscore(settings.scale, settings) self.scoreboard = prepare_scoreboard(settings.scale, settings) self.scoreboardeffect = prepare_scoreboardeffect(settings.scale) self.modicons = prepare_modicons(settings.scale, settings) if loadranking: self.rankingpanel = prepare_rankingpanel(settings.scale, self.bg, settings) self.rankinghitresults = prepare_rankinghitresults(settings.scale, settings) self.rankingscore = prepare_rankingscorecounter(self.scorenumbers) self.rankinggrades = prepare_rankinggrade(settings.scale, settings) self.rankingtitle = prepare_rankingtitle(settings.scale, settings) self.rankingcombo = prepare_rankingcombo(settings.scale * 1.05, settings) self.rankingaccuracy = prepare_rankingaccuracy(settings.scale * 1.05, settings) self.menuback = prepare_menuback(settings.scale, settings) self.rankingreplay = prepare_rankingreplay(settings.scale, settings) self.rankinggraph = prepare_rankinggraph(settings.scale, settings) logger.debug("start preparing ur ranking") self.rankingur = prepare_rankingur(settings, ur) self.rankinggraph.extend(self.rankingur) self.flashlight = prepare_flashlight(settings, fl) self.urarrow = prepare_urarrow(settings) logger.debug('start preparing done')
def draw(shared, conn, beatmap, replay_info, resultinfo, videotime, settings, showranking): asdfasdf = time.time() logger.log(1, "CALL {}, {}".format(videotime, showranking)) logger.debug("process start") ur = getunstablerate(resultinfo) frames = PreparedFrames(settings, beatmap.diff, replay_info.mod_combination, ur=ur, bg=beatmap.bg, loadranking=showranking) drawer = Drawer(shared, beatmap, frames, replay_info, resultinfo, videotime, settings) logger.log(1, "PROCESS {}, {}".format(videotime, drawer)) logger.debug("setup done") logger.debug("Starting draw") timer = 0 timer2 = 0 timer3 = 0 while drawer.frame_info.osr_index < videotime[1]: status = drawer.render_draw() asdf = time.time() if status: conn.send(1) timer3 += time.time() - asdf asdf = time.time() i = conn.recv() timer2 += time.time() - asdf if showranking: for x in range(int(5 * settings.fps)): drawer.draw_rankingpanel() conn.send(1) i = conn.recv() conn.send(10) logger.debug("End draw: %f", time.time() - asdfasdf) logger.debug("\nprocess done {}, {}".format(videotime, drawer)) logger.debug("Drawing time: {}".format(timer)) logger.debug("Total time: {}".format(time.time() - asdfasdf)) logger.debug("Waiting time: {}".format(timer2)) logger.debug("Changing value time: {}".format(timer3))
def __init__(self, frames, fonts): super().__init__(frames[0]) self.nwidth = self.w() scale = frames[1] self.overlap = int(fonts["HitCircleOverlap"]*scale) logger.debug("%s %s %s", self.overlap, fonts["HitCircleOverlap"], scale)
def setupglobals(data, gameplaydata, mod_combination, settings, ppsettings=None, strainsettings=None): skin_path = data["Skin path"] beatmap_path = data["Beatmap path"] output_path = data.get("Output path", "output.avi") ffmpeg = data.get("ffmpeg path", "ffmpeg") default_path = os.path.join(settings.path, "res/default/") fps = data.get("FPS", 60) width = data.get("Width", 1920) height = data.get("Height", 1080) osupath = data.get("osu! path", None) # # if skin_path[-1] != "/" and skin_path[-1] != "\\": # skin_path += "/" # # if beatmap_path[-1] != "/" and beatmap_path[-1] != "\\": # beatmap_path += "/" # # if osupath[-1] != "/" and osupath[-1] != "\\": # osupath += "/" time_frame = 1000 if Mod.DoubleTime in mod_combination or Mod.Nightcore in mod_combination: time_frame *= 1.5 if Mod.HalfTime in mod_combination: time_frame *= 0.75 logger.debug(time_frame) playfield_scale, playfield_width, playfield_height, scale, move_right, move_down = get_screensize( width, height) settings.width, settings.height, settings.scale = width, height, scale settings.playfieldscale, settings.playfieldwidth, settings.playfieldheight = playfield_scale, playfield_width, playfield_height settings.fps, settings.timeframe = fps, time_frame settings.moveright, settings.movedown = move_right, move_down settings.output = output_path settings.ffmpeg = ffmpeg settings.beatmap = beatmap_path settings.osu = osupath skin = Skin(skin_path, default_path) # defaultskin = Skin(default_path, default_path) settings.skin_path = skin_path settings.default_path = default_path settings.skin_ini = skin settings.default_skin_ini = skin # gameplaydata["Enable PP counter"] = gameplaydata.get("Enable PP counter", False) # gameplaydata["Song delay"] = gameplaydata.get("Song delay", 0) # gameplaydata["Show mods icon"] = gameplaydata.get("Show mods icon", True) # gameplaydata["Custom mods"] = gameplaydata.get("Custom mods", "") # gameplaydata["Use FFmpeg video writer"] = gameplaydata.get("Use FFmpeg video writer", False) # gameplaydata["FFmpeg codec"] = gameplaydata.get("Use FFmpeg video writer", False) # gameplaydata["Use FFmpeg video writer"] = gameplaydata.get("Use FFmpeg video writer", False) for setting in defaultsettings: if setting not in gameplaydata: gameplaydata[setting] = defaultsettings[setting] settings.settings = gameplaydata if ppsettings is not None: settings.ppsettings = ppsettings if strainsettings is not None: settings.strainsettings = strainsettings
def prepare_circle(diff, scale, settings, hd): # prepare every single frame before entering the big loop, this will save us a ton of time since we don't need # to overlap number, circle overlay and approach circle every single time. opacity_interval, time_preempt, fade_in = calculate_ar( diff["ApproachRate"], settings) cs = (54.4 - 4.48 * diff["CircleSize"]) * scale radius_scale = cs * overlay_scale * 2 / default_size circle, c_overlay, slider, s_overlay = load(settings) if not hd: approach_frames = prepare_approach(radius_scale, time_preempt, settings) fadeout = [[], []] # circle, slider circle_frames = [] # [color][number][alpha] slidercircle_frames = [] # [color][number][alpha] alphas = [] for c in range(1, settings.skin_ini.colours["ComboNumber"] + 1): color = settings.skin_ini.colours["Combo" + str(c)] orig_circle = overlayhitcircle(c_overlay, circle, color, radius_scale) if not hd: fadeout[0].append(prepare_fadeout(orig_circle, settings)) else: fadeout[0].append([Image.new("RGBA", (1, 1))]) orig_slider = overlayhitcircle(s_overlay, slider, color, radius_scale) if not hd: fadeout[1].append(prepare_fadeout(orig_slider, settings)) else: fadeout[1].append([Image.new("RGBA", (1, 1))]) alpha = 0 # alpha for fadein circle_frames.append([]) slidercircle_frames.append([]) if not hd: # we also overlay approach circle to circle to avoid multiple add_to_frame call for i in range(len(approach_frames)): approach_circle = imageproc.add_color(approach_frames[i], color) approach_slider = approach_circle.copy() circle_frames[-1].append( overlayapproach(orig_circle, approach_circle, alpha)) slidercircle_frames[-1].append( overlayapproach(orig_slider, approach_slider, alpha)) alphas.append(alpha) alpha = min(100, alpha + opacity_interval) # for late tapping slidercircle_frames[-1].append(orig_slider) circle_frames[-1].append(orig_circle) alphas.append(alpha) else: # source: https://github.com/ppy/osu/blob/4cb57f8205edf5ed7b7da076325ba76ec9cc3039/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs#L23 interval = settings.timeframe / settings.fps fade_in = time_preempt * 0.4 fade_in_interval = 100 * interval / fade_in ii = fade_in_interval fade_out = time_preempt * 0.3 fade_out_interval = 100 * interval / fade_out #interval = 1 if not interval else interval for i in np.arange(time_preempt, 0, -interval): if alpha != 0: circle_frames[-1].append(newalpha(orig_circle, alpha / 100)) slidercircle_frames[-1].append( newalpha(orig_slider, alpha / 100)) else: circle_frames[-1].append(Image.new("RGBA", (1, 1))) slidercircle_frames[-1].append(Image.new("RGBA", (1, 1))) if alpha == 100: ii = -fade_out_interval alphas.append(alpha) alpha = max(0, min(100, alpha + ii)) logger.debug("done") return slidercircle_frames, circle_frames, fadeout, alphas
from osr2mp4 import logger from osr2mp4cv import getaudiocodec a = getaudiocodec() codec = {} for x in a: codec[x.decode("utf-8")] = a[x].decode("utf-8") for x in codec: logger.debug(f"{x}: {codec[x]}")
def create_frame(settings, beatmap, replay_info, resultinfo, videotime, showranking): logger.debug('entering preparedframes') if settings.process >= 1: shared_array = [] shared_pipe = [] drawers = [] writers = [] start_index, end_index = videotime osr_interval = int((end_index - start_index) / settings.process) start = start_index my_file = open(os.path.join(settings.temp, "listvideo.txt"), "w") for i in range(settings.process): if i == settings.process - 1: end = end_index else: end = start + osr_interval shared = RawArray(ctypes.c_uint8, settings.height * settings.width * 4) conn1, conn2 = Pipe() # extract container _, file_extension = os.path.splitext(settings.output) f = "output" + str(i) + file_extension vid = (start, end) drawer = Process(target=draw_frame, args=( shared, conn1, beatmap, replay_info, resultinfo, vid, settings, showranking and i == settings.process-1)) writer = Process(target=write_frame, args=(shared, conn2, settings.temp + f, settings, i == settings.process-1)) shared_array.append(shared) shared_pipe.append((conn1, conn2)) drawers.append(drawer) writers.append(writer) my_file.write("file '{}'\n".format(f)) logger.debug("Starting process") drawer.start() logger.debug("Start drawer {}".format(i)) writer.start() logger.debug("Start writer {}".format(i)) start += osr_interval my_file.close() return drawers, writers, shared_pipe, shared_array else: from osr2mp4.VideoProcess.AFrames import PreparedFrames from osr2mp4.CheckSystem.mathhelper import getunstablerate import numpy as np logger.debug("process start") ur = getunstablerate(resultinfo) frames = PreparedFrames(settings, beatmap.diff, replay_info.mod_combination, ur=ur, bg=beatmap.bg, loadranking=showranking) shared = RawArray(ctypes.c_uint8, settings.height * settings.width * 4) drawer = Drawer(shared, beatmap, frames, replay_info, resultinfo, videotime, settings) _, file_extension = os.path.splitext(settings.output) f = os.path.join(settings.temp, "outputf" + file_extension) buf = np.zeros((settings.height * settings.width * 3), dtype=np.uint8) writer = getwriter(f, settings, buf) buf = buf.reshape((settings.height, settings.width, 3)) logger.debug("setup done") framecount = 0 startwritetime = time.time() while drawer.frame_info.osr_index < videotime[1]: status = drawer.render_draw() if status: cv2.cvtColor(drawer.np_img, cv2.COLOR_BGRA2RGB, dst=buf) if not settings.settings["Use FFmpeg video writer"]: writer.write(buf) else: writer.write() framecount += 1 if framecount % 100 == 0: filewriter = open(os.path.join(settings.temp, "speed.txt"), "w") deltatime = time.time() - startwritetime filewriter.write("{}\n{}\n{}\n{}".format(framecount, deltatime, f, startwritetime)) filewriter.close() update_progress(framecount, deltatime, videotime) if showranking: for x in range(int(5 * settings.fps)): drawer.draw_rankingpanel() cv2.cvtColor(drawer.np_img, cv2.COLOR_BGRA2RGB, dst=buf) if not settings.settings["Use FFmpeg video writer"]: writer.write(buf) else: writer.write() writer.release() logger.debug("\nprocess done") return None, None, None, None