text: from recordclass import recordclass
  
  from osr2mp4.ImageProcess import imageproc
  from osr2mp4.ImageProcess.Objects.FrameObject import FrameObject
  
  Circle = recordclass("Circle", "x y duration frame_i color combo_n obj_type fadeout_i is_fadeout x_step max_step")
  
  
  class CircleManager(FrameObject):
  	def __init__(self, frames, timepreempt, number, settings):
  		self.settings = settings
  		self.slidercircle_frames, self.circle_frames, self.circle_fadeout, self.alphas = frames
  		self.number = number
  		self.time_preempt = timepreempt
  		self.interval = self.settings.timeframe / self.settings.fps
  		self.circles = {}
  
  		self.timer = 0
  
  	def add_circle(self, osu_d, x, y, cur_time):
  
  		combo_color, combo_number = osu_d["combo_color"], osu_d["combo_number"]
  
  		object_type = "slider" in osu_d["type"]
  
  		duration = osu_d["time"] - cur_time
  		start_index = int((self.time_preempt - duration)/self.interval + 0.5) - 1
  
  		key = str(osu_d["id"]) + "c"
  		self.circles[key] = Circle(x, y, duration, start_index, combo_color, combo_number, object_type, 0, 0, 0, 0)
  
  	def notelock(self, circle):
  
  		step = 1 if circle.max_step % 2 == 0 else -1
  		circle.x_step += step * 5
  
  		if circle.x_step == 1 and circle.max_step == 5:
  			circle.x_step = 0
  
  		elif circle.x_step - 1 == step * 10:
  			circle.max_step += 1
  
  	def getcircle(self, circle):
  
  		color_index = circle.color - 1
  
  		if circle.obj_type:
  			# in case opacity_index exceed list range
  
  			opacity_index = min(circle.frame_i, len(self.slidercircle_frames[color_index]) - 1)
  			return self.slidercircle_frames[color_index][opacity_index], opacity_index
  
  		else:
  
  			opacity_index = min(circle.frame_i, len(self.circle_frames[color_index]) - 1)
  			return self.circle_frames[color_index][opacity_index], opacity_index
  
  	def add_to_frame(self, background, i, _):
  		circle = self.circles[i]
  
  		color_index = circle.color - 1
  		circle.duration -= self.interval
  
  		# timeout for circle, if self.interval*4 is the time for circle fadeout effect
  		if circle.is_fadeout:
  			is_slider = circle.obj_type
  			fadeout_frames = self.circle_fadeout[is_slider][color_index]
  
  			if circle.fadeout_i > len(fadeout_frames) - 1:
  				return
  
  			img = fadeout_frames[circle.fadeout_i]
  			imageproc.add(img, background, circle.x, circle.y)
  
  			circle.fadeout_i += 1
  			return
  
  		circle.frame_i += 1
  		number = circle.combo_n
  
  		# notelock
  		if circle.x_step:
  			self.notelock(circle)
  
  		img, index = self.getcircle(circle)
  
  		imageproc.add(img, background, circle.x+circle.x_step, circle.y)
  		self.number.add_to_frame(background, circle.x+circle.x_step, circle.y, self.alphas[index], number)
  
  
  