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 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 melo_to_midi(melo, tonic='C', unit=0.125): # ins = Instrument(program=0) # cursor = 0 # for i in melo: # root = major_map_backward[i] # if root != -1: # pitch = root_to_pitch[root] # ins.notes.append(Note(start=cursor, end=cursor + 0.125, pitch=pitch, velocity=60)) # cursor += 0.125 ins = Instrument(program=0) current_pitch = MIDILoader.__melo_number_to_pitch(melo[0]) start = 0 for i in range(len(melo)): if i == len(melo) - 1: note = Note(pitch=current_pitch, velocity=80, start=start * unit, end=(i + 1) * 0.125) ins.notes.append(note) break if melo[i + 1] != melo[i]: if current_pitch is not 0: note = Note(pitch=current_pitch, velocity=80, start=start * unit, end=(i + 1) * 0.125) ins.notes.append(note) current_pitch = MIDILoader.__melo_number_to_pitch(melo[i + 1]) start = i + 1 return ins
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 __construct_midi(self): final_progression_list = [] for i in range(len(self.progression_lib_filtered)): if len(self.progression_lib_filtered[i]) == 0: final_progression_list.append( max(self.progression_lib[i], key=lambda x: x.reliability)) else: final_progression_list.append( random.choice(self.progression_lib_filtered[i])) ins = Instrument(program=0) note_list = [] shift_count = 0 log = [] for progression in final_progression_list: log.append(self.__info(progression)) temp_midi = progression.to_midi(lib=self.midi_lib, tempo=self.meta['tempo'], tonic=self.meta['tonic']) temp_midi = midi_shift(temp_midi, shift=shift_count + self.note_shift, tempo=self.meta['tempo']) note_list += temp_midi.instruments[0].notes shift_count += len(progression) * 2 note_list = self.__smooth_notes(note_list) ins.notes += note_list return ins, log
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 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 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 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 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_pretty_midi_instrument(track: Track) -> Instrument: """Return a Track object as a pretty_midi Instrument object.""" instrument = Instrument(program=track.program, is_drum=track.is_drum, name=track.name) for note in track.notes: instrument.notes.append(to_pretty_midi_note(note)) return instrument
def nmat2ins(nmat, program=0, tempo=120, sixteenth_notes_in_bar=16) -> Instrument: ins = Instrument(program=program) snib = sixteenth_notes_in_bar unit_length = (60 / tempo) / 4 for note in nmat: midi_note = Note(pitch=note[0], velocity=note[1], start=(note[2][0] - 1) * unit_length * snib + note[2][1] * unit_length, end=(note[3][0] - 1) * unit_length * snib + note[3][1] * unit_length + 0.05) ins.notes.append(midi_note) return ins
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 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 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 __load_pop909_melo(self): pop909_loader = MIDILoader(files='POP909') pitch_list = pop909_loader.get_full_midi_ins_from_pop909(index=self.midi_path, change_key_to='C') ins = Instrument(program=0) current_pitch = pitch_list[0] start = 0 for i in range(len(pitch_list)): if i == len(pitch_list) - 1: note = Note(pitch=current_pitch, velocity=80, start=start * 0.125, end=(i + 1) * 0.125) ins.notes.append(note) break if pitch_list[i + 1] != pitch_list[i]: if current_pitch != 0: note = Note(pitch=current_pitch, velocity=80, start=start * 0.125, end=(i + 1) * 0.125) ins.notes.append(note) current_pitch = pitch_list[i + 1] start = i + 1 return ins
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
def save_cleaned_instrument(instrument: Instrument): """ Save the instrument as a standalone midi file in the cleaned directory This function also removes long pauses in the new tracks to compensate for instruments that only play in a small part of the original song """ try: # Create dummy midi = pretty_midi.PrettyMIDI(initial_tempo=80) midi.instruments.append(Instrument(program=instrument.program)) # Adjust timing: Removes all pauses longer than 1 second max_pause = 1 # in seconds (float) original_notes: List[pretty_midi.Note] = pm.instruments[0].notes original_times = [] new_times = [] last_end = 0 shift = 0 for note in original_notes: original_times.append(note.start) # Check timings if note.start > last_end + max_pause: # Pause is too long! adjust timing by shifting left diff = note.start - last_end shift += diff - max_pause new_times.append(note.start - shift) last_end = note.end # Synthesize midi.adjust_times(original_times, new_times) midi.synthesize() # Save filename = f"file{file_id}-ins{i}-notes{len(midi.instruments[0].notes)}-pitch{len(midi.instruments[0].pitch_bends)}-controls{len(midi.instruments[0].control_changes)}" print(f"\t\tSaving instrument: {filename}") midi.write( f"{output_dir}/{filename}-ori_len{int(last_end)}-new_len{int(last_end-shift)}.mid" ) except Exception as e: print(f"Exception while cleaning instrument: {str(e)}")
def dump_midi(data, note_sets, path): midi_file = PrettyMIDI(resolution=220, initial_tempo=120) track = Instrument(0) time = 0 # Shift first timing to 0 #time -= note_sets['timing'][data[0][0]] * 30 for note in data: # <padding> == 0 if note[0] == 0: continue time += note_sets['timing'][note[0]] * 15 / 120 track.notes.append( Note(velocity=100, start=time, end=time + note_sets['duration'][note[1]] * 15 / 120, pitch=note_sets['pitch'][note[2]])) #print(track.notes[-1]) midi_file.instruments.append(track) midi_file.write(path)
def write_to_midi(note_sequences, output_dir, n_to_write=None): if len(note_sequences) == 0: print("No note sequences to write out...") return #number of sequences to write out as MIDI files if n_to_write is None: n_to_write = len(note_sequences) #make the output directory if it doesn't already exist pathlib.Path(output_dir).mkdir(parents=True, exist_ok=True) for i in range(n_to_write): #for note_sequence in note_sequences: midi = PrettyMIDI(initial_tempo=80) piano = Instrument(program=0, is_drum=False, name="test{}".format(i)) piano.notes = note_sequences[i] midi.instruments.append(piano) output_name = output_dir + "/test{}.midi".format(i) #with open(output_name, 'w') midi.write(output_name) print("Piano data successfully extracted from midis, navigate to {} to listen"\ .format(output_dir))
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 create_midi(title, data, instrument_name='Acoustic Grand Piano', treshold=0.6): # Create a PrettyMIDI object song = PrettyMIDI() # Create an Instrument instance for a cello instrument instrument_program = instrument_name_to_program(instrument_name) instrument = Instrument(program=instrument_program) # Iterate over all note probabilities for sec in range(len(data)): # Iterate over all notes for note_number in range(NOTE_RANGE): if data[note_number] > treshold: # Create a Note instance for this note, starting at 0s and ending at .5s note = Note(velocity=100, pitch=note_number, start=0, end=.5) # Add it to our cello instrument instrument.notes.append(note) # Add the cello instrument to the PrettyMIDI object title.instruments.append(instrument) # Write out the MIDI data title.write('{}.mid'.format(title))
def to_wave(self, instrument, font=None, stereo=False, rate=44100, mono_dim2=False, clip=True): # find default soundfont if needed if font is None: font = default_path('TimGM6mb.sf2') assert 0 <= instrument and instrument < 128 # 1.create midi file from pretty_midi import PrettyMIDI, Instrument, Note midi = PrettyMIDI(resolution=960, initial_tempo=self.tempo) inst = Instrument(instrument) reso = 60 / self.tempo * 4 / self.beat for i, ns in enumerate(self.notes): for n in ns: inst.notes.append( Note(velocity=100, pitch=n, start=i * reso, end=i * reso + reso)) midi.instruments.append(inst) midi.write('temp.mid') # 2.create wave file from midi2audio import FluidSynth fs = FluidSynth(font, sample_rate=rate) fs.midi_to_audio('temp.mid', 'temp.wav') # 3.import wav file from scipy.io import wavfile _, wave = wavfile.read('temp.wav') # clip if clip: le = len(self.notes) wave = wave[:int(rate * reso * le)] wave = wave.astype(float) / abs(wave).max() * 0.9 return wave
def tokens2midi(self, tokens: List[str]) -> PrettyMIDI: midi = PrettyMIDI() program = instrument_name_to_program('Acoustic Grand Piano') piano = Instrument(program=program) velocity = 0 t = 0 pitch2start = {} pitch2end = {} pitch2velocity = {} n_tokens = len(tokens) for i in range(n_tokens): tok_i = tokens[i] value = int(tok_i.split("_")[-1]) if tok_i.startswith("SET_VELOCITY"): velocity = value elif tok_i.startswith("TIME_SHIFT"): t += value pitch2end = {k: v + value for k, v in pitch2end.items()} elif tok_i.startswith("NOTE_ON"): pitch2start[value] = t pitch2end[value] = t pitch2velocity[value] = velocity elif tok_i.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
def create_beat( self, samples: Dict[float, NDArray[Float32]] = None, sample_rate: int = 44100, ) -> AudioFile: """ Create a beat from the pattern in the sequencer. """ if samples is not None: raise ValueError( "Samples are not needed to create a beat for an MidiSequencer!" ) mid = PrettyMIDI(initial_tempo=self.bpm) drum_track = Instrument(program=0, is_drum=True, name="drums") mid.instruments.append(drum_track) for row in self.pattern: for note in row: if note is not None: drum_track.notes.append(note) return AudioFile( np.array(mid.fluidsynth(fs=sample_rate), dtype=np.float32), self.bpm, sample_rate, )
def to_pretty_midi( multitrack: "Multitrack", default_tempo: float = None, default_velocity: int = DEFAULT_VELOCITY, ) -> PrettyMIDI: """Return a Multitrack object as a PrettyMIDI object. Parameters ---------- default_tempo : int, default: `pypianoroll.DEFAULT_TEMPO` (120) Default tempo to use. If attribute `tempo` is available, use its first element. default_velocity : int, default: `pypianoroll.DEFAULT_VELOCITY` (64) Default velocity to assign to binarized tracks. Returns ------- :class:`pretty_midi.PrettyMIDI` Converted PrettyMIDI object. Notes ----- - Tempo changes are not supported. - Time signature changes are not supported. - The velocities of the converted piano rolls will be clipped to [0, 127]. - Adjacent nonzero values of the same pitch will be considered a single note with their mean as its velocity. """ if default_tempo is not None: tempo = default_tempo elif multitrack.tempo is not None: tempo = float(scipy.stats.hmean(multitrack.tempo)) else: tempo = DEFAULT_TEMPO # Create a PrettyMIDI instance midi = PrettyMIDI(initial_tempo=tempo) # Compute length of a time step time_step_length = 60.0 / tempo / multitrack.resolution for track in multitrack.tracks: instrument = Instrument( program=track.program, is_drum=track.is_drum, name=track.name ) if isinstance(track, BinaryTrack): processed = track.set_nonzeros(default_velocity) elif isinstance(track, StandardTrack): copied = deepcopy(track) processed = copied.clip() else: raise ValueError( f"Expect BinaryTrack or StandardTrack, but got {type(track)}." ) clipped = processed.pianoroll.astype(np.uint8) binarized = clipped > 0 padded = np.pad(binarized, ((1, 1), (0, 0)), "constant") diff = np.diff(padded.astype(np.int8), axis=0) positives = np.nonzero((diff > 0).T) pitches = positives[0] note_ons = positives[1] note_on_times = time_step_length * note_ons note_offs = np.nonzero((diff < 0).T)[1] note_off_times = time_step_length * note_offs for idx, pitch in enumerate(pitches): velocity = np.mean(clipped[note_ons[idx] : note_offs[idx], pitch]) note = pretty_midi.Note( velocity=int(velocity), pitch=pitch, start=note_on_times[idx], end=note_off_times[idx], ) instrument.notes.append(note) instrument.notes.sort(key=attrgetter("start")) midi.instruments.append(instrument) return midi
def test_dataset_hook_slakh(benchmark_audio): # make a fake slakh directory. band = {"guitar": [30, 31], "drums": [127]} only_guitar = {"guitar": [30, 31]} empty = {} bad = {"guitar": [30], "guitar_2": [30]} with tempfile.TemporaryDirectory() as tmpdir: track_dir = os.path.join(tmpdir, "Track") os.mkdir(track_dir) # Create Metadata file metadata = "audio_dir: stems" metadata += "\nmidi_dir: MIDI" metadata += "\nstems:" metadata += "\n S00:" metadata += "\n program_num: 30" metadata += "\n S01:" metadata += "\n program_num: 127" metadata += "\n S02:" metadata += "\n program_num: 30" metadata += "\n S03:" metadata += "\n program_num: 30" metadata_path = os.path.join(track_dir, "metadata.yaml") metadata_file = open(metadata_path, "w") metadata_file.write(metadata) metadata_file.close() stems_dir = os.path.join(track_dir, "stems") midi_dir = os.path.join(track_dir, "MIDI") os.mkdir(stems_dir) os.mkdir(midi_dir) # Note: These aren't actually guitar and drums guitar_path1 = os.path.join(stems_dir, "S00.wav") guitar_path2 = os.path.join(stems_dir, "S02.wav") guitar_path3 = os.path.join(stems_dir, "S03.wav") drums_path = os.path.join(stems_dir, "S01.wav") mix_path = os.path.join(track_dir, "mix.wav") # making midi objects midi_0 = PrettyMIDI() midi_1 = PrettyMIDI() guitar = Instrument(30, name="guitar") guitar.notes = [Note(70, 59, 0, 1)] drum = Instrument(127, is_drum=True, name="drum") drum.notes = [Note(40, 30, 0, 1)] midi_0.instruments.append(guitar) midi_1.instruments.append(drum) midi_0.write(os.path.join(midi_dir, "S00.mid")) midi_1.write(os.path.join(midi_dir, "S01.mid")) midi_0.write(os.path.join(midi_dir, "S02.mid")) midi_0.write(os.path.join(midi_dir, "S03.mid")) midi_mix = PrettyMIDI() midi_mix.instruments += [guitar, drum] midi_mix.write(os.path.join(track_dir, "all_src.mid")) # Move them within directory shutil.copy(benchmark_audio['K0140.wav'], guitar_path1) shutil.copy(benchmark_audio['K0149.wav'], drums_path) # Make a mix from them. guitar_signal = nussl.AudioSignal(path_to_input_file=guitar_path1) drums_signal = nussl.AudioSignal(path_to_input_file=drums_path) guitar_signal.truncate_seconds(2) drums_signal.truncate_seconds(2) mix_signal = guitar_signal + drums_signal mix_signal.write_audio_to_file(mix_path) drums_signal.write_audio_to_file(drums_path) guitar_signal.write_audio_to_file(guitar_path1) guitar_signal.write_audio_to_file(guitar_path3) guitar_signal.write_audio_to_file(guitar_path2) # now that our fake slakh has been created, lets try some mixing band_slakh = nussl.datasets.Slakh(tmpdir, band, midi=True, make_submix=True, max_tracks_per_src=1) assert len(band_slakh) == 1 data = band_slakh[0] _mix_signal, _sources = data["mix"], data["sources"] assert np.allclose(mix_signal.audio_data, _mix_signal.audio_data) assert len(_sources) == 2 assert np.allclose(_sources["drums"].audio_data, drums_signal.audio_data) assert np.allclose(_sources["guitar"].audio_data, guitar_signal.audio_data) _midi_mix, _midi_sources = data["midi_mix"], data["midi_sources"] assert len(_midi_mix.instruments) == 2 assert len(_midi_sources) == 2 assert _midi_sources["guitar"][0].instruments[0].program == 30 assert _midi_sources["drums"][0].instruments[0].program == 127 band_slakh = nussl.datasets.Slakh(tmpdir, band, midi=True, make_submix=False) data = band_slakh[0] _mix_signal, _sources = data["mix"], data["sources"] assert isinstance(_sources["guitar"], list) assert len(_sources) == 2 assert len(_sources["guitar"]) == 3 assert len(_sources["drums"]) == 1 assert np.allclose( sum(_sources["guitar"]).audio_data, 3 * guitar_signal.audio_data) with pytest.raises(DataSetException): not_enough_instruments = nussl.datasets.Slakh( tmpdir, band, midi=True, make_submix=True, min_acceptable_sources=3) guitar_slakh = nussl.datasets.Slakh(tmpdir, only_guitar, make_submix=True, min_acceptable_sources=1, max_tracks_per_src=1) data = guitar_slakh[0] _guitar_signal, _sources = data["mix"], data["sources"] assert len(_sources) == 1 assert np.allclose(_sources["guitar"].audio_data, guitar_signal.audio_data) assert np.allclose(_guitar_signal.audio_data, guitar_signal.audio_data) with pytest.raises(DataSetException): empty_slakh = nussl.datasets.Slakh(tmpdir, empty, min_acceptable_sources=1) with pytest.raises(ValueError): nussl.datasets.Slakh(tmpdir, band, min_acceptable_sources=0) with pytest.raises(ValueError): nussl.datasets.Slakh(tmpdir, band, max_tracks_per_src=0) with pytest.raises(ValueError): bad_slakh = nussl.datasets.Slakh(tmpdir, bad)