import mido mido.set_backend('mido.backends.pygame') from mido import Message, MidiFile, MidiTrack import time import pynput import sys sys.path.append('../../') from src.music.config import SYNTH_RECORDED_MIDI_PATH from datetime import datetime #TODO: debug this with other cable, keyboard and sound card global KEY_PRESSED KEY_PRESSED = None def on_press(key): global KEY_PRESSED try: KEY_PRESSED = key.name except: pass def on_release(key): global KEY_PRESSED KEY_PRESSED = None def is_pressed(key): global KEY_PRESSED return KEY_PRESSED == key # keyboard listener listener = pynput.keyboard.Listener(on_press=on_press, on_release=on_release) listener.start() LEN_MIDI_RECORDINGS = 30 class MidiRecorder: def __init__(self, place='', len_midi_recordings=LEN_MIDI_RECORDINGS): self.place = place self.len_midi_recordings = len_midi_recordings self.port = mido.open_input(mido.get_input_names()[0]) def get_filename(self): now = datetime.now() return self.place + '_' + now.strftime("%b_%d_%Y_%Hh%Mm%Ss") + '.mid' def read_last_midi_msgs(self): return list(self.port.iter_pending()) def live_read(self): while not is_pressed('esc'): for msg in self.read_last_midi_msgs(): print(msg) def check_if_recording_started(self, msgs, t_init): started = False if len(msgs) > 0: for m in msgs: if m.type == 'note_on': started = True t_init = time.time() return started, t_init def create_empty_midi(self): mid = MidiFile() track = MidiTrack() mid.tracks.append(track) track.append(Message('program_change', program=0, time=0)) return mid, track def record_next_N_seconds(self, n=None, saving_path=None): if saving_path is None: saving_path = SYNTH_RECORDED_PATH + self.get_filename() if n is None: n = self.len_midi_recordings print(f'Recoding the next {n} secs.' f'\n\tRecording starts when the first key is pressed;' f'\n\tPress Enter to end the recording;' f'\n\tPress BackSpace (<--) to cancel the recording;' f'\n\tSaving to {saving_path}') try: mid, track = self.create_empty_midi() started = False backspace_pressed = False t_init = time.time() while not is_pressed('enter') and (time.time() - t_init) < n: msgs = self.read_last_midi_msgs() if not started: started, t_init = self.check_if_recording_started(msgs, t_init) if started: print("\n\t--> First note pressed, it's on!") for m in msgs: print(m) if m.type == 'note_on' and m.velocity == 0: m_off = Message(type='note_off', velocity=127, note=m.note, channel=m.channel, time=m.time) track.append(m_off) track.append(m) if is_pressed('backspace'): backspace_pressed = True print('\n \t--> Recording cancelled! (you pressed BackSpace)') break # save the file if not backspace_pressed and len(mid.tracks[0]) > 0: mid.save(saving_path) print(f'\n--> Recording saved, duration: {mid.length:.2f} secs, {len(mid.tracks[0])} events.') except: print('\n --> The recording failed.') def run(self): # with pynput.Listener( # on_press=self.on_press) as listener: # listener.join() ready_msg = False print('Starting the recording loop!\n\tPress BackSpace to cancel the current recording;\n\tPress Esc to quit the loop (only works while not recording)') while True: if not ready_msg: print('-------\nReady to record!') print('Press space to start a recording\n') ready_msg = True if is_pressed('space'): self.record_next_N_seconds() ready_msg = False if is_pressed('esc'): print('End of the recording session. See you soon!') break midi_recorder = MidiRecorder(place='home') midi_recorder.live_read() # midi_recorder.run() # try: # controls[msg.control] = msg.value # except: # notes.append(msg.note) # port = mido.open_input() # while True: # for msg in port.iter_pending(): # print(msg) # # print('start pause') # time.sleep(5) # print('stop pause')