def part_midi(f, key=None): fname = f.split(os.path.sep)[-1] _midi = PrettyMIDI(f) # part for ind, instrument in enumerate(_midi.instruments): midi = PrettyMIDI(f) n = len(midi.instruments) # sound for ind2, inst in enumerate(midi.instruments): if ind2 != ind: inst.program = subSound else: inst.program = mainSound if instrument.name: name = instrument.name elif len(names) == n: name = names[ind] else: name = str(ind) if n != len(volumes): continue # volume for inst, value in zip(midi.instruments, volumes): if instrument is inst: value += volumeDiff inst.control_changes.append( ControlChange(number=7, value=value, time=0.001)) midi.write( os.path.join(outdir, fname.rsplit(".", 1)[0] + "_" + name + ".mid"))
def read_midi_files(path: Union[Path, str], regex: str, extra: bool = True) -> List[Tuple[PrettyMIDI, int]]: """ Reads mid files in given folder and returns a list of PrettyMIDI. For all following directories use **/*.*. """ folder = Path(path) if extra: return [(PrettyMIDI(file.as_posix()), int(file.parent.stem) if file.parent.stem != 'extra' else int(file.parent.parent.stem)) for file in folder.glob(regex)] return [(PrettyMIDI(file.as_posix()), int(file.parent.stem)) for file in folder.glob(regex) if file.parent.stem != 'extra']
def convert2midi(self): midi = PrettyMIDI(resolution=STATE_RESOLUTION, initial_tempo=STATE_TEMP) inst = Instrument(1, False, 'Note_Seqce') inst.notes = copy.deepcopy(self.notes) midi.instruments.append(inst) return midi
def create_drum_pretty_midi( onset_matrix: np.ndarray, vel_matrix: np.ndarray, q_note_res: int = Q_NOTE_RES, bpm: float = 120.0, playback_midi_map: List[int] = CHRISTHETREE_PLAYBACK_MIDI_MAP_8 ) -> PrettyMIDI: pm = PrettyMIDI(initial_tempo=bpm) res = (60.0 / bpm) / q_note_res drum_inst = Instrument(0, is_drum=True) n_beats = vel_matrix.shape[0] for beat_idx in range(n_beats): onset_vals = onset_matrix[beat_idx, :] onsets = np.nonzero(onset_vals >= 0.5)[0] vels = vel_matrix[beat_idx, :] for onset in onsets: pitch = playback_midi_map[onset] vel = int((vels[onset] * 127) + 0.5) _add_note(drum_inst, pitch, vel, res * beat_idx, (res * beat_idx) + 0.2) pm.instruments.append(drum_inst) return pm
def extract_drums(midi_path: str) -> Optional[PrettyMIDI]: """ Extracts a PrettyMIDI instance of all the merged drum tracks from the given MIDI path. :param midi_path: the path to the MIDI file :return: the PrettyMIDI instance of the merged drum tracks """ os.makedirs(args.path_output_dir, exist_ok=True) pm = PrettyMIDI(midi_path) pm_drums = copy.deepcopy(pm) pm_drums.instruments = [ instrument for instrument in pm_drums.instruments if instrument.is_drum ] if len(pm_drums.instruments) > 1: # Some drum tracks are split, we can merge them drums = Instrument(program=0, is_drum=True) for instrument in pm_drums.instruments: for note in instrument.notes: drums.notes.append(note) pm_drums.instruments = [drums] if len(pm_drums.instruments) != 1: raise Exception(f"Invalid number of drums {midi_path}: " f"{len(pm_drums.instruments)}") return pm_drums
def convert_midi_files(): """Save a multi-track piano-roll converted from a MIDI file to target dataset directory and update MIDI information to `midi_dict`""" converter_root_dir = 'E:/MIDI_converted' root_dir = 'E:/free_MIDI' midi_collection = get_midi_collection() for midi in midi_collection.find({'Converted': False}): genre = midi['Genre'] name = midi['Name'] performer = midi['Performer'] filepath = root_dir + '/' + genre + '/' + name + ' - ' + performer + '.mid' try: midi_name = os.path.splitext(os.path.basename(filepath))[0] multitrack = Multitrack(beat_resolution=24, name=midi_name) pm = PrettyMIDI(filepath) midi_info = get_midi_info(pm) multitrack = Multitrack(filepath) merged = get_merged(multitrack) os.chdir(converter_root_dir) if not os.path.exists(converter_root_dir + '/' + genre): os.mkdir(converter_root_dir + '/' + genre) converter_path = converter_root_dir + '/' + genre + '/' + midi_name + '.npz' # merged.save(converter_path) print(get_midi_info(pm)) ''' midi_collection.update_one( {'_id', midi['_id']}, {'$set' :{'Converted': True}} ) ''' # print([midi_name, midi_info]) except: print(filepath) print(traceback.format_exc())
def array_to_pm(array, fs=DEFAULT_FS, velocity=DEFAULT_VELOCITY, pitch_range=DEFAULT_PITCH_RANGE): pm = PrettyMIDI() inst = Instrument(1) pm.instruments.append(inst) last_notes = {} last_state = np.zeros(array.shape[1]) > 0.5 for i, step in enumerate(array): now = i / fs step = step > 0.5 changed = step != last_state for pitch in np.where(changed)[0]: if step[pitch]: last_notes[pitch] = Note(velocity, pitch + pitch_range.start, now, None) inst.notes.append(last_notes[pitch]) else: last_notes[pitch].end = now del last_notes[pitch] last_state = step now = (i + 1) / fs for note in last_notes.values(): note.end = now return pm
def to_midi(self, tempo=120, instrument=PIANO, tonic=None, lib=None): if not self.progression: Logging.error("Progression not assigned!") return None if not tonic: tonic = self.meta['tonic'] midi = PrettyMIDI() unit_length = 30 / tempo ins = Instrument(instrument) if not self.saved_in_source_base: current_pos = 0 for i in self.get_chord_progression(): memo = -1 length = 0 for j in i: if j == memo: length += unit_length else: if memo != -1: for pitch in memo.to_midi_pitch( tonic=self.__key_changer( self.meta['tonic'], memo.root, tonic)): note = Note(pitch=pitch, velocity=80, start=current_pos, end=current_pos + length) ins.notes.append(note) current_pos += length length = unit_length memo = j for pitch in memo.to_midi_pitch(tonic=self.__key_changer( self.meta['tonic'], memo.root, tonic)): note = Note(pitch=pitch, velocity=80, start=current_pos, end=current_pos + length) ins.notes.append(note) current_pos += length else: if lib is None: lib = pickle_read('lib') try: all_notes = lib[self.meta['source']] except: Logging.error( 'Progression with source name {n} ' 'cannot be find in library! ' 'Call set_in_lib(in_lib=False) to generate MIDI ' 'by progression list itself'.format(n=self.meta['source'])) return False for note in all_notes: ins.notes.append( Note(start=note[0] * unit_length, end=note[1] * unit_length, pitch=note[2] + str_to_root[tonic], velocity=note[3])) midi.instruments.append(ins) return midi
def extract_drums(msd_id: str) -> Optional[PrettyMIDI]: """ Extracts a PrettyMIDI instance of all the merged drum tracks from the given MSD id. :param msd_id: the MSD id :return: the PrettyMIDI instance of the merged drum tracks """ os.makedirs(args.path_output_dir, exist_ok=True) midi_md5 = get_matched_midi_md5(msd_id, MSD_SCORE_MATCHES) midi_path = get_midi_path(msd_id, midi_md5, args.path_dataset_dir) pm = PrettyMIDI(midi_path) pm_drums = copy.deepcopy(pm) pm_drums.instruments = [instrument for instrument in pm_drums.instruments if instrument.is_drum] if len(pm_drums.instruments) > 1: # Some drum tracks are split, we can merge them drums = Instrument(program=0, is_drum=True) for instrument in pm_drums.instruments: for note in instrument.notes: drums.notes.append(note) pm_drums.instruments = [drums] if len(pm_drums.instruments) != 1: raise Exception(f"Invalid number of drums {msd_id}: " f"{len(pm_drums.instruments)}") return pm_drums
def listen_pitches(midi_pitch: list, time, instrument=0): midi = PrettyMIDI() ins = Instrument(instrument) for i in midi_pitch: ins.notes.append(Note(pitch=i, start=0, end=time, velocity=80)) midi.instruments.append(ins) listen(midi)
def write_midi(self, score_events, midi_program, pitch_low_passband=0, pitch_high_passband=127, time_offset=0.0): """ Given a sequence of NoteEvents, calculate the MIDI ticks for each note and write these to a MIDI file. PARAMETERS: score_events (list): list of ScoreEvents midi_program (int): MIDI program to use for the MIDI track pitch_low_passband (int): discard any pitches with midi numbers less than this bound pitch_high_passband (int): discard any pitches with midi numbers greater than this bound time_offset (float): amount of time (s) to delay MIDI note events """ midi = PrettyMIDI(resolution=MidiIO.DEFAULT_PPQ, initial_tempo=MidiIO.DEFAULT_TEMPO) instr = Instrument(program=midi_program) for e in score_events: for n in e.underlying_events(): if pitch_low_passband <= n.midi_number <= pitch_high_passband: note = MidiNote(velocity=MidiIO.DEFAULT_VELOCITY, pitch=n.midi_number, start=(n.onset_ts + time_offset), end=(n.offset_ts + time_offset)) instr.notes.append(note) midi.instruments.append(instr) midi.remove_invalid_notes() directory = os.path.split(self._path)[0] if not os.path.exists(directory): os.makedirs(directory) midi.write(self._path)
def to_midi(self, program=DEFAULT_SAVING_PROGRAM, resolution=DEFAULT_RESOLUTION, tempo=DEFAULT_TEMPO): midi = PrettyMIDI(resolution=resolution, initial_tempo=tempo) inst = Instrument(program, False, 'NoteSeq') inst.notes = copy.deepcopy(self.notes) midi.instruments.append(inst) return midi
def extract_pianos(msd_id: str) -> List[PrettyMIDI]: """ Extracts a list of PrettyMIDI instance of all the separate piano tracks from the given MSD id. :param msd_id: the MSD id :return: the list of PrettyMIDI instances of the separate piano tracks """ os.makedirs(args.path_output_dir, exist_ok=True) midi_md5 = get_matched_midi_md5(msd_id, MSD_SCORE_MATCHES) midi_path = get_midi_path(msd_id, midi_md5, args.path_dataset_dir) pm = PrettyMIDI(midi_path) pm.instruments = [ instrument for instrument in pm.instruments if instrument.program in PIANO_PROGRAMS and not instrument.is_drum ] pm_pianos = [] if len(pm.instruments) > 1: for piano_instrument in pm.instruments: pm_piano = copy.deepcopy(pm) pm_piano_instrument = Instrument(program=piano_instrument.program) pm_piano.instruments = [pm_piano_instrument] for note in piano_instrument.notes: pm_piano_instrument.notes.append(note) pm_pianos.append(pm_piano) else: pm_pianos.append(pm) for index, pm_piano in enumerate(pm_pianos): if len(pm_piano.instruments) != 1: raise Exception(f"Invalid number of piano {msd_id}: " f"{len(pm_piano.instruments)}") if pm_piano.get_end_time() > 1000: raise Exception(f"Piano track too long {msd_id}: " f"{pm_piano.get_end_time()}") return pm_pianos
def midi_to_list(filename: str, start_time: float, duration: float) -> List[int]: pm = PrettyMIDI(filename) pm.adjust_times(np.array([start_time, start_time + duration]), np.array([0., duration])) # ensure one midi contain only on instrument note_seq = NoteSeq(notes=pm.instruments[0].notes) event_seq = EventSeq.from_note_seq(note_seq) return event_seq.to_list()
def __init__(self, path): pm = PrettyMIDI(path) pm.remove_invalid_notes() self.midi = pm self.tempo = pm.estimate_tempo() self.beat_times = pm.get_beats() self.bar_times = pm.get_downbeats() self.end_time = pm.get_end_time() self.instruments = pm.instruments
def get_midi_file_list(self): midi_list = [] for root, dirs, files in os.walk(self._midi_dir): for file in files: if fnmatch.fnmatch(file, "*.mid"): midi_filename = os.path.join(root, file) pretty_midi = PrettyMIDI(midi_filename) midi_list.append(pretty_midi) return midi_list
def all_midi(f, key=None): midi = PrettyMIDI(f) fname = f.split(os.path.sep)[-1] n = len(midi.instruments) for ind, instrument in enumerate(midi.instruments): # sound instrument.program = mainSound if n == len(volumes): instrument.control_changes.append( ControlChange(number=7, value=volumes[ind], time=0.001)) midi.write(os.path.join(outdir, fname.rsplit(".", 1)[0] + "_all.mid"))
def __init__(self, midi_path='', phrase=None, meta=None, note_shift=0, **kwargs): try: self.midi_path = None self.note_shift = note_shift self.midi = PrettyMIDI(midi_path) self.melo = self.midi.instruments[0] except: self.midi_path = midi_path self.melo = self.__load_pop909_melo() self.meta = meta self.phrase = phrase
def write_midi(note_sequence, output_dir, filename): #make output directory pathlib.Path(output_dir).mkdir(parents=True, exist_ok=True) #generate midi midi = PrettyMIDI() piano_track = Instrument(program=0, is_drum=False, name=filename) piano_track.notes = note_sequence midi.instruments.append(piano_track) output_name = output_dir + f"{filename}.midi" midi.write(output_name)
def pitch_lists_to_midi_file(pitch_lists, midi_path): midi = PrettyMIDI() ins = Instrument(0) cursor = 0 unit_length = 0.125 for pitch_list in pitch_lists: for pitch in pitch_list: if pitch != 0: ins.notes.append(Note(start=cursor, end=cursor + unit_length, pitch=pitch, velocity=60)) cursor += unit_length midi.instruments.append(ins) midi.write(midi_path)
def section(pm, start, end, index=None, exclude_drum=False): section_midi = PrettyMIDI() for i, instrument in enumerate(pm.instruments): if exclude_drum and instrument.is_drum: continue if index != None and i not in index: continue section_instrument = pretty_midi.Instrument(instrument.program) section_instrument.notes = [ note for note in instrument.notes if start <= note.end < end ] section_midi.instruments.append(section_instrument) return section_midi
def test_encode_decode(): mid_seq = MidiSequencer.from_file(PrettyMIDI("audio/rock.mid")) encoded = mid_seq.encode() decoded = MidiSequencer.decode(encoded) for mid_row, decoded_row in zip(mid_seq.pattern, decoded.pattern): for mid_note, decoded_note in zip(mid_row, decoded_row): if mid_note is None and decoded_note is None: assert mid_note is None assert decoded_note is None else: assert mid_note.pitch == decoded_note.pitch assert mid_note.start == decoded_note.start
def read_midi(filename: str, start_time: float, duration: float) -> PrettyMIDI: """ :param filename: :param start_time: in seconds :param duration: in seconds :return: """ pm = PrettyMIDI(filename) pm.adjust_times([start_time, start_time + duration], [0., duration]) return pm
def convert_midi_to_image(url): file = requests.get(url) open('input.mid', 'wb').write(file.content) pm = PrettyMIDI("input.mid") preset = Preset(plot_width=1000, plot_height=500) plotter = Plotter(preset=preset) plotter.save(pm, 'imageHtml.html') hti = Html2Image() hti.screenshot(html_file='imageHtml.html', save_as='image.png', size=(1000, 500)) return discord.File( r'image.png') if os.path.getsize('image.png') <= 16000000 else None
def read_one_midi_and_cut(filename, output, cut_length=16): data = PrettyMIDI(filename) notes = [] for track in data.instruments: notes += track.notes notes = sorted(notes, key=lambda note: note.start) #print(notes) end_time = 0 for note in reversed(notes): if note.end > end_time: end_time = note.end start_time = 0 end_time = max(0, end_time - cut_length) import random cut_start_time = random.uniform(start_time, end_time) cut_end_time = cut_start_time + cut_length print('%s: start=%.1f, end=%.1f' % (filename, cut_start_time, cut_end_time)) midi_length = len(notes) for i in reversed(range(midi_length)): if notes[i].start < cut_start_time or\ notes[i].start > cut_end_time: del notes[i] elif notes[i].end > cut_end_time: notes[i].end = cut_end_time for note in notes: note.start -= cut_start_time note.end -= cut_start_time midi_file = PrettyMIDI(resolution=220, initial_tempo=120) track = Instrument(0) track.notes = notes midi_file.instruments.append(track) midi_file.write(output)
def piano_roll2midi(piano_roll, fs=SAMPLE_RATE): frames, notes = piano_roll.shape pm = PrettyMIDI() instrument_program = instrument_name_to_program('Acoustic Grand Piano') instrument = Instrument(program=instrument_program) piano_roll = np.pad(piano_roll, [(0, 0), (1, 1)], 'constant') velocity_changes = np.nonzero(np.diff(piano_roll)) print(velocity_changes) print(*velocity_changes[0]) print(np.array(velocity_changes).shape) prev_velocities = np.zeros(notes, dtype=int) note_on_time = np.zeros(notes)
def read_midi_pretty_midi(path: Union[str, Path]) -> Music: """Read a MIDI file into a Music object using pretty_midi as backend. Parameters ---------- path : str or Path Path to the MIDI file to read. Returns ------- :class:`muspy.Music` object Converted Music object. """ music = from_pretty_midi(PrettyMIDI(str(path))) music.metadata.source_filename = Path(path).name return music
def read(path: Union[str, Path], **kwargs) -> Multitrack: """Read a MIDI file into a Multitrack object. Parameters ---------- path : str or Path Path to the file to read. **kwargs Keyword arguments to pass to :func:`pypianoroll.from_pretty_midi`. See Also -------- :func:`pypianoroll.write` : Write a Multitrack object to a MIDI file. :func:`pypianoroll.load` : Load a NPZ file into a Multitrack object. """ return from_pretty_midi(PrettyMIDI(str(path)), **kwargs)
def get_instrument_classes(msd_id) -> Optional[list]: """ Returns the list of instruments classes given by PrettyMIDI for the MSD id. :param msd_id: the MSD id :return: the list of instruments classes """ midi_md5 = get_matched_midi_md5(msd_id, MSD_SCORE_MATCHES) midi_path = get_midi_path(msd_id, midi_md5, args.path_dataset_dir) pm = PrettyMIDI(midi_path) classes = [ program_to_instrument_class(instrument.program) for instrument in pm.instruments if not instrument.is_drum ] drums = ["Drums" for instrument in pm.instruments if instrument.is_drum] classes = classes + drums if not classes: raise Exception(f"No program classes for {msd_id}: " f"{len(classes)}") return classes
def tokens2midi(self, tokens): """ Игнорирование токенов педали :param tokens: :return: """ midi = PrettyMIDI() program = pretty_midi.instrument_name_to_program('Acoustic Grand Piano') piano = Instrument(program=program) velocity = 0 t = 0 pitch2start = {} pitch2end = {} pitch2velocity = {} for token in tokens: if token.startswith("PEDAL"): continue value = int(token.split("_")[-1]) if token.startswith("SET_VELOCITY"): velocity = value if token.startswith("TIME_SHIFT"): t += value pitch2end = {k: v + value for k, v in pitch2end.items()} if token.startswith("NOTE_ON"): pitch2start[value] = t pitch2end[value] = t pitch2velocity[value] = velocity if token.startswith("NOTE_OFF"): if value in pitch2start: start = pitch2start.pop(value) end = pitch2end.pop(value) if end > start: note = Note( velocity=self._bin2velocity(pitch2velocity.pop(value)), pitch=value, start=start / 1000, end=end / 1000 ) piano.notes.append(note) midi.instruments.append(piano) return midi