class GearCenter(InstructionGroup): def __init__(self, x, y, storage_pos, box_pos, type, size, background_color): super(GearCenter, self).__init__() self.color = background_color self.size = size self.storage_pos = storage_pos self.box_pos = box_pos self.type = type self.x = x self.y = y self.add(self.color) if self.type == 'center': self.middle_black = CEllipse( texture=CoreImage('images/play.png').texture) else: self.middle_black = CEllipse(cpos=self.storage_pos, csize=(self.size, self.size)) self.add(self.middle_black) self.is_draggable = False self.in_music_box = False def update_music_pos(self, pos): self.box_pos = pos def update_storage_pos(self, pos): self.storage_pos = pos def reset(self): self.middle_black.set_cpos(self.storage_pos) self.in_music_box = False def on_layout(self, pos, size): if self.in_music_box: self.middle_black.set_cpos(self.box_pos) else: self.middle_black.set_cpos(pos) self.middle_black.set_csize((size, size)) def get_distance_from_center(self, touch): return sqrt((touch[0] - self.middle_black.get_cpos()[0])**2 + (touch[1] - self.middle_black.get_cpos()[1])**2) def on_touch_down(self, touch): distance = self.get_distance_from_center(touch) if distance <= self.size and distance >= self.size / 2: self.is_draggable = True self.touch_x_diff = touch[0] - self.middle_black.get_cpos()[0] self.touch_y_diff = touch[1] - self.middle_black.get_cpos()[1] return True return False def on_touch_up(self, touch, gear_box_x, can_add_gear): # if it was previously dragged, update it to the correct location if self.is_draggable: if touch[0] <= gear_box_x or not can_add_gear(self): self.middle_black.set_cpos(self.storage_pos) self.in_music_box = False else: self.middle_black.set_cpos(self.box_pos) self.in_music_box = True self.is_draggable = False return self.in_music_box def on_touch_move(self, touch): if self.is_draggable: self.middle_black.set_cpos( (touch[0] - self.touch_x_diff, touch[1] - self.touch_y_diff)) return True return False
class NowBar(InstructionGroup): def __init__(self, bpm): super(NowBar, self).__init__() self.bpm = bpm # color the cursor grey self.color = Color(*kCursorDefaultColor) self.add(self.color) # save position and size self.xpos = PlaceOnBeat(.75) #kTrackLowerLimit self.xstart = self.xpos self.ypos = kGemBarYPos self.csize = kCursorSize # draw the cursor as a circle cpos = (self.xpos, self.ypos) self.cursor = CEllipse(cpos=cpos, csize=self.csize, texture=Image(kNowBarPng).texture) self.add(self.cursor) # limits that NowBar will be moving within, correlates with length of gem bar self.lim_lo = kTrackLowerLimit self.lim_hi = Window.width - self.lim_lo # save time for animation, by starting large, the cursor will maintain its size self.t = kCursorMaxTime # save speed of the cursor self.v = BpmToPixels(bpm) # initialize position of the NowBar self.active = True # hold callback that will be used to indicate reaching the end of the line self.end_cb = None def install_cb(self, cb): self.end_cb = cb def change_bpm(self, bpm): self.bpm = bpm self.v = BpmToPixels(self.bpm) def get_xpos(self): return self.xpos def update_pos(self, dt): # y should remain constant curr_xpos = self.cursor.get_cpos()[0] new_xpos = curr_xpos + self.v * dt self.cursor.set_cpos((new_xpos, self.ypos)) if not self.in_bounds(): if self.end_cb: self.end_cb() self.reset() self.xpos = self.cursor.get_cpos()[0] # move cursor back to beginning of the screen def reset(self): self.cursor.set_cpos((self.lim_lo, self.ypos)) def restart(self): self.cursor.set_cpos((self.xstart, self.ypos)) self.activate(True) # animate def animate(self, dt): new_size = kCursorSize[0] * exp(-kCursorDecayRate * self.t) * cos( kCursorOscRate * self.t) + kCursorSize[0] self.csize = (new_size, new_size) self.cursor.csize = self.csize self.t = kCursorMaxTime if ( self.t + dt >= kCursorMaxTime) else self.t + dt # reset time for animating key presses, can call this function when input is recorded def time_reset(self): self.t = 0 # find out if the barline is on screen, if so we will draw it def in_bounds(self): xpos = self.cursor.get_cpos()[0] return True if self.lim_lo <= xpos <= self.lim_hi else False def activate(self, active): self.active = active # update position and update animation def on_update(self, dt): # return whether the bar is active or inactive self.update_pos(dt) self.animate(dt) return self.active
class Gear(InstructionGroup): def __init__(self, x, y, size, num_teeth, gear_type, gear_value, storage_pos, box_pos, gear_id, background_color=Color(0, 0, 0), part=0): super(Gear, self).__init__() # part is 0 for melody and 1 for bassline self.part = part self.type = gear_type # 'volume', 'pitch', 'speed', 'instrument', 'center' self.color = self._get_color() self.value = gear_value self.x = x self.y = y self.storage_pos = storage_pos self.box_pos = box_pos self.gear_id = gear_id self.size = size self.add(self.color) self.main_circle = CEllipse(cpos=self.storage_pos, csize=(self.size, self.size)) self.add(self.main_circle) self.middle_size = self.size / 2 self.teeth = [] self.num_teeth = num_teeth self.add_teeth(self.storage_pos, self.num_teeth) self.is_draggable = False self.in_music_box = False self.touch_x_diff = None self.touch_y_diff = None self.time = 0 self.rpm = 0.1 self.is_rotating = False def update_music_pos(self, pos): self.box_pos = pos def update_storage_pos(self, pos): self.storage_pos = pos def _get_color(self): if self.type == 'volume': return colors["red"] elif self.type == 'pitch': return colors["orange"] elif self.type == 'tempo': return colors["purple"] elif self.type == 'center': return Color(rgb=hex_to_rgb('#5e6f81')) elif self.type == 'center1': return colors["trout"] else: return colors["yellow"] def add_teeth(self, center, num_teeth): for tooth in self.teeth: self.remove(tooth) self.teeth = [] self.add(self.color) self.add(PushMatrix()) self.add(Translate(center)) # use this Rotate to animate rotation for the whole flower self.rot = Rotate(angle=0, origin=self.storage_pos) self.add(self.rot) # make petals ellipses with these width and height: self.middle_size = self.size / 2 w = self.size / 5 h = self.size / 5 # how much to rotate each petal. d_theta = 360. / num_teeth for n in range(num_teeth): self.add(Rotate(angle=d_theta, origin=center)) self.add(Translate(self.middle_size, 0)) rect = CRectangle(cpos=center, csize=(h, w)) self.teeth.append(rect) self.add(rect) self.add(Translate(-self.middle_size, 0)) self.add(PopMatrix()) def on_layout(self, pos, size): self.size = size if self.in_music_box: self._update_graphics(self.box_pos) self.rot.origin = self.box_pos else: self._update_graphics(pos) self.rot.origin = pos self.main_circle.set_csize((size, size)) def stop(self): self.is_rotating = False def toggle_rotate(self): self.is_rotating = not self.is_rotating return self.is_rotating def _update_graphics(self, position): self.main_circle.set_cpos(position) self.add_teeth(position, self.num_teeth) def reset(self): self._update_graphics(self.storage_pos) self.rot.origin = self.storage_pos self.in_music_box = False def get_distance_from_center(self, touch): return sqrt((touch[0] - self.main_circle.get_cpos()[0])**2 + (touch[1] - self.main_circle.get_cpos()[1])**2) def on_touch_down(self, touch): distance = self.get_distance_from_center(touch) if distance <= self.size / 2 and distance >= self.middle_size / 2: self.is_draggable = True self.touch_x_diff = touch[0] - self.main_circle.get_cpos()[0] self.touch_y_diff = touch[1] - self.main_circle.get_cpos()[1] return True if self.type == 'center' and distance <= self.size: self.is_draggable = True self.touch_x_diff = touch[0] - self.main_circle.get_cpos()[0] self.touch_y_diff = touch[1] - self.main_circle.get_cpos()[1] return True return False def on_touch_up(self, touch, gear_box_x, can_add_gear): # if it was previously dragged, update it to the correct location if self.is_draggable: if touch[0] <= gear_box_x or not can_add_gear(self): self._update_graphics(self.storage_pos) self.rot.origin = self.storage_pos self.in_music_box = False else: self._update_graphics(self.box_pos) self.rot.origin = self.box_pos self.in_music_box = True self.is_draggable = False return self.in_music_box def on_touch_move(self, touch): if self.is_draggable: self._update_graphics( (touch[0] - self.touch_x_diff, touch[1] - self.touch_y_diff)) self.rot.origin = (touch[0] - self.touch_x_diff, touch[1] - self.touch_y_diff) return True return False def on_update(self, dt, multiple=False): if not multiple: if self.type == 'center': direction = -1 else: direction = 1 else: if self.type == 'center': direction = -1 elif self.type == 'center1': direction = 1 else: direction = -1 if self.is_rotating: degrees_per_sec = self.rpm * 360 / 60 self.rot.angle = degrees_per_sec * self.time self.time += direction * dt