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'
class MainWidget4(BaseWidget): def __init__(self): super(MainWidget4, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') self.audio.set_generator(self.synth) # create clock, tempo_map, scheduler self.clock = Clock() self.tempo_map = SimpleTempoMap(120) self.sched = Scheduler(self.clock, self.tempo_map) # create the metronome: self.metro = Metronome(self.sched, self.synth) # and text to display our status self.label = topleft_label() self.add_widget(self.label) def on_key_down(self, keycode, modifiers): if keycode[1] == 'c': self.clock.toggle() if keycode[1] == 'm': self.metro.toggle() bpm_adj = lookup(keycode[1], ('up', 'down'), (10, -10)) if bpm_adj: new_tempo = self.tempo_map.get_tempo() + bpm_adj self.tempo_map.set_tempo(new_tempo, self.sched.get_time()) def on_update(self): # scheduler and audio get poked every frame self.sched.on_update() self.audio.on_update() bpm = self.tempo_map.get_tempo() self.label.text = self.sched.now_str() + '\n' self.label.text += 'Metronome:' + ("ON" if self.metro.playing else "OFF") + '\n' self.label.text += 'tempo:{}\n'.format(bpm) self.label.text += 'm: toggle Metronome\n' self.label.text += 'up/down: change speed\n'
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'
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()