Example #1
0
    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,
        )
Example #2
0
    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)
Example #3
0
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'
Example #4
0
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'
Example #5
0
    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()
Example #6
0
    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)
Example #7
0
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'
Example #8
0
    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)
Example #9
0
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'
Example #10
0
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()
Example #11
0
    def __init__(self, norm, sandbox, mixer, client, client_id):
        self.norm = norm
        self.module_name = 'SoundBlock'
        self.sandbox = sandbox

        self.mixer = mixer
        self.tempo_map = SimpleTempoMap(bpm=60)
        self.sched = AudioScheduler(self.tempo_map)
        self.synth = Synth("data/FluidR3_GM.sf2")
        self.sched.set_generator(self.synth)
        self.mixer.add(self.sched)
        self.cmd = {}

        self.client = client
        self.cid = client_id
        self.instruments = {
            'piano': 1,
            'violin': 41,
            'trumpet': 57,
            'ocarina': 80,
            'choir': 53
        }
        self.inst_list = ['piano', 'violin', 'trumpet', 'ocarina', 'choir']
        self.drumkit = {
            'snare': 38,
            'crash': 49,
            'bass': 35,
            'hihat': 46,
            'triangle': 81
        }
        self.drum_list = ['snare', 'crash', 'bass', 'hihat', 'triangle']
        self.channel = 0
        self.drum_channel = len(self.inst_list)

        # set up the correct sound (program: bank and preset)
        # each instrument is on a different channel
        for index, inst in enumerate(self.inst_list):
            self.synth.program(index, 0, self.instruments[inst])

        for index, drum in enumerate(self.drum_list):
            self.synth.program(index + len(self.instruments), 128, 0)

        # many variables here are dicts because a user's module handler needs to keep track of
        # not just its own variables, but other users' variables as well! so we use dictionaries
        # with client ids as the keys.
        self.hold_point = {}
        self.hold_shape = {}

        # this variable is needed for when a user clicks on a soundblock in a touch_down event,
        # so that the corresponding touch_up event is skipped
        self.skip = {}

        self.color_dict = {
            'red': (201 / 255, 108 / 255, 130 / 255),
            'orange': (214 / 255, 152 / 255, 142 / 255),
            'yellow': (238 / 255, 234 / 255, 202 / 255),
            'green': (170 / 255, 220 / 255, 206 / 255),
            'teal': (159 / 255, 187 / 255, 208 / 255),
            'blue': (44 / 255, 85 / 255, 123 / 255),
            'turquoise': (50 / 255, 147 / 255, 140 / 255),
            'indigo': (46 / 255, 40 / 255, 90 / 255),
            'violet': (147 / 255, 127 / 255, 159 / 255),
            'pink': (199 / 255, 150 / 255, 170 / 255),
            'peach': (238 / 255, 142 / 255, 154 / 255),
            'magenta': (172 / 255, 69 / 255, 133 / 255),
            'grey': (140 / 255, 143 / 255, 148 / 255),
            'white': (239 / 255, 226 / 255, 222 / 255)
        }

        self.default_color = self.color_dict['violet']
        self.default_pitch = 60
        self.default_timbre = 'sine'
        self.default_instrument = 'piano'
        self.default_drum = 'snare'

        self.color = {}
        self.pitch = {}
        self.timbre = {}
        self.instrument = {}
        self.drum = {}

        self.display = False

        self.blocks = AnimGroup()
        self.sandbox.add(self.blocks)

        self.gui = BlockGUI(self.norm,
                            pos=self.norm.nt((50, 100)),
                            is_drum=False,
                            pitch_callback=self.update_pitch,
                            instrument_callback=self.update_instrument,
                            drum_callback=self.update_drum)

        self.delete_mode = {}
Example #12
0
class SoundBlockHandler(object):
    """
    Handles user interaction and drawing of graphics before generating a SoundBlock.
    Also stores and updates all currently active SoundBlocks.
    """
    def __init__(self, norm, sandbox, mixer, client, client_id):
        self.norm = norm
        self.module_name = 'SoundBlock'
        self.sandbox = sandbox

        self.mixer = mixer
        self.tempo_map = SimpleTempoMap(bpm=60)
        self.sched = AudioScheduler(self.tempo_map)
        self.synth = Synth("data/FluidR3_GM.sf2")
        self.sched.set_generator(self.synth)
        self.mixer.add(self.sched)
        self.cmd = {}

        self.client = client
        self.cid = client_id
        self.instruments = {
            'piano': 1,
            'violin': 41,
            'trumpet': 57,
            'ocarina': 80,
            'choir': 53
        }
        self.inst_list = ['piano', 'violin', 'trumpet', 'ocarina', 'choir']
        self.drumkit = {
            'snare': 38,
            'crash': 49,
            'bass': 35,
            'hihat': 46,
            'triangle': 81
        }
        self.drum_list = ['snare', 'crash', 'bass', 'hihat', 'triangle']
        self.channel = 0
        self.drum_channel = len(self.inst_list)

        # set up the correct sound (program: bank and preset)
        # each instrument is on a different channel
        for index, inst in enumerate(self.inst_list):
            self.synth.program(index, 0, self.instruments[inst])

        for index, drum in enumerate(self.drum_list):
            self.synth.program(index + len(self.instruments), 128, 0)

        # many variables here are dicts because a user's module handler needs to keep track of
        # not just its own variables, but other users' variables as well! so we use dictionaries
        # with client ids as the keys.
        self.hold_point = {}
        self.hold_shape = {}

        # this variable is needed for when a user clicks on a soundblock in a touch_down event,
        # so that the corresponding touch_up event is skipped
        self.skip = {}

        self.color_dict = {
            'red': (201 / 255, 108 / 255, 130 / 255),
            'orange': (214 / 255, 152 / 255, 142 / 255),
            'yellow': (238 / 255, 234 / 255, 202 / 255),
            'green': (170 / 255, 220 / 255, 206 / 255),
            'teal': (159 / 255, 187 / 255, 208 / 255),
            'blue': (44 / 255, 85 / 255, 123 / 255),
            'turquoise': (50 / 255, 147 / 255, 140 / 255),
            'indigo': (46 / 255, 40 / 255, 90 / 255),
            'violet': (147 / 255, 127 / 255, 159 / 255),
            'pink': (199 / 255, 150 / 255, 170 / 255),
            'peach': (238 / 255, 142 / 255, 154 / 255),
            'magenta': (172 / 255, 69 / 255, 133 / 255),
            'grey': (140 / 255, 143 / 255, 148 / 255),
            'white': (239 / 255, 226 / 255, 222 / 255)
        }

        self.default_color = self.color_dict['violet']
        self.default_pitch = 60
        self.default_timbre = 'sine'
        self.default_instrument = 'piano'
        self.default_drum = 'snare'

        self.color = {}
        self.pitch = {}
        self.timbre = {}
        self.instrument = {}
        self.drum = {}

        self.display = False

        self.blocks = AnimGroup()
        self.sandbox.add(self.blocks)

        self.gui = BlockGUI(self.norm,
                            pos=self.norm.nt((50, 100)),
                            is_drum=False,
                            pitch_callback=self.update_pitch,
                            instrument_callback=self.update_instrument,
                            drum_callback=self.update_drum)

        self.delete_mode = {}

    def on_touch_down(self, cid, pos):
        if cid == self.cid:
            self.gui.on_touch_down(pos)

        if not self.sandbox.in_bounds(pos):
            return

        # when a block is clicked, flash and play a sound
        for block in self.blocks.objects:
            if in_bounds(pos, block.pos, block.size):
                if self.delete_mode[cid]:
                    self.blocks.objects.remove(block)
                    self.blocks.remove(block)
                    return

                block.flash()
                self.skip[cid] = True
                return  # don't start drawing a SoundBlock

        if self.delete_mode[cid]:
            return

        self.hold_point[cid] = pos
        self.hold_shape[cid] = Rectangle(pos=pos, size=(0, 0))

        self.sandbox.add(Color(1, 1, 1))
        self.sandbox.add(self.hold_shape[cid])

    def on_touch_move(self, cid, pos):
        if not self.sandbox.in_bounds(pos):
            return

        #determine which direction rectangle is being created in
        hold_point = self.hold_point[cid]
        size = self.calculate_size(hold_point, pos)
        bottom_left = pos

        #moving northeast
        if pos[0] > hold_point[0] and pos[1] > hold_point[1]:
            bottom_left = hold_point

        #moving southeast
        elif pos[0] > hold_point[0] and pos[1] < hold_point[1]:
            bottom_left = (hold_point[0], pos[1])

        #moving southwest
        elif pos[0] < hold_point[0] and pos[1] < hold_point[1]:
            bottom_left = pos

        #moving northwest
        elif pos[0] < hold_point[0] and pos[1] > hold_point[1]:
            bottom_left = (pos[0], hold_point[1])

        self.hold_shape[cid].pos = bottom_left
        self.hold_shape[cid].size = size

    def on_touch_up(self, cid, pos):
        if self.skip.get(cid):
            self.skip[cid] = False
            return

        if self.delete_mode[cid]:
            return

        if self.hold_shape.get(cid) not in self.sandbox:
            if not self.sandbox.in_bounds(pos):
                return

        bottom_left = self.hold_shape[cid].pos
        size = self.hold_shape[cid].size

        if size[0] <= 10 or size[1] <= 10:
            self.sandbox.remove(self.hold_shape[cid])
            return

        self.sandbox.remove(self.hold_shape[cid])

        pitch = self.pitch[cid]
        color = self.color[cid]
        instrument = self.instrument[cid]
        self.channel = self.inst_list.index(instrument)
        drum = self.drum[cid]
        self.drum_channel = self.drum_list.index(drum) + len(self.inst_list)

        if self.gui.is_drum:
            block = SoundBlock(self.norm, self.sandbox, bottom_left, size,
                               self.drum_channel, self.drumkit[drum], color,
                               self, self.sound)
        else:
            block = SoundBlock(self.norm, self.sandbox, bottom_left, size,
                               self.channel, pitch, color, self, self.sound)
        self.blocks.add(block)

    def on_key_down(self, cid, key):
        index = lookup(key, 'q2w3er5t6y7ui', range(13))
        if index is not None:
            if self.cid == cid:
                self.gui.ps.select(index)
        if key == '[':
            if cid == self.cid:
                self.gui.ps.left_press()
        if key == ']':
            if cid == self.cid:
                self.gui.ps.right_press()

        if key == 'v' and cid == self.cid:
            self.delete_mode[cid] = not self.delete_mode[cid]
            self.update_server_state(post=True)

        if key == 'up':
            if not self.gui.is_drum:
                self.gui.switch_module()

        if key == 'down':
            if self.gui.is_drum:
                self.gui.switch_module()

        if self.gui.is_drum:
            drum = lookup(key, 'asdfg',
                          ['snare', 'crash', 'bass', 'hihat', 'triangle'])
            if drum is not None:
                self.drum[cid] = drum
                if self.cid == cid:
                    self.drum_channel = self.drum_list.index(drum) + len(
                        self.inst_list)
                    self.gui.ds.select(drum)
        else:
            instrument = lookup(
                key, 'asdfg',
                ['piano', 'violin', 'trumpet', 'ocarina', 'choir'])
            if instrument is not None:
                self.instrument[cid] = instrument
                if self.cid == cid:
                    self.channel = self.inst_list.index(instrument)
                    self.gui.ints.select(
                        instrument)  # have the GUI update as well

    def display_controls(self):
        info = 'delete mode: {}\n'.format(self.delete_mode[self.cid])
        if self.gui.is_drum:
            info += 'drum: {}\n'.format(self.drum_list[self.drum_channel -
                                                       len(self.inst_list)])
        else:
            info += 'instrument: {}\n'.format(self.inst_list[self.channel])
        return info

    def on_update(self):
        self.blocks.on_update()
        self.gui.on_update(Window.mouse_pos)

    def update_server_state(self, post=False):
        """
        Update server state. If post is True, relay this updated state to all clients.
        """
        state = {
            'color': self.color,
            'pitch': self.pitch,
            'timbre': self.timbre,
            'instrument': self.instrument,
            'drum': self.drum,
            'delete_mode': self.delete_mode
        }
        data = {
            'module': self.module_name,
            'cid': self.cid,
            'state': state,
            'post': post
        }
        self.client.emit('update_state', data)

    def update_client_state(self, cid, state):
        """
        Update this handler's state.
        """
        if cid != self.cid:  # this client already updated its own state
            self.color = state['color']
            self.pitch = state['pitch']
            self.timbre = state['timbre']
            self.instrument = state['instrument']
            self.drum = state['drum']
            self.delete_mode = state['delete_mode']

    def sync_state(self, state):
        """
        Initial sync with the server's copy of module state.
        We don't sync with hold_shape, hold_point, and hold_line because those objects are not
        json-serializable and are short-term values anyway.
        """
        self.color = state['color']
        self.pitch = state['pitch']
        self.timbre = state['timbre']
        self.instrument = state['instrument']
        self.drum = state['drum']
        self.delete_mode = state['delete_mode']

        # after initial sync, add default values for this client
        self.color[self.cid] = self.default_color
        self.pitch[self.cid] = self.default_pitch
        self.timbre[self.cid] = self.default_timbre
        self.instrument[self.cid] = self.default_instrument
        self.drum[self.cid] = self.default_drum
        self.delete_mode[self.cid] = False

        self.skip[self.cid] = False

        # now that default values are set, we can display this module's info
        self.display = True

        # update server with these default values
        # post=True here because we want all other clients' states to update with this client's
        # default values.
        self.update_server_state(post=True)

    def sound(self, channel, pitch):
        """
        Play a sound with a given pitch on the given channel.
        """
        if self.cmd.get((channel, pitch)):
            self.sched.cancel(self.cmd[(channel, pitch)])
        self.synth.noteon(channel, pitch, 100)
        now = self.sched.get_tick()
        self.cmd[(channel,
                  pitch)] = self.sched.post_at_tick(self._noteoff, now + 240,
                                                    (channel, pitch))

    def update_pitch(self, color, pitch):
        """Update this client's color and pitch due to PitchSelect."""

        self.color[self.cid] = self.color_dict[color]
        self.pitch[self.cid] = pitch
        self.update_server_state(post=True)

    def update_instrument(self, instrument):
        """Update this client's instrument due to InstrumentSelect."""
        self.instrument[self.cid] = instrument
        self.channel = self.inst_list.index(instrument)
        self.update_server_state(post=True)

    def update_drum(self, drum):
        self.drum[self.cid] = drum
        self.drum_channel = self.drum_list.index(drum) + len(self.inst_list)
        self.update_server_state(post=True)

    def _noteoff(self, tick, args):
        channel, pitch = args
        self.synth.noteoff(channel, pitch)

    def calculate_size(self, corner, pos):
        x = abs(pos[0] - corner[0])
        y = abs(pos[1] - corner[1])
        return (x, y)

    def calculate_center(self, corner, size):
        c_x = corner[0] + (size[0] / 2)
        c_y = corner[1] + (size[1] / 2)
        return (c_x, c_y)
Example #13
0
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()
Example #14
0
    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]
Example #15
0
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)
Example #16
0
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()
Example #17
0
    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))
Example #18
0
    def __init__(self):
        super(IntroScreen, self).__init__()
        self.genre_popup = CheckboxPopup(self.genre_callback, "GENRE",
                                         GENRE_CHECKBOXES)
        self.volume_popup = VolumePopup(self.slider_callback)
        self.record_popup = RecordPopup(self.init_recording,
                                        self.toggle_playing)
        self.instruments_popup = CheckboxPopup(self.instrument_callback,
                                               "INSTRUMENTS",
                                               INSTRUMENT_CHECKBOXES)
        self.storage_popup = StoragePopup(self.get_live_wave,
                                          self.set_live_wave)
        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.playing = False
        self.recording = False
        self.cmd = None

        self.scene = Scene()
        self.add_widget(self.scene)
        self.scene.foreground.radio.set_callback(self.genre_popup.open)
        self.scene.foreground.amp.set_callback(self.volume_popup.open)
        self.scene.foreground.mic.set_callback(self.record_popup.open)
        self.scene.foreground.guitar.set_callback(self.instruments_popup.open)
        self.scene.foreground.storage.set_callback(self.storage_popup.open)

        self.cur_pitch = 0
        self.midi_notes = None

        self.bass = [((40, 60), (0, 0)), ((43, 64), (0, 42)),
                     ((28, 48), (0, 33))]
        self.tenor = [((52, 69), (0, 0)), ((52, 69), (0, 41)),
                      ((45, 64), (0, 26))]
        self.alto = [((57, 77), (0, 0)), ((60, 79), (0, 40)),
                     ((52, 72), (0, 29)), ((67, 86), (0, 73))]
        self.instruments = [self.bass, self.tenor, self.alto]
        self.genre = 'pop'

        self.indices = [0, 0, 0]

        # Note Scheduler
        self.synth = Synth('data/FluidR3_GM.sf2')

        # create TempoMap, AudioScheduler
        self.tempo_map = SimpleTempoMap(120)
        self.sched = AudioScheduler(self.tempo_map)
        self.metro = Metronome(self.sched, self.synth)
        self.start_tick = None

        # connect scheduler into audio system
        self.mixer.add(self.sched)
        self.sched.set_generator(self.synth)

        # Note Sequencers
        self.seq = [None, None, None]

        # live Generator
        self.live_wave = None

        # current .wav file
        self.current_wave_file = None
Example #19
0
class IntroScreen(BaseWidget):
    image = "data/bedroom.jpg"

    def __init__(self):
        super(IntroScreen, self).__init__()
        self.genre_popup = CheckboxPopup(self.genre_callback, "GENRE",
                                         GENRE_CHECKBOXES)
        self.volume_popup = VolumePopup(self.slider_callback)
        self.record_popup = RecordPopup(self.init_recording,
                                        self.toggle_playing)
        self.instruments_popup = CheckboxPopup(self.instrument_callback,
                                               "INSTRUMENTS",
                                               INSTRUMENT_CHECKBOXES)
        self.storage_popup = StoragePopup(self.get_live_wave,
                                          self.set_live_wave)
        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.playing = False
        self.recording = False
        self.cmd = None

        self.scene = Scene()
        self.add_widget(self.scene)
        self.scene.foreground.radio.set_callback(self.genre_popup.open)
        self.scene.foreground.amp.set_callback(self.volume_popup.open)
        self.scene.foreground.mic.set_callback(self.record_popup.open)
        self.scene.foreground.guitar.set_callback(self.instruments_popup.open)
        self.scene.foreground.storage.set_callback(self.storage_popup.open)

        self.cur_pitch = 0
        self.midi_notes = None

        self.bass = [((40, 60), (0, 0)), ((43, 64), (0, 42)),
                     ((28, 48), (0, 33))]
        self.tenor = [((52, 69), (0, 0)), ((52, 69), (0, 41)),
                      ((45, 64), (0, 26))]
        self.alto = [((57, 77), (0, 0)), ((60, 79), (0, 40)),
                     ((52, 72), (0, 29)), ((67, 86), (0, 73))]
        self.instruments = [self.bass, self.tenor, self.alto]
        self.genre = 'pop'

        self.indices = [0, 0, 0]

        # Note Scheduler
        self.synth = Synth('data/FluidR3_GM.sf2')

        # create TempoMap, AudioScheduler
        self.tempo_map = SimpleTempoMap(120)
        self.sched = AudioScheduler(self.tempo_map)
        self.metro = Metronome(self.sched, self.synth)
        self.start_tick = None

        # connect scheduler into audio system
        self.mixer.add(self.sched)
        self.sched.set_generator(self.synth)

        # Note Sequencers
        self.seq = [None, None, None]

        # live Generator
        self.live_wave = None

        # current .wav file
        self.current_wave_file = None

    def genre_callback(self, value, label):
        self.genre = value
        if value == 'classical':
            self.instruments_popup.set_checkboxes(ORCHESTRA)
            self.indices = [1, 1, 1]
            self.instrument_callback(None, None)
        if value == 'pop':
            self.instruments_popup.set_checkboxes(POP)
            self.indices = [2, 2, 0]
            self.instrument_callback(None, None)

    def instrument_callback(self, value, label):
        if label == 'high voice':
            self.indices[2] = ['piano', 'violin', 'guitar',
                               'flute'].index(value)
        if label == 'mid voice':
            self.indices[1] = ['piano', 'viola', 'guitar'].index(value)
        if label == 'low voice':
            self.indices[0] = ['piano', 'cello', 'bass'].index(value)
        if self.live_wave is not None:
            for i in self.seq:
                i.stop()
                self.live_wave.reset()
                #reharmonize and update NoteSequencers
            duration_midi = harmony.harmonize(
                self.midi_notes,
                self.genre,
                brange=self.bass[self.indices[0]][0],
                trange=self.tenor[self.indices[1]][0],
                arange=self.alto[self.indices[2]][0])
            tempo = self.tempo_map.get_tempo()
            multiplier = 1 / 60 * tempo * 480
            converted_midi_duration = [[(i * multiplier, j) for i, j in k]
                                       for k in duration_midi]

            for i in range(3):
                self.seq[i] = NoteSequencer(
                    self.sched, self.synth, i + 1,
                    self.instruments[i][self.indices[i]][1],
                    converted_midi_duration[i + 1], self.scene.add_note_sprite,
                    True)
            if self.playing:
                self.play_recording(1)

    def slider_callback(self, voice, value):
        val = int(value)
        idx = ["bass", "tenor", "alto", "melody"].index(voice) + 1
        if idx < 4:
            self.synth.cc(idx, 7, val)
        else:
            if self.live_wave:
                self.live_wave.set_gain(val / 100)

    def on_update(self):
        self.audio.on_update()
        self.scene.on_update()

    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 and not self.playing and not self.recording:
            new_tempo = max(self.tempo_map.get_tempo() + bpm_adj, 30)
            self.tempo_map.set_tempo(new_tempo, self.sched.get_time())

    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.record_popup.mic_meter.set(db)
        self.record_popup.mic_graph.add_point(db)

        # pitch detection: get pitch and display on meter and graph
        self.cur_pitch = self.pitch.write(frames)
        self.record_popup.pitch_meter.set(self.cur_pitch)
        self.record_popup.pitch_graph.add_point(self.cur_pitch)

        # record audio
        self.recorder.add_audio(frames, num_channels)

    def init_recording(self):
        if not self.recording:
            self.start_tick = self.sched.get_tick()
        data = self.recorder.toggle()
        if not data:
            self.recording = True
            if self.live_wave is not None:
                try:
                    self.mixer.remove(self.live_wave)
                except:
                    pass
            for i in self.seq:
                if i is not None:
                    i.stop()
            self.playing = False
        else:
            self.recording = False
            stop_tick = self.sched.get_tick()
            wave_gen, filename, duration_midi = data
            self.current_wave_file = WaveFile(filename)
            #ignore short notes
            i = 0
            while i < len(duration_midi):
                if duration_midi[i][0] < 0.1:
                    duration_midi[i - 1] = (duration_midi[i][0] +
                                            duration_midi[i - 1][0],
                                            duration_midi[i - 1][1])
                    duration_midi.pop(i)
                else:
                    i += 1
            duration_midi[0] = (duration_midi[0][0] - .1, duration_midi[0][1])
            ticks = [(int(note[0] * 480 * self.tempo_map.get_tempo() / 60),
                      note[1]) for note in duration_midi]
            ticks[0] = (ticks[0])
            duration_midi = []
            tick_length = sum(i[0] for i in ticks)
            curr_beat = int(480 - self.start_tick % 480 +
                            .22 * 8 * self.tempo_map.get_tempo()) % 480
            ind = 0
            ticks_passed = 0
            while tick_length > 0:
                tot = 0
                times = {}
                while tot < curr_beat and ind < len(ticks):
                    left = ticks[ind][0] - ticks_passed
                    if left > curr_beat - tot:
                        ticks_passed += curr_beat - tot
                        if ticks[ind][1] in times:
                            times[ticks[ind][1]] += curr_beat - tot
                        else:
                            times[ticks[ind][1]] = curr_beat - tot
                        tot = curr_beat
                    else:
                        tot += left
                        ticks_passed = 0
                        if ticks[ind][1] in times:
                            times[ticks[ind][1]] += left
                        else:
                            times[ticks[ind][1]] = left
                        ind += 1
                big = 80
                note = 0
                print(times)
                for guy in times:
                    if times[guy] > big and guy != 0:
                        note = guy
                        big = times[guy]
                duration_midi.append(
                    (60 * curr_beat / 480 / self.tempo_map.get_tempo(), note))
                tick_length -= curr_beat
                curr_beat = min(480, tick_length)
            duration_midi = [(0.1, 0)] + duration_midi
            self.midi_notes = duration_midi
            #find harmonies
            self.live_wave = wave_gen
            good = False
            for i in duration_midi:
                if i[1] > 0:
                    good = True
                    break
            if good:
                duration_midi = harmony.harmonize(
                    duration_midi,
                    self.genre,
                    brange=self.bass[self.indices[0]][0],
                    trange=self.tenor[self.indices[1]][0],
                    arange=self.alto[self.indices[2]][0])
                #print([[i[1] for i in j] for j in duration_midi])

                # cheat to use SimpleTempoMap
                tempo = self.tempo_map.get_tempo()
                multiplier = 1 / 60 * tempo * 480
                converted_midi_duration = [[(i * multiplier, j) for i, j in k]
                                           for k in duration_midi]
                #make NoteSequencers
                for i in range(3):
                    self.seq[i] = NoteSequencer(
                        self.sched, self.synth, i + 1,
                        self.instruments[i][self.indices[i]][1],
                        converted_midi_duration[i + 1],
                        self.scene.add_note_sprite, True)

    def play_recording(self, tick):
        for i in self.seq:
            if i is not None:
                i.start()
        if self.live_wave:
            self.live_wave.play()
            if self.live_wave not in self.mixer.generators:
                self.mixer.add(self.live_wave)

    def start_playing(self):
        if self.playing:
            return
        self.metro.stop()
        self.playing = True

        now = self.sched.get_tick()
        next_beat = quantize_tick_up(now, kTicksPerQuarter * 4)
        self.cmd = self.sched.post_at_tick(self.play_recording, next_beat)

    def stop_playing(self):
        if not self.playing:
            return

        self.playing = False
        for i in self.seq:
            i.stop()
        self.live_wave.reset()

        self.sched.cancel(self.cmd)
        self.cmd = None

    def toggle_playing(self):
        print(self.playing)
        if self.playing:
            self.stop_playing()
        else:
            self.start_playing()

    def get_live_wave(self):
        if self.live_wave:
            return WaveGenerator(self.current_wave_file, True), self.seq.copy()

    def set_live_wave(self, new_live_wave, note_sequencers):
        if self.live_wave:
            if self.live_wave is not None:
                try:
                    self.mixer.remove(self.live_wave)
                except:
                    pass

            for i in self.seq:
                if i is not None:
                    i.stop()
            self.seq = note_sequencers
            for i in self.seq:
                if i is not None:
                    i.start()
            self.live_wave = new_live_wave
            self.mixer.add(self.live_wave)
            self.start_playing()
Example #20
0
    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
Example #21
0
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()