def __init__(self, **kwargs): super(LevelSelectScreen, self).__init__(**kwargs) Window.clearcolor = colors['grey'].rgba self.anim_group = AnimGroup() self.canvas.add(self.anim_group) self.label = Label(text='Play it by Gear', font_name='./fonts/PassionOne-Regular', color=(.165, .718, .792, 1)) self.add_widget(self.label) self.buttons = [] self.id_counter = 0 self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.start_time = None self.switch_level = None self.border_color = colors['dark_grey'] self.border = Line(rectangle=(0, 0, Window.width, Window.height), width=Window.width * 0.03) self.anim_group.add(self.border_color) self.anim_group.add(self.border) self.on_layout((Window.width, Window.height))
def __init__(self, notes, bank=0, preset=0, loop=False, simon_says=False, bass_puzzle=False): super().__init__() self.audio = Audio(2) self.synth = Synth("./data/FluidR3_GM.sf2") self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) self.sched.set_generator(self.synth) self.audio.set_generator(self.sched) self.notes = notes self.bank = bank self.preset = preset self.loop = loop self.simon_says = simon_says self.bass_puzzle = bass_puzzle self.note_seq = NoteSequencer( sched=self.sched, synth=self.synth, channel=1, program=(self.bank, self.preset), notes=self.notes, loop=self.loop, )
def __init__(self): super(MainWidget, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # Note Sequencers self.seq1 = NoteSequencer(self.sched, self.synth, 1, (0, 65), kYesterday, False) self.seq2 = NoteSequencer(self.sched, self.synth, 2, (0, 52), kSomewhere, True) # and text to display our status self.label = topleft_label() self.add_widget(self.label)
class MainWidget1(BaseWidget) : def __init__(self): super(MainWidget1, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # create the arpeggiator: self.arpeg = Arpeggiator(self.sched, self.synth, channel = 1, program = (0,0) ) # and text to display our status self.label = topleft_label() self.add_widget(self.label) def on_key_down(self, keycode, modifiers): if keycode[1] == 'm': self.metro.toggle() if keycode[1] == 'a': self.arpeg.start() pitches = lookup(keycode[1], 'qwe', ((60, 64, 67, 72), (55, 59, 62, 65, 67, 71), (60, 65, 69))) if pitches: self.arpeg.set_pitches(pitches) rhythm = lookup(keycode[1], 'uiop', ((120, 1), (160, 1), (240, 0.75), (480, 0.25))) if rhythm: self.arpeg.set_rhythm(*rhythm) direction = lookup(keycode[1], '123', ('up', 'down', 'updown')) if direction: self.arpeg.set_direction(direction) def on_key_up(self, keycode): if keycode[1] == 'a': self.arpeg.stop() def on_update(self) : self.audio.on_update() self.label.text = self.sched.now_str() + '\n' self.label.text += 'tempo:%d\n' % self.tempo_map.get_tempo() self.label.text += 'm: toggle Metronome\n' self.label.text += 'a: Enable Arpeggiator\n' self.label.text += 'q w e: Changes pitches\n' self.label.text += 'u i o p: Change Rhythm\n' self.label.text += '1 2 3: Change Direction\n'
def __init__(self, **kwargs): super(MainScreen, self).__init__(**kwargs) mode = 'mac' if (len(sys.argv) == 2) and (sys.argv[1] == 'mac') else 'pc' self.norm = Normalizer(mode) self.info = topleft_label() self.add_widget(self.info) self.writer = AudioWriter('recordings/song') self.audio = Audio(2, self.writer.add_audio) self.mixer = Mixer() self.mixer.set_gain(1.0) self.audio.set_generator(self.mixer) self.sandbox = Sandbox(canvas=self.canvas, pos=self.norm.nt((580, 50)), size=self.norm.nt((1000, 1000))) # since putting all our sound module code in MainScreen would be a nightmare, we've # modularized our modules into separate files. each module has two classes, the sound # module itself and its handler class. the handler class is essentially a wrapper of # many of MainScreen's important event functions (e.g. on_touch_down) that keeps track # of all variables related to that sound module for every connected client. self.module_dict = { 'PhysicsBubble': PhysicsBubble, 'SoundBlock': SoundBlock, 'TempoCursor': TempoCursor } block = SoundBlockHandler(self.norm, self.sandbox, self.mixer, client, client_id) self.module_handlers = { 'SoundBlock': block, 'PhysicsBubble': PhysicsBubbleHandler(self.norm, self.sandbox, self.mixer, client, client_id, block), 'TempoCursor': TempoCursorHandler(self.norm, self.sandbox, self.mixer, client, client_id, block) } # name a default starting module and handler self.module = PhysicsBubble self.module_handler = self.module_handlers[self.module.name] self.sandbox.add(self.module_handler.gui) # sync with existing server state client.emit('sync_module_state', {'module': 'PhysicsBubble'}) client.emit('sync_module_state', {'module': 'SoundBlock'}) client.emit('sync_module_state', {'module': 'TempoCursor'}) client.emit('update_norm', {'norm': {client_id: self.norm.mode}})
def __init__(self, level=0, prev_room=None, on_finished_puzzle=None): super().__init__() self.create_objects() self.place_objects() self.blocks_placed = 0 self.create_treasure_popup((Window.width, Window.height)) self.audio = Audio(2) self.mixer = Mixer() self.mixer.set_gain(0.2) self.audio.set_generator(self.mixer) self.wave_file_gen = WaveGenerator( WaveFile("./data/treasure_music.wav"))
def __init__(self, level, goal_music_seq, duration, edit_goal_play_status=None): super(LevelOptions, self).__init__() self.level = level # level number self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.options_bar = Rectangle(pos=(0, 0)) self.home_button = Rectangle( texture=CoreImage('images/home.png').texture) self.play_button = Rectangle( texture=CoreImage('images/play.png').texture) self.reset_button = Rectangle( texture=CoreImage('images/reset.png').texture) self.check_button = Rectangle( texture=CoreImage('images/check.png').texture) self.on_layout((Window.width, Window.height)) self.add(colors['grey']) self.add(self.options_bar) self.add(colors['green']) self.add(self.home_button) self.add(self.play_button) self.add(self.reset_button) self.add(self.check_button) self.is_playing = False self.start_time = None self.duration = 0 self.goal_music_seq = None self.duration_circle = Line() self.add(self.duration_circle) # true iff you recently lost or won the game self.win_or_lose = False self.win_gen = WaveGenerator(WaveFile("./data/win_sound.wav")) self.lose_gen = WaveGenerator(WaveFile("./data/lose_sound.wav")) self.goal_music_seq = goal_music_seq self.duration = duration self.button_press_time = None self.edit_goal_play_status = edit_goal_play_status
class MainWidget(BaseWidget): def __init__(self): super(MainWidget, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # Note Sequencers self.seq1 = NoteSequencer(self.sched, self.synth, 1, (0, 65), kYesterday, False) self.seq2 = NoteSequencer(self.sched, self.synth, 2, (0, 52), kSomewhere, True) # and text to display our status self.label = topleft_label() self.add_widget(self.label) def on_key_down(self, keycode, modifiers): obj = lookup(keycode[1], 'mas', (self.metro, self.seq1, self.seq2)) if obj is not None: obj.toggle() bpm_adj = lookup(keycode[1], ('up', 'down'), (10, -10)) if bpm_adj: new_tempo = self.tempo_map.get_tempo() + bpm_adj self.tempo_map.set_tempo(new_tempo, self.sched.get_time()) def on_update(self): self.audio.on_update() self.label.text = self.sched.now_str() + '\n' self.label.text += 'tempo:%d\n' % self.tempo_map.get_tempo() self.label.text += 'm: toggle Metronome\n' self.label.text += 'a: toggle Sequence 1\n' self.label.text += 's: toggle Sequence 2\n' self.label.text += 'up/down: change speed\n'
class MainWidget4(BaseWidget): def __init__(self): super(MainWidget4, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') self.audio.set_generator(self.synth) # create clock, tempo_map, scheduler self.clock = Clock() self.tempo_map = SimpleTempoMap(120) self.sched = Scheduler(self.clock, self.tempo_map) # create the metronome: self.metro = Metronome(self.sched, self.synth) # and text to display our status self.label = topleft_label() self.add_widget(self.label) def on_key_down(self, keycode, modifiers): if keycode[1] == 'c': self.clock.toggle() if keycode[1] == 'm': self.metro.toggle() bpm_adj = lookup(keycode[1], ('up', 'down'), (10, -10)) if bpm_adj: new_tempo = self.tempo_map.get_tempo() + bpm_adj self.tempo_map.set_tempo(new_tempo, self.sched.get_time()) def on_update(self): # scheduler and audio get poked every frame self.sched.on_update() self.audio.on_update() bpm = self.tempo_map.get_tempo() self.label.text = self.sched.now_str() + '\n' self.label.text += 'Metronome:' + ("ON" if self.metro.playing else "OFF") + '\n' self.label.text += 'tempo:{}\n'.format(bpm) self.label.text += 'm: toggle Metronome\n' self.label.text += 'up/down: change speed\n'
def __init__(self): super(MainWidget4, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') self.audio.set_generator(self.synth) # create clock, tempo_map, scheduler self.clock = Clock() self.tempo_map = SimpleTempoMap(120) self.sched = Scheduler(self.clock, self.tempo_map) # create the metronome: self.metro = Metronome(self.sched, self.synth) # and text to display our status self.label = topleft_label() self.add_widget(self.label)
def __init__(self): super(MainWidget2, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # create the arpeggiator: self.arpeg = Arpeggiator(self.sched, self.synth, channel = 1, program = (0,0) ) self.arpeg.set_direction('updown') #size of the notes sent to the arpeggiator self.arpegSize = 3 #all of the notes this program can make. However, only self.arpegSize notes are sent to the arpegiator at a time self.allNotes = [50, 53, 55, 56, 57, 60, 62, 65, 67, 68, 69, 72, 74] self.lastPitchIndex = None self.lastPulseIndex = None self.noteLengths = [240, 210, 180, 150, 120, 90, 60] self.articulation = .75 # and text to display our status self.label = topleft_label() self.add_widget(self.label) # and text to display our status self.label = topleft_label() self.add_widget(self.label) self.objects = AnimGroup() self.canvas.add(self.objects) self.add_lines()
class MainWidget1(BaseWidget): def __init__(self): super(MainWidget1, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') self.audio.set_generator(self.synth) self.label = topleft_label() self.add_widget(self.label) cc_range = range(0, 128, 8) self.modifier = Modifier() self.modifier.add('a', "program", range(128), lambda x: self.synth.program_change(0, x)) self.modifier.add('s', "vibrato", cc_range, lambda x: self.synth.cc(0, 1, x)) self.modifier.add('d', "volume", cc_range, lambda x: self.synth.cc(0, 7, x)) self.modifier.add('f', "sustain", (0, 127), lambda x: self.synth.cc(0, 64, x)) self.modifier.add('z', "bend", range(-8192, 8192, 256), lambda x: self.synth.pitch_bend(0, int(x))) def on_key_down(self, keycode, modifiers): self.modifier.on_key_down(keycode[1]) pitch = lookup(keycode[1], kKeys, kPitches) if pitch: self.synth.noteon(0, pitch, 100) def on_key_up(self, keycode): self.modifier.on_key_up(keycode[1]) pitch = lookup(keycode[1], kKeys, kPitches) if pitch: self.synth.noteoff(0, pitch) def on_update(self): self.audio.on_update() self.modifier.on_update() self.label.text = self.modifier.get_txt() + '\n'
def __init__(self): super(MainWidget5, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # and text to display our status self.label = topleft_label() self.add_widget(self.label)
def __init__(self): super(MainWidget1, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') self.audio.set_generator(self.synth) self.label = topleft_label() self.add_widget(self.label) cc_range = range(0, 128, 8) self.modifier = Modifier() self.modifier.add('a', "program", range(128), lambda x: self.synth.program_change(0, x)) self.modifier.add('s', "vibrato", cc_range, lambda x: self.synth.cc(0, 1, x)) self.modifier.add('d', "volume", cc_range, lambda x: self.synth.cc(0, 7, x)) self.modifier.add('f', "sustain", (0, 127), lambda x: self.synth.cc(0, 64, x)) self.modifier.add('z', "bend", range(-8192, 8192, 256), lambda x: self.synth.pitch_bend(0, int(x)))
class MainWidget5(BaseWidget): def __init__(self): super(MainWidget5, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # and text to display our status self.label = topleft_label() self.add_widget(self.label) def on_key_down(self, keycode, modifiers): if keycode[1] == 'm': self.metro.toggle() bpm_adj = lookup(keycode[1], ('up', 'down'), (10, -10)) if bpm_adj: new_tempo = self.tempo_map.get_tempo() + bpm_adj self.tempo_map.set_tempo(new_tempo, self.sched.get_time()) def on_update(self): self.audio.on_update() bpm = self.tempo_map.get_tempo() self.label.text = self.sched.now_str() + '\n' self.label.text += 'tempo:{}\n'.format(bpm) self.label.text += 'm: toggle Metronome\n' self.label.text += 'up/down: change speed\n'
def __init__(self): super(MainWidget, self).__init__() self.writer = AudioWriter('song') self.audio = Audio(2, self.writer.add_audio) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(95*2) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # variables to store options self.transposition = 0 self.style = None self.melody = None self.chords = None self.chord_option = None self.perc = None self.perc_option = None # variables to store screen options self.style_selection = StyleSelection(self.update_style_screen) # screen index 0 self.key_selection = KeySelection(self.update_key_screen) # screen index 1 self.chord_selection = None # screen index 2 self.perc_selection = None # screen index 3 self.melody_selection = None # screen index 4 self.active_screen = self.style_selection self.screen_index = 0 self.add_widget(self.active_screen)
class MainWidget2(BaseWidget) : def __init__(self): super(MainWidget2, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # create the arpeggiator: self.arpeg = Arpeggiator(self.sched, self.synth, channel = 1, program = (0,0) ) self.arpeg.set_direction('updown') #size of the notes sent to the arpeggiator self.arpegSize = 3 #all of the notes this program can make. However, only self.arpegSize notes are sent to the arpegiator at a time self.allNotes = [50, 53, 55, 56, 57, 60, 62, 65, 67, 68, 69, 72, 74] self.lastPitchIndex = None self.lastPulseIndex = None self.noteLengths = [240, 210, 180, 150, 120, 90, 60] self.articulation = .75 # and text to display our status self.label = topleft_label() self.add_widget(self.label) # and text to display our status self.label = topleft_label() self.add_widget(self.label) self.objects = AnimGroup() self.canvas.add(self.objects) self.add_lines() def add_lines(self): w = Window.width h = Window.height numBuckets = len(self.allNotes) - self.arpegSize sizeOfBucket = w / numBuckets for i in range(numBuckets): xVal = i * sizeOfBucket line = Line(points=[xVal, 0, xVal, h], width=2) self.objects.add(line) numBuckets = len(self.noteLengths) sizeOfBucket = h / numBuckets for i in range(numBuckets): yVal = i * sizeOfBucket line = Line(points=[0, yVal, w, yVal], width=2) self.objects.add(line) def on_touch_down(self, touch): p = touch.pos self.update_pitches(p) self.update_pulse(p) self.arpeg.start() def on_touch_up(self, touch): self.arpeg.stop() def on_touch_move(self, touch): p = touch.pos self.update_pitches(p) self.update_pulse(p) def update_pitches(self, pos=(0,0)): mouseX = pos[0] w = Window.width numBuckets = len(self.allNotes) - self.arpegSize sizeOfBucket = w / numBuckets noteBucket = int(mouseX // sizeOfBucket) if noteBucket != self.lastPitchIndex: arpegNotes = self.allNotes[noteBucket:noteBucket+self.arpegSize] self.lastSlice = arpegNotes self.arpeg.set_pitches(arpegNotes) self.lastPitchIndex = noteBucket def update_pulse(self, pos=(0,0)): mouseY = pos[1] h = Window.height numBuckets = len(self.noteLengths) sizeOfBucket = h / numBuckets pulseBucket = int(mouseY // sizeOfBucket) if pulseBucket < len(self.noteLengths) and pulseBucket != self.lastPulseIndex: length = self.noteLengths[pulseBucket] self.arpeg.set_rhythm(length, self.articulation) self.lastPulseIndex = pulseBucket def on_update(self) : self.audio.on_update() self.label.text = self.sched.now_str() + '\n'
class TreasureRoom(Puzzle): def __init__(self, level=0, prev_room=None, on_finished_puzzle=None): super().__init__() self.create_objects() self.place_objects() self.blocks_placed = 0 self.create_treasure_popup((Window.width, Window.height)) self.audio = Audio(2) self.mixer = Mixer() self.mixer.set_gain(0.2) self.audio.set_generator(self.mixer) self.wave_file_gen = WaveGenerator( WaveFile("./data/treasure_music.wav")) """ Mandatory Puzzle methods """ def is_game_over(self): pass def create_objects(self): self.objects = {} size = (self.grid.tile_side_len, self.grid.tile_side_len) icons = [ "./data/guitar.png", "./data/bass.png", "./data/drums.png", "./data/piano.png", ] init_positions = [(1, 1), (1, 7), (7, 1), (7, 7)] final_positions = [(2, 4), (3, 4), (5, 4), (6, 4)] colors = [ Color(hsv=(0, 0.5, 1)), # Green Color(hsv=(0.15, 0.5, 1)), # Red Color(hsv=(0.25, 0.5, 1)), # Yellow Color(hsv=(0.5, 0.5, 1)), # Blue ] for i in range(len(icons)): self.objects[init_positions[i]] = MovingBlock( size, self.grid.grid_to_pixel(init_positions[i]), ((1, 1), (8, 8)), colors[i], icons[i], final_positions[i], ) self.grid.get_tile(final_positions[i]).set_color(colors[i]) def place_objects(self): self.create_objects() self.add(PushMatrix()) self.add(Translate(*self.grid.pos)) for pos, obj in self.objects.items(): self.add(obj) self.add(PopMatrix()) def valid_block_move(self, pos, move_range): return (move_range[0][0] <= pos[0] < move_range[1][0] and move_range[0][1] <= pos[1] < move_range[1][1]) def move_block(self, new_location, x, y): obj_loc = (new_location[0] + x, new_location[1] + y) if self.is_valid_pos(obj_loc) and self.valid_block_move( obj_loc, self.objects[new_location].move_range): self.remove(self.objects[new_location]) obj = MovingBlock( self.objects[new_location].size, self.grid.grid_to_pixel(obj_loc), self.objects[new_location].move_range, self.objects[new_location].color, self.objects[new_location].icon_source, self.objects[new_location].final_position, ) del self.objects[new_location] self.add(PushMatrix()) self.add(Translate(*self.grid.pos)) self.add(obj) self.add(PopMatrix()) self.objects[obj_loc] = obj self.blocks_placed += self.objects[obj_loc].on_block_placement( obj_loc) return True else: return False def on_player_input(self, button): if button in [Button.UP, Button.DOWN, Button.LEFT, Button.RIGHT]: move_possible = True x, y = button.value cur_location = self.character.grid_pos new_location = (cur_location[0] + x, cur_location[1] + y) self.character.change_direction(button.value) if new_location in self.objects: if self.objects[new_location].moveable: move_possible = self.move_block(new_location, x, y) if move_possible: self.character.move_player(new_location) if self.character.grid_pos in self.objects: if isinstance(self.objects[self.character.grid_pos], DoorTile): if not isinstance( self.objects[self.character.grid_pos].other_room, Puzzle): # instantiate class when we enter the door self.objects[ self.character.grid_pos].other_room = self.objects[ self.character.grid_pos].other_room( self, self.level + 1) return self.objects[self.character.grid_pos].other_room if self.blocks_placed == 4: self.on_game_over() self.mixer.add(self.wave_file_gen) def create_treasure_popup(self, win_size): self.game_over_window_color = Color(rgba=(1, 1, 1, 1)) self.game_over_window = CRectangle( cpos=(win_size[0] // 2, win_size[1] // 2), csize=(win_size[0] // 2, win_size[1] // 5), ) self.game_over_text_color = Color(rgba=(0, 0, 0, 1)) self.game_over_text = CLabelRect( (win_size[0] // 2, win_size[1] // 2), "You unlocked the pharaoh's treasure!\nYou WIN!", 40) self.treasure = CRectangle(cpos=(win_size[0] // 2, win_size[1] // 4), csize=(win_size[0] // 4, win_size[1] // 4), source='./data/treasure.png') def on_game_over(self): self.game_over = True self.add(self.game_over_window_color) self.add(self.game_over_window) self.add(self.game_over_text_color) self.add(self.game_over_text) self.add(self.game_over_window_color) self.add(self.treasure) def on_update(self): self.audio.on_update() def on_layout(self, win_size): self.remove(self.character) self.remove(self.grid) self.grid.on_layout(win_size) for pos, obj in self.objects.items(): self.remove(obj) self.add(self.grid) self.place_objects() self.character.on_layout(win_size) self.add(self.character) self.create_treasure_popup(win_size) if self.game_over: self.remove(self.game_over_window_color) self.remove(self.game_over_window) self.remove(self.game_over_text_color) self.remove(self.game_over_text) self.remove(self.treasure) self.on_game_over()
class LevelOptions(InstructionGroup): def __init__(self, level, goal_music_seq, duration, edit_goal_play_status=None): super(LevelOptions, self).__init__() self.level = level # level number self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.options_bar = Rectangle(pos=(0, 0)) self.home_button = Rectangle( texture=CoreImage('images/home.png').texture) self.play_button = Rectangle( texture=CoreImage('images/play.png').texture) self.reset_button = Rectangle( texture=CoreImage('images/reset.png').texture) self.check_button = Rectangle( texture=CoreImage('images/check.png').texture) self.on_layout((Window.width, Window.height)) self.add(colors['grey']) self.add(self.options_bar) self.add(colors['green']) self.add(self.home_button) self.add(self.play_button) self.add(self.reset_button) self.add(self.check_button) self.is_playing = False self.start_time = None self.duration = 0 self.goal_music_seq = None self.duration_circle = Line() self.add(self.duration_circle) # true iff you recently lost or won the game self.win_or_lose = False self.win_gen = WaveGenerator(WaveFile("./data/win_sound.wav")) self.lose_gen = WaveGenerator(WaveFile("./data/lose_sound.wav")) self.goal_music_seq = goal_music_seq self.duration = duration self.button_press_time = None self.edit_goal_play_status = edit_goal_play_status def on_layout(self, winsize): size_dim = min(Window.width / 6, Window.height / 6) self.options_bar.size = (Window.width, size_dim + Window.height / 25) self.home_button.pos = (Window.width - 5 * size_dim, Window.height / 50) self.home_button.size = (size_dim, size_dim) self.play_button.pos = (Window.width - 3.75 * size_dim, Window.height / 50) self.play_button.size = (size_dim, size_dim) self.reset_button.pos = (Window.width - 2.5 * size_dim, Window.height / 50) self.reset_button.size = (size_dim, size_dim) self.check_button.pos = (Window.width - 1.25 * size_dim, Window.height / 50) self.check_button.size = (size_dim, size_dim) def on_touch_up(self, switch_screen, gear_music_seq, level_complete, win_particle, you_win_label, lose_particle, you_lose_label, reset_fn, touch): self.switch_screen = switch_screen def reset(): reset_fn() win_particle.stop() you_win_label.text = ' ' lose_particle.stop() you_lose_label.text = ' ' if self.win_gen in self.mixer.generators: self.mixer.remove(self.win_gen) elif self.lose_gen in self.mixer.generators: self.mixer.remove(self.lose_gen) # When you win/you lose is displayed, clicking anywhere on the # screen should bring you back to the home screen if self.win_or_lose: reset() switch_screen('level_select') self.win_or_lose = False elif self.is_clicked(self.home_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) self.button_press_time = time.time() # go back to level select screen reset() elif self.is_clicked(self.play_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) if self.edit_goal_play_status: self.edit_goal_play_status('started') # play/stop goal music self.is_playing = not self.is_playing if self.is_playing: self.goal_music_seq.start() self.start_time = time.time() self.play_button.texture = CoreImage('images/stop.png').texture else: self.goal_music_seq.stop() self.start_time = None self.play_button.texture = CoreImage('images/play.png').texture elif self.is_clicked(self.reset_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) # reset gear positions reset() elif self.is_clicked(self.check_button, touch): # play button press sound self.mixer.add(WaveGenerator(WaveFile("./data/button_press.wav"))) # if gear placement is correct self.win_or_lose = True self.goal_music_seq.stop() if gear_music_seq: gear_music_seq.stop() if level_complete: # show particle effect, you win label, and play sound win_particle.start() you_win_label.text = 'YOU WIN' edit_progress_file(self.level, 'g') # generate and play winning music self.win_gen = WaveGenerator(WaveFile("./data/win_sound.wav")) self.mixer.add(self.win_gen) else: lose_particle.start() you_lose_label.text = 'YOU LOSE' edit_progress_file(self.level, 'r') self.lose_gen = WaveGenerator( WaveFile("./data/lose_sound.wav")) self.mixer.add(self.lose_gen) def on_update(self): self.audio.on_update() if self.button_press_time and time.time( ) - self.button_press_time > 0.13: self.button_press_time = None self.switch_screen('level_select') # if goal sound played completely, switch back to play icon if self.start_time and time.time() - self.start_time >= self.duration: self.goal_music_seq.stop() self.is_playing = False self.play_button.texture = CoreImage('images/play.png').texture self.duration_circle.width = 0.01 if self.edit_goal_play_status: self.edit_goal_play_status('finished') elif self.start_time and self.is_playing: size_dim = min(Window.width / 6, Window.height / 6) self.duration_circle.width = 10 self.duration_circle.circle = ( Window.width - 3.25 * size_dim, Window.height / 50 + size_dim / 2, size_dim / 2, 0, (self.start_time and time.time() - self.start_time) / self.duration * 360) else: self.duration_circle.width = 0.01 def is_clicked(self, button, touch): return button.pos[0] < touch.x < button.pos[0] + button.size[0] \ and button.pos[1] < touch.y < button.pos[1] + button.size[1]
class LevelEasyMediumScreen(Screen): def __init__(self, level, notes, goal_values, gear_values, **kwargs): super(LevelEasyMediumScreen, self).__init__(**kwargs) # set up notes for the level self.notes = notes # set up gear values for the levels self.goal_values = goal_values # set up gear values for the levels self.gear_values = gear_values self.level = level # only turn on tutorial for level 1 if self.level == 1: self.use_tutorial = True self.tutorial_screen = 'A' self.goal_play_status = None self.gear_play_status = None self.size_dim = min(Window.width / 6, Window.height / 6) self.tutorial_full_overlay = CRectangle(cpos=(Window.width / 2, Window.height / 2), csize=(Window.width, Window.height)) self.tutorial_options_overlay = Rectangle( pos=(0, 0), size=(Window.width, self.size_dim + Window.height / 25)) self.tutorial_musicbox_overlay = Rectangle( pos=(Window.width // 2, self.size_dim + Window.height / 25), size=(Window.width / 2, Window.height - (self.size_dim + Window.height / 25))) self.tutorial_gearbox_overlay = Rectangle( pos=(0, self.size_dim + Window.height / 25), size=(Window.width / 2, Window.height - (self.size_dim + Window.height / 25))) self.skip_image = CoreImage('images/skip_tutorial.png') self.tutorial_skip_button = Rectangle( pos=(0.98 * Window.width - (self.skip_image.width * self.size_dim / 300), 0.98 * Window.height - self.skip_image.height * self.size_dim / 300), size=(self.skip_image.width * self.size_dim / 300, self.skip_image.height * self.size_dim / 300), texture=self.skip_image.texture) else: self.use_tutorial = False ############################################ ### GOAL MUSIC ### ############################################ self.goal_audio = Audio(2) self.goal_synth = Synth('./data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.goal_tempo_map = SimpleTempoMap(120) self.goal_sched = AudioScheduler(self.goal_tempo_map) # connect scheduler into audio system self.goal_audio.set_generator(self.goal_sched) self.goal_sched.set_generator(self.goal_synth) # generate goal music self.goal_music = MusicPlayer(notes=self.notes, sched=self.goal_sched, synth=self.goal_synth, channel=1, tempo_map=self.goal_tempo_map) self.goal_music.update_tempo(self.goal_values[0]) self.goal_music.update_instrument(self.goal_values[1]) self.goal_music.update_pitch(self.goal_values[2]) self.goal_music.update_volume(self.goal_values[3]) self.goal_music_seq = self.goal_music.generate() ############################################ ### GEAR MUSIC ### ############################################ self.gear_audio = Audio(2) self.gear_synth = Synth('./data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.gear_tempo_map = SimpleTempoMap(120) self.gear_sched = AudioScheduler(self.gear_tempo_map) # connect scheduler into audio system self.gear_audio.set_generator(self.gear_sched) self.gear_sched.set_generator(self.gear_synth) # generate gear music self.gear_music = MusicPlayer(notes=self.notes, sched=self.gear_sched, synth=self.gear_synth, channel=1, tempo_map=self.gear_tempo_map) self.gear_music_seq = None ############################################ ### BACKGROUND UI COMPONENTS ### ############################################ self.gear_area = GearArea() self.canvas.add(self.gear_area) self.music_box_area = MusicBoxArea() self.canvas.add(self.music_box_area) self.options = LevelOptions( level=level, goal_music_seq=self.goal_music_seq, duration=self.goal_music.duration, edit_goal_play_status=self.edit_goal_play_status) self.canvas.add(self.options) self.label = Label(text=kwargs['name'], font_name='./fonts/PassionOne-Regular', color=(.165, .718, .792, 1)) self.add_widget(self.label) ########################################### ### GEAR LABELS ### ########################################### self.tempo_label = Label(text='Tempo (bpm)', font_name='./fonts/PassionOne-Regular', color=(0.7254901960784313, 0.5529411764705883, 0.8196078431372549, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (0.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.instrument_label = Label( text='Instrument', font_name='./fonts/PassionOne-Regular', color=(0.996078431372549, 0.8431372549019608, 0.4, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (1.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.pitch_label = Label(text='Pitch (semitones)', font_name='./fonts/PassionOne-Regular', color=(1.0, 0.6509803921568628, 0.09019607843137255, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (2.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.volume_label = Label( text='Volume', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (3.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.add_widget(self.volume_label) self.add_widget(self.pitch_label) self.add_widget(self.instrument_label) self.add_widget(self.tempo_label) ########################################### ### GEAR CONSTRUCTION ### ########################################### self.gears = [] self.gear_centers = [] self.gears_group = AnimGroup() self.canvas.add(self.gears_group) ########################################### ### GEARS ### ########################################### self.gear_storage_locations = [] self.gear_music_locations = [] self.gear_labels = [] self.set_up_gears() ########################################### ### PARTICLE EFFECT ### ########################################### self.win_ps = ParticleSystem('particles/star_particle.pex') self.win_ps.emitter_x = Window.width / 2 self.win_ps.emitter_y = Window.height / 2 self.add_widget(self.win_ps) self.you_win_label = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.5843137254901961, 0.796078431372549, 0.37254901960784315, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 10) + 'sp') self.add_widget(self.you_win_label) self.lose_ps = ParticleSystem('particles/lose_particle.pex') self.lose_ps.emitter_x = Window.width / 2 self.lose_ps.emitter_y = Window.height / 2 self.add_widget(self.lose_ps) self.you_lose_label = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 10) + 'sp') self.add_widget(self.you_lose_label) ########################################### ### ERROR MESSAGE ### ########################################### self.error_msg = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 20) + 'sp') self.add_widget(self.error_msg) # ########################################### # ### ADD TUTORIAL OVERLAYS ### # ########################################### if self.use_tutorial: self.canvas.add(Color(rgba=(0, 0, 0, 0.85))) self.canvas.add(self.tutorial_full_overlay) self.tutorial_label = Label( markup=True, text= "[font=./fonts/lato-bold]Welcome to the\n[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/PassionOne-Regular]Play It By Gear Tutorial[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/lato-bold]\n\nThe goal of this game is to make the \n goal song match the song you create by \nplacing the correct gears in a music box \n\n[/font] [font=./fonts/lato-light] (click to see the next \nstep of the tutorial)[/font]", color=(86 / 255, 189 / 255, 205 / 255, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 40) + 'sp', halign='center') self.add_widget(self.tutorial_label) self.canvas.add(self.tutorial_skip_button) self.on_layout((Window.width, Window.height)) def clear_overlays(self): if self.tutorial_full_overlay in self.canvas.children: self.canvas.remove(self.tutorial_full_overlay) if self.tutorial_options_overlay in self.canvas.children: self.canvas.remove(self.tutorial_options_overlay) if self.tutorial_gearbox_overlay in self.canvas.children: self.canvas.remove(self.tutorial_gearbox_overlay) if self.tutorial_musicbox_overlay in self.canvas.children: self.canvas.remove(self.tutorial_musicbox_overlay) while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def activate_overlays(self, overlay_names): self.clear_overlays() self.canvas.add(Color(rgba=(0, 0, 0, 0.85))) if 'full' in overlay_names: self.canvas.add(self.tutorial_full_overlay) if 'options' in overlay_names: self.canvas.add(self.tutorial_options_overlay) if 'gearbox' in overlay_names: self.canvas.add(self.tutorial_gearbox_overlay) if 'musicbox' in overlay_names: self.canvas.add(self.tutorial_musicbox_overlay) def get_scaled_x_y(self, winsize, x, y): width, height = winsize # scaled_x = width/8 * (x+1) scaled_x = width / (len(self.gear_values) // 4 * 2) * (x + 0.5) scaled_y = height / 5.25 * (y + 0.5) + self.gear_area.position[1] return scaled_x, scaled_y def set_up_gears(self): self.gears = [] self.gears_group.remove_all() center_gear_location = (Window.width / 6 * 4.5, Window.height / 4 * 2.5) center_gear_size = min(Window.width / 10, Window.height / 10) self.center_gear = Gear(None, None, center_gear_size, 10, 'center', 0, center_gear_location, center_gear_location, 1, colors['dark_grey']) self.canvas.add(self.center_gear.color) self.gears_group.add(self.center_gear) self.center_gear_center = GearCenter(None, None, center_gear_location, center_gear_location, 'center', center_gear_size / 2, colors['dark_grey']) self.canvas.add(colors['dark_grey']) self.canvas.add(self.center_gear_center) self.play_center_gear = False self.music_gears = [] tempo_location = (center_gear_location[0], center_gear_location[1] + center_gear_size + center_gear_size / 5) instrument_location = (center_gear_location[0], center_gear_location[1] - center_gear_size - center_gear_size / 5) pitch_location = (center_gear_location[0] + center_gear_size + center_gear_size / 5, center_gear_location[1]) volume_location = (center_gear_location[0] - center_gear_size - center_gear_size / 5, center_gear_location[1]) self.music_box_gear_locations = [ tempo_location, instrument_location, pitch_location, volume_location ] counter = 0 label_font_size = min(Window.width // 80, Window.height // 80) for y in range(0, 4): for x in range(len(self.gear_values) // 4): gear_type = gear_type_map[y] size = min(Window.width / 10, Window.height / 10) music_pos = self.music_box_gear_locations[y] scaled_x, scaled_y = self.get_scaled_x_y( (Window.width, Window.height), x, y) gear = Gear(x, y, size, 8, gear_type, self.gear_values[counter], (scaled_x, scaled_y), music_pos, 0, colors['dark_grey']) self.gears.append(gear) self.canvas.add(gear.color) self.gears_group.add(gear) gear_center = GearCenter(x, y, (scaled_x, scaled_y), music_pos, gear_type, size / 2, colors['dark_grey']) self.gear_centers.append(gear_center) self.canvas.add(gear_center) ## white dots for storage purposes gear_loc = GearLocation((scaled_x, scaled_y), size / 2, x, y, gear_type) self.gear_storage_locations.append(gear_loc) self.canvas.add(gear_loc) text = str(self.gear_values[counter]) font_name = './fonts/PassionOne-Regular' if y == 3: # get volume as percent text = str(100 * self.gear_values[counter] // 127) + '%' if y == 1: # get icon for instrument font_name = './fonts/music-instruments' text = instruments[self.gear_values[counter]] label = Label(text=text, font_name=font_name, color=(0, 0, 0, 1), center_x=scaled_x, center_y=scaled_y, font_size=str(label_font_size) + 'sp') self.gear_labels.append(label) self.add_widget(label) counter += 1 for indx, loc in enumerate(self.music_box_gear_locations): gear_type = gear_type_map[indx % 4] gear_loc = GearLocation(loc, center_gear_size / 2, None, None, gear_type) self.gear_music_locations.append(gear_loc) self.canvas.add(gear_loc) def edit_goal_play_status(self, value): if self.use_tutorial: if self.goal_play_status == None and value == 'started': self.goal_play_status = 'started' elif self.goal_play_status == 'started' and value == 'finished': self.goal_play_status = 'finished' def _can_add_gear(self, new_gear): for gear in self.music_gears: if gear.type == new_gear.type: return False return True def _check_music_gears(self): all_types = ['volume', 'pitch', 'tempo', 'instrument'] for gear in self.music_gears: if gear.type in all_types: all_types.remove(gear.type) return len(all_types) == 0 def update_center_gear_on_layout(self, winsize): width, height = winsize center_gear_location = (width / 6 * 4.5, height / 4 * 2.5) center_gear_size = min(Window.width / 10, Window.height / 10) self.center_gear_center.update_storage_pos(center_gear_location) self.center_gear_center.update_music_pos(center_gear_location) self.center_gear.update_storage_pos(center_gear_location) self.center_gear.update_music_pos(center_gear_location) self.center_gear.on_layout(center_gear_location, center_gear_size) self.center_gear_center.on_layout(center_gear_location, center_gear_size / 2) tempo_location = (center_gear_location[0], center_gear_location[1] + center_gear_size + center_gear_size / 5) instrument_location = (center_gear_location[0], center_gear_location[1] - center_gear_size - center_gear_size / 5) pitch_location = (center_gear_location[0] + center_gear_size + center_gear_size / 5, center_gear_location[1]) volume_location = (center_gear_location[0] - center_gear_size - center_gear_size / 5, center_gear_location[1]) self.music_box_gear_locations = [ tempo_location, instrument_location, pitch_location, volume_location ] for indx, loc in enumerate(self.gear_music_locations): loc.on_layout(self.music_box_gear_locations[indx], center_gear_size / 2) def on_enter(self): if not self.use_tutorial and self.level == 1: while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def on_layout(self, winsize): mapped_dic = {'tempo': 0, 'instrument': 1, 'pitch': 2, 'volume': 3} self.update_center_gear_on_layout(winsize) self.size_dim = min(Window.width / 6, Window.height / 6) size = min(Window.width / 10, Window.height / 10) label_font_size = min(Window.width // 80, Window.height // 80) for loc in self.gear_storage_locations: scaled_x, scaled_y = self.get_scaled_x_y(winsize, loc.x, loc.y) loc.on_layout((scaled_x, scaled_y), size / 2) for indx, gear in enumerate(self.gears): scaled_x, scaled_y = self.get_scaled_x_y(winsize, gear.x, gear.y) gear.update_storage_pos((scaled_x, scaled_y)) gear.update_music_pos( self.music_box_gear_locations[mapped_dic[gear.type]]) gear.on_layout((scaled_x, scaled_y), size) self.gear_labels[indx].center_x = scaled_x self.gear_labels[indx].center_y = scaled_y self.gear_labels[indx].font_size = str(label_font_size) + 'sp' for center in self.gear_centers: scaled_x, scaled_y = self.get_scaled_x_y(winsize, center.x, center.y) center.update_storage_pos((scaled_x, scaled_y)) center.update_music_pos( self.music_box_gear_locations[mapped_dic[center.type]]) center.on_layout((scaled_x, scaled_y), size / 2) # update level label self.label.center_x = self.size_dim * 1.5 self.label.center_y = self.size_dim * 3 / 5 self.label.font_size = str(Window.width // 20) + 'sp' # update you win label self.you_win_label.center_x = (Window.width / 2) self.you_win_label.center_y = (Window.height / 2) self.you_win_label.font_size = str(Window.width // 10) + 'sp' self.tempo_label.center_x = (Window.width / 4) self.tempo_label.center_y = (Window.height / 5.25 * (0.5 + 0.5) + self.gear_area.position[1]) self.tempo_label.font_size = str(Window.width // 50) + 'sp' self.instrument_label.center_x = (Window.width / 4) self.instrument_label.center_y = (Window.height / 5.25 * (1.5 + 0.5) + self.gear_area.position[1]) self.instrument_label.font_size = str(Window.width // 50) + 'sp' self.pitch_label.center_x = (Window.width / 4) self.pitch_label.center_y = (Window.height / 5.25 * (2.5 + 0.5) + self.gear_area.position[1]) self.pitch_label.font_size = str(Window.width // 50) + 'sp' self.volume_label.center_x = (Window.width / 4) self.volume_label.center_y = (Window.height / 5.25 * (3.5 + 0.5) + self.gear_area.position[1]) self.volume_label.font_size = str(Window.width // 50) + 'sp' # update child components self.gear_area.on_layout((Window.width, Window.height)) self.music_box_area.on_layout((Window.width, Window.height)) self.options.on_layout((Window.width, Window.height)) # update particle effect and win/lose labels self.win_ps.emitter_x = Window.width / 2 self.win_ps.emitter_y = Window.height / 2 self.you_win_label.center_x = Window.width / 2 self.you_win_label.center_y = Window.height / 2 self.you_win_label.font_size = str(Window.width // 10) + 'sp' self.lose_ps.emitter_x = Window.width / 2 self.lose_ps.emitter_y = Window.height / 2 self.you_lose_label.center_x = Window.width / 2 self.you_lose_label.center_y = Window.height / 2 self.you_lose_label.font_size = str(Window.width // 10) + 'sp' # update error message location self.error_msg.center_x = Window.width / 2 self.error_msg.center_y = Window.height / 2 self.error_msg.font_size = str(Window.width // 20) + 'sp' # update tutorial overlays, label, and skip button if self.use_tutorial: self.update_tutorial_screen(self.tutorial_screen) self.tutorial_full_overlay.cpos = (Window.width / 2, Window.height / 2) self.tutorial_full_overlay.csize = (Window.width, Window.height) self.tutorial_options_overlay.size = (Window.width, self.size_dim + Window.height / 25) self.tutorial_musicbox_overlay.pos = (Window.width // 2, self.size_dim + Window.height / 25) self.tutorial_musicbox_overlay.size = ( Window.width / 2, Window.height - (self.size_dim + Window.height / 25)) self.tutorial_gearbox_overlay.pos = (0, self.size_dim + Window.height / 25) self.tutorial_gearbox_overlay.size = ( Window.width / 2, Window.height - (self.size_dim + Window.height / 25)) self.tutorial_skip_button.pos = ( 0.98 * Window.width - (self.skip_image.width * self.size_dim / 300), 0.98 * Window.height - self.skip_image.height * self.size_dim / 300) self.tutorial_skip_button.size = (self.skip_image.width * self.size_dim / 300, self.skip_image.height * self.size_dim / 300) def reset(self): for gear in self.gears: # reset gear position gear.reset() # stop gear from rotating gear.stop() # stop center gear from rotating self.center_gear.stop() # stop music self.goal_music_seq.stop() if self.gear_music_seq: self.gear_music_seq.stop() # end tutorial if self.use_tutorial: self.tutorial_label.text = '' self.use_tutorial = False self.clear_overlays() while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def skip_tutorial_pressed(self, touch): if self.use_tutorial: if 0.98 * Window.width - ( self.skip_image.width * self.size_dim / 300 ) < touch.pos[ 0] < 0.98 * Window.width and 0.98 * Window.height - self.skip_image.height * self.size_dim / 300 < touch.pos[ 1] < 0.98 * Window.height: return True return False def on_touch_up(self, touch): # if click is on one of the lower menu buttons, perform the appropriate action self.options.on_touch_up(self.switch_to, self.gear_music_seq, self.check_level_complete(), self.win_ps, self.you_win_label, self.lose_ps, self.you_lose_label, self.reset, touch) for index, gear in enumerate(self.gears): # response is true if you click the current gear response = gear.on_touch_up(touch.pos, self.gear_area.max_x, self._can_add_gear) self.gear_centers[index].on_touch_up(touch.pos, self.gear_area.max_x, self._can_add_gear) if response: if gear not in self.music_gears: self.music_gears.append(gear) # update the gear music based on the gear that is selected function = 'self.gear_music.update_' + gear.type + '(' + str( gear.value) + ')' eval(function) else: if gear in self.music_gears: self.music_gears.remove(gear) self.center_gear.on_touch_up(touch.pos, self.gear_area.max_x, self._can_add_gear) if self.use_tutorial: # if skip button pressed, quit out of tutorial mode if self.skip_tutorial_pressed(touch): self.use_tutorial = False self.remove_widget(self.tutorial_label) self.clear_overlays() while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) elif self.tutorial_screen == 'A': # show screen B (musicbox and gearbox covered) self.tutorial_screen = 'B' self.update_tutorial_screen('B') elif self.tutorial_screen == 'B': # show screen C (musicbox and options covered) self.tutorial_screen = 'C' self.update_tutorial_screen('C') elif self.tutorial_screen == 'C': # show screen D (gearbox and options covered) self.tutorial_screen = 'D' self.update_tutorial_screen('D') elif self.tutorial_screen == 'D': # show screen E (options covered) self.tutorial_screen = 'E' self.update_tutorial_screen('E') elif self.tutorial_screen == 'E' and self._check_music_gears(): # if all gears have been placed, show screen F (gearbox covered) self.tutorial_screen = 'F' self.update_tutorial_screen('F') elif self.tutorial_screen == 'F' and self.gear_play_status == 'finished' and self.goal_play_status == 'finished': # if both tunes have been played show screen G (gearbox and musicbox covered) self.tutorial_screen = 'G' self.update_tutorial_screen('G') elif self.tutorial_screen == 'G': # end tutorial self.use_tutorial = False self.remove_widget(self.tutorial_label) self.clear_overlays() while self.tutorial_skip_button in self.canvas.children: self.canvas.remove(self.tutorial_skip_button) def update_tutorial_screen(self, screen): if not self.use_tutorial: return self.remove_widget(self.tutorial_label) if self.tutorial_screen == 'A': self.activate_overlays(['full']) self.tutorial_label.center_x = Window.width / 2 self.tutorial_label.center_y = Window.height / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Welcome to the\n[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/PassionOne-Regular]Play It By Gear Tutorial[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/lato-bold]\n\nThe goal of this game is to make the \n goal song match the song you create by \nplacing the correct gears in a music box \n\n[/font] [font=./fonts/lato-light] (click to see the next \nstep of the tutorial)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 40) + 'sp' if self.tutorial_screen == 'B': self.activate_overlays(['musicbox', 'gearbox']) self.tutorial_label.center_x = 1 / 2 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]\nAt the bottom of the screen is the menu\nbar which contains some helpful buttons\n\nthe [/font] [font=./fonts/options-icons]^[/font] [font=./fonts/lato-bold] button brings\nyou back to the level select menu\n\nthe [/font] [font=./fonts/options-icons]`[/font] [font=./fonts/lato-bold] button resets the level\n\n[/font] [font=./fonts/lato-light](click to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 50) + 'sp' elif self.tutorial_screen == 'C': self.activate_overlays(['musicbox', 'options']) self.tutorial_label.center_x = 3 / 4 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]The left side of the screen\nhas all the gears you can choose\nfrom in order to make the\nmusic box sound correct\n\n[/font] [font=./fonts/lato-light](click to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'D': self.activate_overlays(['gearbox', 'options']) self.tutorial_label.center_x = 1 / 4 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]The right side of the screen\nis the music box. Gears in\nthe music box modify the song.\n\nYou need one gear of each\ntype/color in the music box in\norder for the song to play. \n\n[/font] [font=./fonts/lato-light](click to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'E': self.activate_overlays(['options']) self.tutorial_label.center_x = Window.width / 2 self.tutorial_label.center_y = (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Now drag one gear of each type/color into the music box\n[/font] [font=./fonts/lato-light](when there are 4 gears in the music box, the tutorial will continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'F': self.activate_overlays(['gearbox']) self.tutorial_label.center_x = 1 / 4 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Play the goal sound by pressing\nthe [/font] [font=./fonts/options-icons]_[/font] [font=./fonts/lato-bold] button, then press\nthe [/font] [font=./fonts/options-icons]~[/font] [font=./fonts/lato-bold] in the center gear to\nplay the song you created\nwith the gears\n\n[/font] [font=./fonts/lato-light](after you play both songs,\nclick again to continue)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 60) + 'sp' elif self.tutorial_screen == 'G': self.activate_overlays(['musicbox', 'gearbox']) self.tutorial_label.center_x = 1 / 2 * Window.width self.tutorial_label.center_y = Window.height / 2 + (min( Window.width / 6, Window.height / 6) + Window.height / 25) / 2 self.tutorial_label.text = "[font=./fonts/lato-bold]Did the two songs sound the same?\n\nIf yes, you can press the [/font] [font=./fonts/options-icons]{[/font] [font=./fonts/lato-bold] button\n to see if you're correct\n\n If no, you can switch the gears in the music box\nuntil you think both songs sound the same\n\n[/font] [font=./fonts/lato-light](click to exit the tutorial)[/font]" self.tutorial_label.font_size = font_size = str( Window.width // 55) + 'sp' self.add_widget(self.tutorial_label) self.canvas.add(self.tutorial_skip_button) def on_touch_down(self, touch): other_gears = False for index, gear in enumerate(self.gears): cur_gear = gear.on_touch_down(touch.pos) other_gears = other_gears or cur_gear self.gear_centers[index].on_touch_down(touch.pos) if other_gears: if self.gear_music_seq: for gear in self.music_gears: gear.stop() self.center_gear.stop() self.gear_music_seq.stop() self.gear_music_seq = None else: response = self.center_gear.on_touch_down(touch.pos) if response: if self._check_music_gears(): for gear in self.music_gears: gear.toggle_rotate() is_rotating = self.center_gear.toggle_rotate() if is_rotating: self.gear_music_seq = self.gear_music.generate() self.gear_music_seq.start() if self.use_tutorial and self.gear_play_status == None: self.gear_play_status = 'started' else: if self.gear_music_seq: self.gear_music_seq.stop() self.gear_music_seq = None else: if not self.use_tutorial: self.error_msg.text = 'Place all 4 gears' else: self.error_msg.text = ' ' return self.error_msg.text = ' ' def on_touch_move(self, touch): for index, gear in enumerate(self.gears): gear.on_touch_move(touch.pos) self.gear_centers[index].on_touch_move(touch.pos) def on_update(self): self.goal_audio.on_update() self.gear_audio.on_update() self.options.on_update() for gear in self.gears: gear.on_update(1) self.center_gear.on_update(1) if self.gear_music_seq and not self.gear_music_seq.playing: for gear in self.music_gears: gear.stop() self.center_gear.stop() self.gear_music_seq = None if self.use_tutorial and self.gear_play_status == 'started': self.gear_play_status = 'finished' def check_level_complete(self): return self.goal_music.is_equal(self.gear_music)
def __init__(self): super(MainWidget3, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(104) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) percNotes = [(480,35), (360,42), (120,35), (480,35), (480,42)] self.base1Notes = [(240,43), (240,43), (240,43), (120,47), (240,41), (240,41), (360,41), (120,40), (360,41), (240,41), (240,41), (120,40), (120,36), (480,-1), (120,40), (240,41), (120,43)] self.base2Notes = [(120,-1), (120,45), (240,43), (120,-1), (240,43), (120,40), (480,43), (120,-1), (120,45), (120,45), (120,48), (240,-1), (240,41), (120,-1), (240,41), (120,40), (480,41), (120,-1), (120,45), (120,45), (120,48), (240,-1), (240,45), (120,-1), (240,45), (120,45), (480,45), (240,43), (120,-1), (120,45), (240,-1), (240,45), (120,-1), (240,45), (120,45), (480,45), (120,-1), (120,45), (120,45), (120,48)] self.baseNotes = self.base2Notes #[40, 41, 43, 45 48,] #changes / pitch sutff self.changes = [ (1920, [72, 74, 76, 79, 81, 84]), (1920, [69, 72, 74, 81]), (3840, [69, 72, 74, 76, 79, 81, 84])] self.changesIndex = 0 self.curChanges = [] self.selectSize = 2 self.lastPitchIndex = None self.lastTouch = None #Note length stuff self.noteLengths = [480, 240, 120] self.articulation = 1 self.lastPulseIndex = 0 #Declare the players self.perc = NoteSequencer(self.sched, self.synth, 1, (128,0), percNotes) self.base1 = NoteSequencer(self.sched, self.synth, 2, (0,33), self.base1Notes, callback = self.graphic_callback) self.base2 = NoteSequencer(self.sched, self.synth, 2, (0,33), self.base2Notes, callback = self.graphic_callback) self.lead = Arpeggiator(self.sched, self.synth, channel = 3, program = (0,65), callback = self.graphic_callback) self.lead.set_direction('updown') #Start the non-interactive stuff now = self.sched.get_tick() next_beat = quantize_tick_up(now, 480) self.perc.toggle() self.base2.toggle() self.sched.post_at_tick(self._updateChanges, next_beat) #Update changes as music starts self.sched.post_at_tick(self._spawnCrossBar, next_beat) # and text to display our status #self.label = topleft_label() #self.add_widget(self.label) #Graphics stuff self.objects = AnimGroup() self.canvas.add(self.objects) #self.allNotes = [40, 41, 43, 45, 48, 900, 69, 72, 74, 76, 79, 81, 84] self.allNotes = [36, 40, 41, 43, 45, 47, 48, 900, 69, 72, 74, 76, 79, 81, 84]
class MainWidget(BaseWidget): def __init__(self): super(MainWidget, self).__init__() self.writer = AudioWriter('song') self.audio = Audio(2, self.writer.add_audio) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(95*2) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) # variables to store options self.transposition = 0 self.style = None self.melody = None self.chords = None self.chord_option = None self.perc = None self.perc_option = None # variables to store screen options self.style_selection = StyleSelection(self.update_style_screen) # screen index 0 self.key_selection = KeySelection(self.update_key_screen) # screen index 1 self.chord_selection = None # screen index 2 self.perc_selection = None # screen index 3 self.melody_selection = None # screen index 4 self.active_screen = self.style_selection self.screen_index = 0 self.add_widget(self.active_screen) def update_style_screen(self, option): self.style = option Window.clearcolor = stylcol[self.style][0] self.change_screens(self.key_selection) self.screen_index = 1 def update_key_screen(self, instance): self.transposition = key_to_transpose[instance] # can now set up melody, chord, percussion settings self.melody = transpose_melody(self.style, 1, self.transposition) self.chords = transpose_instrument(self.style, "chords", self.transposition) self.chord_selection = ChordSelection(self.update_chord_screen, self.sched, self.synth, self.chords, stylcol[self.style][1]) self.perc = transpose_instrument(self.style, "percussion", 0) self.perc_selection = PercSelection(self.update_perc_screen, self.sched, self.synth, self.perc, stylcol[self.style][1]) self.change_screens(self.chord_selection) self.screen_index = 2 def update_chord_screen(self, option): self.chord_option = option self.change_screens(self.perc_selection) self.screen_index = 3 def update_perc_screen(self, option): self.perc_option = option # can now update our composition screen self.melody_selection = MelodySelection( self.synth, self.sched, self.chords[self.chord_option], self.perc[self.perc_option], self.melody, self.change_key_button, self.change_chord_button, self.change_perc_button, self.writer ) self.change_screens(self.melody_selection) self.screen_index = 4 def change_key_button(self, instance): self.transposition = key_to_transpose[instance] self.melody = transpose_melody(self.style, 1, self.transposition) self.chords = transpose_instrument(self.style, "chords", self.transposition) self.melody_selection.stop() self.remove_widget(self.melody_selection) self.melody_selection = MelodySelection( self.synth, self.sched, self.chords[self.chord_option], self.perc[self.perc_option], self.melody, self.change_key_button, self.change_chord_button, self.change_perc_button, self.writer ) self.add_widget(self.melody_selection) self.active_screen = self.melody_selection def change_chord_button(self, instance): if self.chord_option == 1: option = 2 else: option = 1 self.chord_option = option self.melody_selection.change_chords(self.chords[self.chord_option]) def change_perc_button(self, instance): if self.perc_option == 1: option = 2 else: option = 1 self.perc_option = option self.melody_selection.change_perc(self.perc[self.perc_option]) def change_screens(self, screen): self.remove_widget(self.active_screen) self.active_screen = screen self.add_widget(self.active_screen) def on_touch_down(self, touch): self.active_screen.on_touch_down(touch) def on_touch_move(self, touch): self.active_screen.on_touch_move(touch) def on_key_down(self, keycode, modifiers): self.active_screen.on_key_down(keycode, modifiers) if keycode[1] == 'r': self.writer.toggle() def on_layout(self, winsize): if self.style_selection != None: self.style_selection.on_layout(winsize) if self.key_selection != None: self.key_selection.on_layout(winsize) if self.chord_selection != None: self.chord_selection.on_layout(winsize) if self.perc_selection != None: self.perc_selection.on_layout(winsize) if self.melody_selection != None: self.melody_selection.on_layout(winsize) def on_update(self): self.audio.on_update() self.active_screen.on_update()
class MainWidget3(BaseWidget) : def __init__(self): super(MainWidget3, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(104) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.audio.set_generator(self.sched) self.sched.set_generator(self.synth) # create the metronome: self.metro = Metronome(self.sched, self.synth) percNotes = [(480,35), (360,42), (120,35), (480,35), (480,42)] self.base1Notes = [(240,43), (240,43), (240,43), (120,47), (240,41), (240,41), (360,41), (120,40), (360,41), (240,41), (240,41), (120,40), (120,36), (480,-1), (120,40), (240,41), (120,43)] self.base2Notes = [(120,-1), (120,45), (240,43), (120,-1), (240,43), (120,40), (480,43), (120,-1), (120,45), (120,45), (120,48), (240,-1), (240,41), (120,-1), (240,41), (120,40), (480,41), (120,-1), (120,45), (120,45), (120,48), (240,-1), (240,45), (120,-1), (240,45), (120,45), (480,45), (240,43), (120,-1), (120,45), (240,-1), (240,45), (120,-1), (240,45), (120,45), (480,45), (120,-1), (120,45), (120,45), (120,48)] self.baseNotes = self.base2Notes #[40, 41, 43, 45 48,] #changes / pitch sutff self.changes = [ (1920, [72, 74, 76, 79, 81, 84]), (1920, [69, 72, 74, 81]), (3840, [69, 72, 74, 76, 79, 81, 84])] self.changesIndex = 0 self.curChanges = [] self.selectSize = 2 self.lastPitchIndex = None self.lastTouch = None #Note length stuff self.noteLengths = [480, 240, 120] self.articulation = 1 self.lastPulseIndex = 0 #Declare the players self.perc = NoteSequencer(self.sched, self.synth, 1, (128,0), percNotes) self.base1 = NoteSequencer(self.sched, self.synth, 2, (0,33), self.base1Notes, callback = self.graphic_callback) self.base2 = NoteSequencer(self.sched, self.synth, 2, (0,33), self.base2Notes, callback = self.graphic_callback) self.lead = Arpeggiator(self.sched, self.synth, channel = 3, program = (0,65), callback = self.graphic_callback) self.lead.set_direction('updown') #Start the non-interactive stuff now = self.sched.get_tick() next_beat = quantize_tick_up(now, 480) self.perc.toggle() self.base2.toggle() self.sched.post_at_tick(self._updateChanges, next_beat) #Update changes as music starts self.sched.post_at_tick(self._spawnCrossBar, next_beat) # and text to display our status #self.label = topleft_label() #self.add_widget(self.label) #Graphics stuff self.objects = AnimGroup() self.canvas.add(self.objects) #self.allNotes = [40, 41, 43, 45, 48, 900, 69, 72, 74, 76, 79, 81, 84] self.allNotes = [36, 40, 41, 43, 45, 47, 48, 900, 69, 72, 74, 76, 79, 81, 84] def graphic_callback(self, pitch, length): w = Window.width numBuckets = len(self.allNotes) bucket = self.allNotes.index(pitch) widthOfBucket = w/numBuckets width = widthOfBucket - 10 leftX = bucket*widthOfBucket + 5 height = length/480 * 100 shape = NoteShape((leftX,0), height, width) self.objects.add(shape) def _spawnCrossBar(self, tick, ignore): shape = CrossBar() self.objects.add(shape) self.sched.post_at_tick(self._spawnCrossBar, tick+480) def _updateChanges(self, tick, ignore): timeTillNextChange = self.changes[self.changesIndex][0] self.curChanges = self.changes[self.changesIndex][1] #print("CHANGE OCCURED: ", self.curChanges) self.changesIndex = (self.changesIndex + 1) % len(self.changes) self.sched.post_at_tick(self._updateChanges, tick+timeTillNextChange) self.lastPitchIndex = None if self.lastTouch != None: self.update_pitches(self.lastTouch) def changeBaseLine(self): self.base1.toggle() self.base2.toggle() def on_key_down(self, keycode, modifiers): obj = lookup(keycode[1], 'm', (self.metro)) if obj is not None: obj.toggle() if keycode[1] == 'q': self.changeBaseLine() def on_key_up(self, keycode): pass def on_touch_down(self, touch): p = touch.pos self.update_pitches(p) self.update_pulse(p) self.lead.start() self.lastTouch = p def on_touch_up(self, touch): self.lead.stop() def on_touch_move(self, touch): p = touch.pos self.update_pitches(p) self.update_pulse(p) self.lastTouch = p def update_pitches(self, pos=(0,0)): mouseX = pos[0] w = Window.width numBuckets = len(self.curChanges) - self.selectSize + 1 sizeOfBucket = w / numBuckets noteBucket = int(mouseX // sizeOfBucket) if noteBucket != self.lastPitchIndex: arpegNotes = self.curChanges[noteBucket:noteBucket+self.selectSize] self.lead.set_pitches(arpegNotes) self.lastPitchIndex = noteBucket def update_pulse(self, pos=(0,0)): mouseY = pos[1] h = Window.height numBuckets = len(self.noteLengths) sizeOfBucket = h / numBuckets pulseBucket = int(mouseY // sizeOfBucket) if pulseBucket < len(self.noteLengths) and pulseBucket != self.lastPulseIndex: length = self.noteLengths[pulseBucket] self.lead.set_rhythm(length, self.articulation) self.lastPulseIndex = pulseBucket def on_update(self) : self.audio.on_update() self.objects.on_update()
def __init__(self, level, notes, goal_values, gear_values, **kwargs): super(LevelEasyMediumScreen, self).__init__(**kwargs) # set up notes for the level self.notes = notes # set up gear values for the levels self.goal_values = goal_values # set up gear values for the levels self.gear_values = gear_values self.level = level # only turn on tutorial for level 1 if self.level == 1: self.use_tutorial = True self.tutorial_screen = 'A' self.goal_play_status = None self.gear_play_status = None self.size_dim = min(Window.width / 6, Window.height / 6) self.tutorial_full_overlay = CRectangle(cpos=(Window.width / 2, Window.height / 2), csize=(Window.width, Window.height)) self.tutorial_options_overlay = Rectangle( pos=(0, 0), size=(Window.width, self.size_dim + Window.height / 25)) self.tutorial_musicbox_overlay = Rectangle( pos=(Window.width // 2, self.size_dim + Window.height / 25), size=(Window.width / 2, Window.height - (self.size_dim + Window.height / 25))) self.tutorial_gearbox_overlay = Rectangle( pos=(0, self.size_dim + Window.height / 25), size=(Window.width / 2, Window.height - (self.size_dim + Window.height / 25))) self.skip_image = CoreImage('images/skip_tutorial.png') self.tutorial_skip_button = Rectangle( pos=(0.98 * Window.width - (self.skip_image.width * self.size_dim / 300), 0.98 * Window.height - self.skip_image.height * self.size_dim / 300), size=(self.skip_image.width * self.size_dim / 300, self.skip_image.height * self.size_dim / 300), texture=self.skip_image.texture) else: self.use_tutorial = False ############################################ ### GOAL MUSIC ### ############################################ self.goal_audio = Audio(2) self.goal_synth = Synth('./data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.goal_tempo_map = SimpleTempoMap(120) self.goal_sched = AudioScheduler(self.goal_tempo_map) # connect scheduler into audio system self.goal_audio.set_generator(self.goal_sched) self.goal_sched.set_generator(self.goal_synth) # generate goal music self.goal_music = MusicPlayer(notes=self.notes, sched=self.goal_sched, synth=self.goal_synth, channel=1, tempo_map=self.goal_tempo_map) self.goal_music.update_tempo(self.goal_values[0]) self.goal_music.update_instrument(self.goal_values[1]) self.goal_music.update_pitch(self.goal_values[2]) self.goal_music.update_volume(self.goal_values[3]) self.goal_music_seq = self.goal_music.generate() ############################################ ### GEAR MUSIC ### ############################################ self.gear_audio = Audio(2) self.gear_synth = Synth('./data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.gear_tempo_map = SimpleTempoMap(120) self.gear_sched = AudioScheduler(self.gear_tempo_map) # connect scheduler into audio system self.gear_audio.set_generator(self.gear_sched) self.gear_sched.set_generator(self.gear_synth) # generate gear music self.gear_music = MusicPlayer(notes=self.notes, sched=self.gear_sched, synth=self.gear_synth, channel=1, tempo_map=self.gear_tempo_map) self.gear_music_seq = None ############################################ ### BACKGROUND UI COMPONENTS ### ############################################ self.gear_area = GearArea() self.canvas.add(self.gear_area) self.music_box_area = MusicBoxArea() self.canvas.add(self.music_box_area) self.options = LevelOptions( level=level, goal_music_seq=self.goal_music_seq, duration=self.goal_music.duration, edit_goal_play_status=self.edit_goal_play_status) self.canvas.add(self.options) self.label = Label(text=kwargs['name'], font_name='./fonts/PassionOne-Regular', color=(.165, .718, .792, 1)) self.add_widget(self.label) ########################################### ### GEAR LABELS ### ########################################### self.tempo_label = Label(text='Tempo (bpm)', font_name='./fonts/PassionOne-Regular', color=(0.7254901960784313, 0.5529411764705883, 0.8196078431372549, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (0.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.instrument_label = Label( text='Instrument', font_name='./fonts/PassionOne-Regular', color=(0.996078431372549, 0.8431372549019608, 0.4, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (1.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.pitch_label = Label(text='Pitch (semitones)', font_name='./fonts/PassionOne-Regular', color=(1.0, 0.6509803921568628, 0.09019607843137255, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (2.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.volume_label = Label( text='Volume', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=(Window.width / 4), center_y=(Window.height / 5.25 * (3.5 + 0.5) + self.gear_area.position[1]), font_size=str(Window.width // 50) + 'sp') self.add_widget(self.volume_label) self.add_widget(self.pitch_label) self.add_widget(self.instrument_label) self.add_widget(self.tempo_label) ########################################### ### GEAR CONSTRUCTION ### ########################################### self.gears = [] self.gear_centers = [] self.gears_group = AnimGroup() self.canvas.add(self.gears_group) ########################################### ### GEARS ### ########################################### self.gear_storage_locations = [] self.gear_music_locations = [] self.gear_labels = [] self.set_up_gears() ########################################### ### PARTICLE EFFECT ### ########################################### self.win_ps = ParticleSystem('particles/star_particle.pex') self.win_ps.emitter_x = Window.width / 2 self.win_ps.emitter_y = Window.height / 2 self.add_widget(self.win_ps) self.you_win_label = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.5843137254901961, 0.796078431372549, 0.37254901960784315, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 10) + 'sp') self.add_widget(self.you_win_label) self.lose_ps = ParticleSystem('particles/lose_particle.pex') self.lose_ps.emitter_x = Window.width / 2 self.lose_ps.emitter_y = Window.height / 2 self.add_widget(self.lose_ps) self.you_lose_label = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 10) + 'sp') self.add_widget(self.you_lose_label) ########################################### ### ERROR MESSAGE ### ########################################### self.error_msg = Label(text=' ', font_name='./fonts/PassionOne-Regular', color=(0.9254901960784314, 0.32941176470588235, 0.3176470588235294, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 20) + 'sp') self.add_widget(self.error_msg) # ########################################### # ### ADD TUTORIAL OVERLAYS ### # ########################################### if self.use_tutorial: self.canvas.add(Color(rgba=(0, 0, 0, 0.85))) self.canvas.add(self.tutorial_full_overlay) self.tutorial_label = Label( markup=True, text= "[font=./fonts/lato-bold]Welcome to the\n[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/PassionOne-Regular]Play It By Gear Tutorial[/font] [font=./fonts/options-icons]|[/font] [font=./fonts/lato-bold]\n\nThe goal of this game is to make the \n goal song match the song you create by \nplacing the correct gears in a music box \n\n[/font] [font=./fonts/lato-light] (click to see the next \nstep of the tutorial)[/font]", color=(86 / 255, 189 / 255, 205 / 255, 1), center_x=Window.width / 2, center_y=Window.height / 2, font_size=str(Window.width // 40) + 'sp', halign='center') self.add_widget(self.tutorial_label) self.canvas.add(self.tutorial_skip_button) self.on_layout((Window.width, Window.height))
class MainWidget(BaseWidget): def __init__(self): super(MainWidget, self).__init__() self.audio = Audio(2, input_func=self.receive_audio, num_input_channels=1) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.pitch = PitchDetector() self.recorder = VoiceAudioWriter('data') self.info = topleft_label() self.add_widget(self.info) self.anim_group = AnimGroup() self.mic_meter = MeterDisplay((50, 25), 150, (-96, 0), (.1, .9, .3)) self.mic_graph = GraphDisplay((110, 25), 150, 300, (-96, 0), (.1, .9, .3)) self.pitch_meter = MeterDisplay((50, 200), 150, (30, 90), (.9, .1, .3)) self.pitch_graph = GraphDisplay((110, 200), 150, 300, (30, 90), (.9, .1, .3)) self.canvas.add(self.mic_meter) self.canvas.add(self.mic_graph) self.canvas.add(self.pitch_meter) self.canvas.add(self.pitch_graph) # Record button self.record_button = InteractiveImage() self.record_button.source = "../data/mic.png" self.record_button.x = 400 self.record_button.y = 400 self.record_button.size = (100, 100) self.record_button.set_callback(self.init_recording) self.add_widget(self.record_button) # Play button self.play_button = InteractiveImage() self.play_button.source = "../data/play.png" self.play_button.x = 600 self.play_button.y = 400 self.play_button.size = (100, 100) self.play_button.set_callback(self.play_recording) self.add_widget(self.play_button) self.canvas.add(self.anim_group) self.onset_disp = None self.onset_x = 0 self.cur_pitch = 0 # Note Scheduler self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.mixer.add(self.sched) self.sched.set_generator(self.synth) # Note Sequencers self.seq = [] # live Generator self.live_wave = None def on_update(self): self.audio.on_update() self.anim_group.on_update() self.info.text = 'fps:%d\n' % kivyClock.get_fps() self.info.text += 'load:%.2f\n' % self.audio.get_cpu_load() self.info.text += "pitch: %.1f\n" % self.cur_pitch self.info.text += 'max delta: %.3f\n' % self.onset_detector.get_max_delta( ) self.info.text += 'onset delta thresh (up/down): %.3f\n' % self.onset_detector.onset_thresh if self.recorder.active: self.info.text += 'RECORDING' def receive_audio(self, frames, num_channels): assert (num_channels == 1) # Microphone volume level, take RMS, convert to dB. # display on meter and graph rms = np.sqrt(np.mean(frames**2)) rms = np.clip(rms, 1e-10, 1) # don't want log(0) db = 20 * np.log10(rms) # convert from amplitude to decibels self.mic_meter.set(db) self.mic_graph.add_point(db) # pitch detection: get pitch and display on meter and graph self.cur_pitch = self.pitch.write(frames) self.pitch_meter.set(self.cur_pitch) self.pitch_graph.add_point(self.cur_pitch) # record audio self.recorder.add_audio(frames, num_channels) # onset detection and classification self.onset_detector.write(frames) def init_recording(self): data = self.recorder.toggle() if data: print(data) wave_gen, filename, duration_midi = data for i in range(len(duration_midi)): if duration_midi[i][0] < 0.12: duration_midi[i] = (duration_midi[i][0], 0) duration_midi = harmony.harmonize(duration_midi) self.live_wave = wave_gen print([[i[1] for i in j] for j in duration_midi]) tempo = 120 multiplier = 1 / 60 * tempo * 480 converted_midi_duration = [[(i * multiplier, j) for i, j in k] for k in duration_midi] for i in converted_midi_duration: self.seq.append( NoteSequencer(self.sched, self.synth, 1, (0, 0), i, True)) def play_recording(self): print("hello") for i in self.seq: i.start() if self.live_wave: self.mixer.add(self.live_wave) def on_key_down(self, keycode, modifiers): t = lookup(keycode[1], ['up', 'down'], [.001, -.001]) if t is not None: self.onset_detector.onset_thresh += t if keycode[1] == "w": self.init_recording() if keycode[1] == "s" and self.seq: self.play_recording()
class LevelSelectScreen(Screen): def __init__(self, **kwargs): super(LevelSelectScreen, self).__init__(**kwargs) Window.clearcolor = colors['grey'].rgba self.anim_group = AnimGroup() self.canvas.add(self.anim_group) self.label = Label(text='Play it by Gear', font_name='./fonts/PassionOne-Regular', color=(.165, .718, .792, 1)) self.add_widget(self.label) self.buttons = [] self.id_counter = 0 self.audio = Audio(2) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.start_time = None self.switch_level = None self.border_color = colors['dark_grey'] self.border = Line(rectangle=(0, 0, Window.width, Window.height), width=Window.width * 0.03) self.anim_group.add(self.border_color) self.anim_group.add(self.border) self.on_layout((Window.width, Window.height)) def generate_buttons(self, row_pos, num_buttons, max_num_buttons, num_rows, margin): for i in range(num_buttons): self.id_counter += 1 square_dim = min(Window.width / (max_num_buttons + 2), Window.height / (num_rows + 1)) button = LevelButton(pos=(i / 6 * (Window.width) + margin, row_pos), size=(square_dim, square_dim), id=self.id_counter) self.buttons.append(button) self.anim_group.add(button) def on_touch_up(self, touch): for b in self.buttons: if b.is_clicked(touch): self.mixer.add( WaveGenerator(WaveFile("./data/button_press.wav"))) self.start_time = time.time() edit_progress_file(b.id, 'y') self.switch_level = 'Level ' + str(b.id) def on_enter(self): # update button colors by regenerating buttons self.on_layout((Window.width, Window.height)) def on_layout(self, winsize): # update level buttons self.anim_group.remove_all() self.id_counter = 0 self.buttons = [] self.generate_buttons(row_pos=(3 * Window.height / 5 - Window.height / 10), num_buttons=4, max_num_buttons=5, num_rows=3, margin=Window.width / 6) self.generate_buttons(row_pos=(2 * Window.height / 5 - Window.height / 10), num_buttons=5, max_num_buttons=5, num_rows=3, margin=Window.width / 12) self.generate_buttons(row_pos=(1 * Window.height / 5 - Window.height / 10), num_buttons=4, max_num_buttons=5, num_rows=3, margin=Window.width / 6) # update title label self.label.center_x = Window.width / 2 self.label.center_y = 5 * Window.height / 6 self.label.font_size = str(Window.width // 15) + 'sp' # update border self.border_color = colors['dark_grey'] self.border = Line(rectangle=(0, 0, Window.width, Window.height), width=Window.width * 0.03) self.anim_group.add(self.border_color) self.anim_group.add(self.border) def on_update(self): self.audio.on_update() if self.start_time and time.time() - self.start_time > 0.13: self.start_time = None self.switch_to(self.switch_level)
class MainScreen(Screen): def __init__(self, **kwargs): super(MainScreen, self).__init__(**kwargs) mode = 'mac' if (len(sys.argv) == 2) and (sys.argv[1] == 'mac') else 'pc' self.norm = Normalizer(mode) self.info = topleft_label() self.add_widget(self.info) self.writer = AudioWriter('recordings/song') self.audio = Audio(2, self.writer.add_audio) self.mixer = Mixer() self.mixer.set_gain(1.0) self.audio.set_generator(self.mixer) self.sandbox = Sandbox(canvas=self.canvas, pos=self.norm.nt((580, 50)), size=self.norm.nt((1000, 1000))) # since putting all our sound module code in MainScreen would be a nightmare, we've # modularized our modules into separate files. each module has two classes, the sound # module itself and its handler class. the handler class is essentially a wrapper of # many of MainScreen's important event functions (e.g. on_touch_down) that keeps track # of all variables related to that sound module for every connected client. self.module_dict = { 'PhysicsBubble': PhysicsBubble, 'SoundBlock': SoundBlock, 'TempoCursor': TempoCursor } block = SoundBlockHandler(self.norm, self.sandbox, self.mixer, client, client_id) self.module_handlers = { 'SoundBlock': block, 'PhysicsBubble': PhysicsBubbleHandler(self.norm, self.sandbox, self.mixer, client, client_id, block), 'TempoCursor': TempoCursorHandler(self.norm, self.sandbox, self.mixer, client, client_id, block) } # name a default starting module and handler self.module = PhysicsBubble self.module_handler = self.module_handlers[self.module.name] self.sandbox.add(self.module_handler.gui) # sync with existing server state client.emit('sync_module_state', {'module': 'PhysicsBubble'}) client.emit('sync_module_state', {'module': 'SoundBlock'}) client.emit('sync_module_state', {'module': 'TempoCursor'}) client.emit('update_norm', {'norm': {client_id: self.norm.mode}}) def on_touch_down(self, touch): if touch.button != 'left': return global client, client_id data = {'cid': client_id, 'module': self.module.name, 'pos': touch.pos} client.emit('touch_down', data) def on_touch_move(self, touch): if touch.button != 'left': return global client, client_id data = {'cid': client_id, 'module': self.module.name, 'pos': touch.pos} client.emit('touch_move', data) def on_touch_up(self, touch): if touch.button != 'left': return global client, client_id data = {'cid': client_id, 'module': self.module.name, 'pos': touch.pos} client.emit('touch_up', data) def on_key_down(self, keycode, modifiers): global client, client_id key = keycode[1] # switch module using keys (for now) module_name = lookup(key, 'zxc', ['PhysicsBubble', 'SoundBlock', 'TempoCursor']) if module_name is not None: old_handler = self.module_handler new_handler = self.module_handlers[module_name] if old_handler.module_name != new_handler.module_name: self.sandbox.remove(old_handler.gui) self.sandbox.add(new_handler.gui) self.module = self.module_dict[module_name] self.module_handler = new_handler elif key == 'spacebar': print('boop') self.writer.toggle() else: data = {'cid': client_id, 'module': self.module.name, 'key': key} client.emit('key_down', data) def on_update(self): self.audio.on_update() for _, handler in self.module_handlers.items(): handler.on_update() self.info.text = 'module: {}\n\n'.format(self.module.name) self.info.text += self.module_handler.display_controls() def on_layout(self, win_size): resize_topleft_label(self.info) def update_count(self, count): self.count = count
def __init__(self): super(MainWidget, self).__init__() self.audio = Audio(2, input_func=self.receive_audio, num_input_channels=1) self.mixer = Mixer() self.audio.set_generator(self.mixer) self.pitch = PitchDetector() self.recorder = VoiceAudioWriter('data') self.info = topleft_label() self.add_widget(self.info) self.anim_group = AnimGroup() self.mic_meter = MeterDisplay((50, 25), 150, (-96, 0), (.1, .9, .3)) self.mic_graph = GraphDisplay((110, 25), 150, 300, (-96, 0), (.1, .9, .3)) self.pitch_meter = MeterDisplay((50, 200), 150, (30, 90), (.9, .1, .3)) self.pitch_graph = GraphDisplay((110, 200), 150, 300, (30, 90), (.9, .1, .3)) self.canvas.add(self.mic_meter) self.canvas.add(self.mic_graph) self.canvas.add(self.pitch_meter) self.canvas.add(self.pitch_graph) # Record button self.record_button = InteractiveImage() self.record_button.source = "../data/mic.png" self.record_button.x = 400 self.record_button.y = 400 self.record_button.size = (100, 100) self.record_button.set_callback(self.init_recording) self.add_widget(self.record_button) # Play button self.play_button = InteractiveImage() self.play_button.source = "../data/play.png" self.play_button.x = 600 self.play_button.y = 400 self.play_button.size = (100, 100) self.play_button.set_callback(self.play_recording) self.add_widget(self.play_button) self.canvas.add(self.anim_group) self.onset_disp = None self.onset_x = 0 self.cur_pitch = 0 # Note Scheduler self.synth = Synth('../data/FluidR3_GM.sf2') # create TempoMap, AudioScheduler self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) # connect scheduler into audio system self.mixer.add(self.sched) self.sched.set_generator(self.synth) # Note Sequencers self.seq = [] # live Generator self.live_wave = None
class PuzzleSound(object): def __init__(self, notes, bank=0, preset=0, loop=False, simon_says=False, bass_puzzle=False): super().__init__() self.audio = Audio(2) self.synth = Synth("./data/FluidR3_GM.sf2") self.tempo_map = SimpleTempoMap(120) self.sched = AudioScheduler(self.tempo_map) self.sched.set_generator(self.synth) self.audio.set_generator(self.sched) self.notes = notes self.bank = bank self.preset = preset self.loop = loop self.simon_says = simon_says self.bass_puzzle = bass_puzzle self.note_seq = NoteSequencer( sched=self.sched, synth=self.synth, channel=1, program=(self.bank, self.preset), notes=self.notes, loop=self.loop, ) def set_notes(self, notes): self.notes = notes if self.simon_says or self.bass_puzzle: self.note_seq = NoteSequencer( sched=self.sched, synth=self.synth, channel=1, program=(self.bank, self.preset), notes=self.notes, loop=self.loop, ) self.note_seq.stop() self.note_seq.set_notes(self.notes) if self.bank == 0: self.letters = [n.get_letter() for n in self.notes] def set_cb_ons(self, cb_ons): self.note_seq.set_cb_ons(cb_ons) def set_cb_offs(self, cb_offs): self.note_seq.set_cb_offs(cb_offs) def set_on_finished(self, on_finished): self.note_seq.set_on_finished(on_finished) def toggle(self): self.note_seq.toggle() def on_update(self): self.audio.on_update()