def main(): parser = argparse.ArgumentParser(description=__doc__) parser.set_defaults(func=main) parser.add_argument('input_file', type=argparse.FileType('rb'), metavar='FILE') parser.add_argument('output_dir', type=str, metavar='OUTPUTDIR') parser.add_argument('-i', '--instrument', type=str, default='') parser.add_argument('--drums', action='store_true') parser.add_argument('-p', '--program', type=int) parser.add_argument('--stretch', type=str) parser.add_argument('--tempo', type=float) parser.add_argument('--time-signature', type=lambda s: tuple(int(x) for x in s.split('/')), default=(4, 4)) parser.add_argument('--resolution', type=int, default=480) parser.add_argument( '--range', type=lambda r: [None if x == '' else int(x) for x in r.split(':')]) parser.add_argument('--group-by-name', action='store_true') parser.add_argument('--time-unit', type=float) args = parser.parse_args() if args.program is None: if args.instrument: args.program = pretty_midi.instrument_name_to_program( args.instrument) else: args.program = 0 tempo = 60. if args.stretch: # Calculate the time stretch ratio if ':' in args.stretch: a, b = args.stretch.split(':') args.stretch = float(a) / float(b) tempo = float(b) else: args.stretch = float(args.stretch) tempo = tempo / args.stretch if args.tempo: tempo = args.tempo data = pickle.load(args.input_file) fill_length = len(str(len(data) - 1)) if args.range: data = data[slice(*args.range)] if args.group_by_name: grouped = collections.defaultdict(list) for (name, start, end), notes in data: start, end = start * args.time_unit, end * args.time_unit grouped[name].extend( _shift_and_clip(note, start, end) for note in notes if note.start + start < end and note.end > 0.) data = list(grouped.items()) for i, segment in enumerate(data): midi = pretty_midi.PrettyMIDI(initial_tempo=tempo, resolution=args.resolution) if args.range and args.range[0]: i += args.range[0] index = str(i).zfill(fill_length) if isinstance(segment, list): notes = segment fname = f'{index}.mid' elif isinstance(segment, tuple) and len(segment) == 2: segment_id, notes = segment if not isinstance(segment_id, str): segment_id = '_'.join(str(x) for x in segment_id) fname = f'{index}_{segment_id}.mid' else: raise RuntimeError(f'Cannot parse segment: {segment}') if args.stretch is not None: for note in notes: note.start *= args.stretch note.end *= args.stretch # Remove notes with length below the MIDI resolution notes = [ note for note in notes if midi.time_to_tick(note.start) < midi.time_to_tick(note.end) ] # Some notes might be overlapping, we need to split them between multiple tracks. # TODO: This calls for a more efficient implementation. tracks = [[]] for note in notes: for track in tracks: # Find the first track without an overlapping note. if not any(note2.pitch == note.pitch and note2.start < note.end and note2.end > note.start for note2 in track): track.append(note) break # Always keep the last track empty (we delete it afterwards) if tracks[-1]: tracks.append([]) del tracks[-1] midi.time_signature_changes[:] = [ pretty_midi.TimeSignature(*args.time_signature, 0.) ] for track in tracks: instrument = pretty_midi.Instrument(name=args.instrument, program=args.program, is_drum=args.drums) instrument.notes[:] = track midi.instruments.append(instrument) midi.write(os.path.join(args.output_dir, fname))
def sequence_proto_to_pretty_midi(sequence): """Convert tensorflow.magenta.NoteSequence proto to a PrettyMIDI. Time is stored in the NoteSequence in absolute values (seconds) as opposed to relative values (MIDI ticks). When the NoteSequence is translated back to PrettyMIDI the absolute time is retained. The tempo map is also recreated. Args: sequence: A tensorfow.magenta.NoteSequence proto. Returns: A pretty_midi.PrettyMIDI object or None if sequence could not be decoded. """ kwargs = {} if sequence.tempos and sequence.tempos[0].time == 0: kwargs['initial_tempo'] = sequence.tempos[0].bpm pm = pretty_midi.PrettyMIDI(resolution=sequence.ticks_per_beat, **kwargs) # Create an empty instrument to contain time and key signatures. instrument = pretty_midi.Instrument(0) pm.instruments.append(instrument) # Populate time signatures. for seq_ts in sequence.time_signatures: time_signature = pretty_midi.containers.TimeSignature( seq_ts.numerator, seq_ts.denominator, seq_ts.time) pm.time_signature_changes.append(time_signature) # Populate key signatures. for seq_key in sequence.key_signatures: key_number = seq_key.key if seq_key.mode == seq_key.MINOR: key_number += _PRETTY_MIDI_MAJOR_TO_MINOR_OFFSET key_signature = pretty_midi.containers.KeySignature( key_number, seq_key.time) pm.key_signature_changes.append(key_signature) # Populate tempo. The first tempo change was done in PrettyMIDI constructor. # TODO(@douglaseck): Update this code if pretty_midi adds the ability to # write tempo. if len(sequence.tempos) > 1: for seq_tempo in sequence.tempos[1:]: tick_scale = 60.0 / (pm.resolution * seq_tempo.bpm) tick = pm.time_to_tick(seq_tempo.time) # pylint: disable=protected-access pm._PrettyMIDI__tick_scales.append((tick, tick_scale)) # pylint: enable=protected-access # Populate instrument events by first gathering notes and other event types # in lists then write them sorted to the PrettyMidi object. instrument_events = defaultdict(lambda: defaultdict(list)) for seq_note in sequence.notes: instrument_events[(seq_note.instrument, seq_note.program)]['notes'].append( pretty_midi.Note(seq_note.velocity, seq_note.pitch, seq_note.start_time, seq_note.end_time)) for seq_bend in sequence.pitch_bends: instrument_events[(seq_bend.instrument, seq_bend.program)]['bends'].append( pretty_midi.PitchBend(seq_bend.bend, seq_bend.time)) for seq_cc in sequence.control_changes: instrument_events[(seq_cc.instrument, seq_cc.program)]['controls'].append( pretty_midi.ControlChange( seq_cc.control_number, seq_cc.control_value, seq_cc.time)) for (instr_id, prog_id) in sorted(instrument_events.keys()): # For instr_id 0 append to the instrument created above. if instr_id > 0: instrument = pretty_midi.Instrument(prog_id, is_drum=(instr_id == 9)) pm.instruments.append(instrument) instrument.program = prog_id instrument.notes = instrument_events[(instr_id, prog_id)]['notes'] instrument.pitch_bends = instrument_events[(instr_id, prog_id)]['bends'] instrument.control_changes = instrument_events[(instr_id, prog_id)]['controls'] return pm
def test_get_piano_roll_and_get_chroma(): pm = pretty_midi.PrettyMIDI() assert pm.get_piano_roll().shape == (128, 0) # Currently just a rudimentary test since it's hard to test things like # pitch bends correctly inst = pretty_midi.Instrument(0) pm.instruments.append(inst) inst.notes.append( pretty_midi.Note(pitch=40, velocity=100, start=0.05, end=0.45)) inst = pretty_midi.Instrument(0) pm.instruments.append(inst) inst.notes.append( pretty_midi.Note(pitch=40, velocity=50, start=0.35, end=0.5)) inst.notes.append( pretty_midi.Note(pitch=45, velocity=100, start=0.1, end=0.2)) inst = pretty_midi.Instrument(0) pm.instruments.append(inst) inst.control_changes.append( pretty_midi.ControlChange(number=64, value=65, time=0.12)) inst.control_changes.append( pretty_midi.ControlChange(number=64, value=63, time=0.5)) inst.notes.append( pretty_midi.Note(pitch=50, velocity=50, start=0.35, end=0.4)) inst.notes.append( pretty_midi.Note(pitch=55, velocity=20, start=0.1, end=0.15)) inst.notes.append( pretty_midi.Note(pitch=55, velocity=10, start=0.2, end=0.25)) inst.notes.append( pretty_midi.Note(pitch=55, velocity=50, start=0.3, end=0.42)) expected_piano_roll = np.zeros((128, 50)) expected_piano_roll[40, 5:35] = 100 expected_piano_roll[40, 35:45] = 150 expected_piano_roll[40, 45:] = 50 expected_piano_roll[45, 10:20] = 100 expected_piano_roll[50, 35:40] = 50 expected_piano_roll[55, 10:15] = 20 expected_piano_roll[55, 20:25] = 10 expected_piano_roll[55, 30:42] = 50 assert np.allclose(pm.get_piano_roll(pedal_threshold=None), expected_piano_roll) expected_piano_roll[50, 35:50] = 50 expected_piano_roll[55, 10:30] = 20 expected_piano_roll[55, 30:50] = 50 assert np.allclose(pm.get_piano_roll(), expected_piano_roll) expected_chroma = np.zeros((12, 50)) expected_chroma[4, 5:35] = 100 expected_chroma[4, 35:45] = 150 expected_chroma[4, 45:] = 50 expected_chroma[9, 10:20] = 100 expected_chroma[2, 35:40] = 50 expected_chroma[7, 10:15] = 20 expected_chroma[7, 20:25] = 10 expected_chroma[7, 30:42] = 50 assert np.allclose(pm.get_chroma(pedal_threshold=None), expected_chroma) expected_chroma[2, 35:50] = 50 expected_chroma[7, 10:30] = 20 expected_chroma[7, 30:50] = 50 assert np.allclose(pm.get_chroma(), expected_chroma)
def tx1_to_midi(tx1): import pretty_midi tx1 = tx1.strip().splitlines() nsamps = sum([int(x.split('_')[1]) for x in tx1 if x[:2] == 'WT']) # Create MIDI instruments p1_prog = pretty_midi.instrument_name_to_program('Lead 1 (square)') p2_prog = pretty_midi.instrument_name_to_program('Lead 2 (sawtooth)') tr_prog = pretty_midi.instrument_name_to_program('Synth Bass 1') no_prog = pretty_midi.instrument_name_to_program('Breath Noise') p1 = pretty_midi.Instrument(program=p1_prog, name='p1', is_drum=False) p2 = pretty_midi.Instrument(program=p2_prog, name='p2', is_drum=False) tr = pretty_midi.Instrument(program=tr_prog, name='tr', is_drum=False) no = pretty_midi.Instrument(program=no_prog, name='no', is_drum=True) name_to_ins = {'P1': p1, 'P2': p2, 'TR': tr, 'NO': no} name_to_pitch = {'P1': None, 'P2': None, 'TR': None, 'NO': None} name_to_start = {'P1': None, 'P2': None, 'TR': None, 'NO': None} name_to_max_velocity = {'P1': 15, 'P2': 15, 'TR': 1, 'NO': 15} samp = 0 for event in tx1: if event[:2] == 'WT': samp += int(event[3:]) else: tokens = event.split('_') name = tokens[0] ins = name_to_ins[tokens[0]] old_pitch = name_to_pitch[name] if tokens[1] == 'NOTEON': if old_pitch is not None: ins.notes.append(pretty_midi.Note( velocity=name_to_max_velocity[name], pitch=old_pitch, start=name_to_start[name] / 44100., end=samp / 44100.)) name_to_pitch[name] = int(tokens[2]) name_to_start[name] = samp else: if old_pitch is not None: ins.notes.append(pretty_midi.Note( velocity=name_to_max_velocity[name], pitch=name_to_pitch[name], start=name_to_start[name] / 44100., end=samp / 44100.)) name_to_pitch[name] = None name_to_start[name] = None # Deactivating this for generated files #for name, pitch in name_to_pitch.items(): # assert pitch is None # Create MIDI and add instruments midi = pretty_midi.PrettyMIDI(initial_tempo=120, resolution=22050) midi.instruments.extend([p1, p2, tr, no]) # Create indicator for end of song eos = pretty_midi.TimeSignature(1, 1, nsamps / 44100.) midi.time_signature_changes.append(eos) with tempfile.NamedTemporaryFile('rb') as mf: midi.write(mf.name) midi_str = mf.read() return midi, midi_str
def sequence_proto_to_pretty_midi(sequence, drop_events_n_seconds_after_last_note=None): """Convert tensorflow.magenta.NoteSequence proto to a PrettyMIDI. Time is stored in the NoteSequence in absolute values (seconds) as opposed to relative values (MIDI ticks). When the NoteSequence is translated back to PrettyMIDI the absolute time is retained. The tempo map is also recreated. Args: sequence: A tensorfow.magenta.NoteSequence proto. drop_events_n_seconds_after_last_note: Events (e.g., time signature changes) that occur this many seconds after the last note will be dropped. If None, then no events will be dropped. Returns: A pretty_midi.PrettyMIDI object or None if sequence could not be decoded. """ ticks_per_quarter = (sequence.ticks_per_quarter if sequence.ticks_per_quarter else constants.STANDARD_PPQ) max_event_time = None if drop_events_n_seconds_after_last_note is not None: max_event_time = (max([n.end_time for n in sequence.notes] or [0]) + drop_events_n_seconds_after_last_note) # Try to find a tempo at time zero. The list is not guaranteed to be in order. initial_seq_tempo = None for seq_tempo in sequence.tempos: if seq_tempo.time == 0: initial_seq_tempo = seq_tempo break kwargs = {} kwargs['initial_tempo'] = (initial_seq_tempo.qpm if initial_seq_tempo else constants.DEFAULT_QUARTERS_PER_MINUTE) pm = pretty_midi.PrettyMIDI(resolution=ticks_per_quarter, **kwargs) # Create an empty instrument to contain time and key signatures. instrument = pretty_midi.Instrument(0) pm.instruments.append(instrument) # Populate time signatures. for seq_ts in sequence.time_signatures: if max_event_time and seq_ts.time > max_event_time: continue time_signature = pretty_midi.containers.TimeSignature( seq_ts.numerator, seq_ts.denominator, seq_ts.time) pm.time_signature_changes.append(time_signature) # Populate key signatures. for seq_key in sequence.key_signatures: if max_event_time and seq_key.time > max_event_time: continue key_number = seq_key.key if seq_key.mode == seq_key.MINOR: key_number += _PRETTY_MIDI_MAJOR_TO_MINOR_OFFSET key_signature = pretty_midi.containers.KeySignature( key_number, seq_key.time) pm.key_signature_changes.append(key_signature) # Populate tempos. # TODO(douglaseck): Update this code if pretty_midi adds the ability to # write tempo. for seq_tempo in sequence.tempos: # Skip if this tempo was added in the PrettyMIDI constructor. if seq_tempo == initial_seq_tempo: continue if max_event_time and seq_tempo.time > max_event_time: continue tick_scale = 60.0 / (pm.resolution * seq_tempo.qpm) tick = pm.time_to_tick(seq_tempo.time) # pylint: disable=protected-access pm._tick_scales.append((tick, tick_scale)) pm._update_tick_to_time(0) # pylint: enable=protected-access # Populate instrument events by first gathering notes and other event types # in lists then write them sorted to the PrettyMidi object. instrument_events = defaultdict(lambda: defaultdict(list)) for seq_note in sequence.notes: instrument_events[(seq_note.instrument, seq_note.program, seq_note.is_drum)]['notes'].append( pretty_midi.Note(seq_note.velocity, seq_note.pitch, seq_note.start_time, seq_note.end_time)) for seq_bend in sequence.pitch_bends: if max_event_time and seq_bend.time > max_event_time: continue instrument_events[(seq_bend.instrument, seq_bend.program, seq_bend.is_drum)]['bends'].append( pretty_midi.PitchBend(seq_bend.bend, seq_bend.time)) for seq_cc in sequence.control_changes: if max_event_time and seq_cc.time > max_event_time: continue instrument_events[(seq_cc.instrument, seq_cc.program, seq_cc.is_drum)]['controls'].append( pretty_midi.ControlChange( seq_cc.control_number, seq_cc.control_value, seq_cc.time)) for (instr_id, prog_id, is_drum) in sorted(instrument_events.keys()): # For instr_id 0 append to the instrument created above. if instr_id > 0: instrument = pretty_midi.Instrument(prog_id, is_drum) pm.instruments.append(instrument) instrument.program = prog_id instrument.notes = instrument_events[(instr_id, prog_id, is_drum)]['notes'] instrument.pitch_bends = instrument_events[(instr_id, prog_id, is_drum)]['bends'] instrument.control_changes = instrument_events[(instr_id, prog_id, is_drum)]['controls'] return pm
import glob, os import pretty_midi out_midis, out_names = ([], []) os.chdir("../midi/piano_midi") for file in glob.glob("*.mid"): pm = pretty_midi.PrettyMIDI(file) filename = file.split('.mid')[0] print("Working on %s..." % filename) piano_midi = pretty_midi.PrettyMIDI( ) # Create the new monophonic midi file piano_program = pretty_midi.instrument_name_to_program( 'Acoustic Grand Piano') piano = pretty_midi.Instrument( program=piano_program) # Create a piano instrument pitch, onset, offset = (-1, -1, -1) pm.instruments[0].notes.sort(key=lambda x: x.start, reverse=False) for note in pm.instruments[ 0].notes: # Append the notes to the piano instrument if (note.start == onset): # If two notes start at the same time if (note.pitch > pitch): piano.notes[len(piano.notes) - 1] = note # Select the note with the higher pitch else: continue else: if (len(piano.notes) > 0 and note.start < offset): # If the previous note remains, piano.notes[len(piano.notes) -
def interpolation(args, model, dataset, fs=25, program=0): x_a, x_b = dataset[random.randint( 0, len(dataset) - 1)], dataset[random.randint(0, len(dataset) - 1)] x_a, x_b = x_a.to(args.device), x_b.to(args.device) # Encode samples to the latent space z_a, z_b = model.encode(x_a.unsqueeze(0)), model.encode(x_b.unsqueeze(0)) # Run through alpha values interp = [] alpha_values = np.linspace(0, 1, args.n_steps) for alpha in alpha_values: z_interp = (1 - alpha) * z_a[0] + alpha * z_b[0] interp.append(model.decode(z_interp)) # Draw interpolation step by step i = 0 stack_interp = [] for step in interp: if args.num_classes > 1: step = torch.argmax(step[0], dim=0) stack_interp.append(step) # plt.matshow(step.cpu().detach(), alpha=1) # plt.title("Interpolation " + str(i)) # plt.savefig(args.figures_path + "interpolation" + str(i) + ".png") # plt.close() i += 1 stack_interp = torch.cat(stack_interp, dim=1) # Draw stacked interpolation plt.figure() plt.matshow(stack_interp.cpu(), alpha=1) plt.title("Interpolation") plt.savefig(args.figures_path + "interpolation.png") plt.close() # Generate MIDI from interpolation pm = pretty_midi.PrettyMIDI() notes, frames = stack_interp.shape instrument = pretty_midi.Instrument(program=program) # Pad 1 column of zeros to acknowledge initial and ending events piano_roll = np.pad(stack_interp.cpu().detach(), [(0, 0), (1, 1)], 'constant') # Use changes in velocities to find note on/note off events velocity_changes = np.nonzero(np.diff(piano_roll).T) # Keep track on velocities and note on times prev_velocities = np.zeros(notes, dtype=int) note_on_time = np.zeros(notes) for time, note in zip(*velocity_changes): # Use time + 1s because of padding above velocity = piano_roll[note, time + 1] time = time / fs if velocity > 0: if prev_velocities[note] == 0: note_on_time[note] = time prev_velocities[note] = 75 else: pm_note = pretty_midi.Note(velocity=prev_velocities[note], pitch=note + args.min_pitch, start=note_on_time[note], end=time) instrument.notes.append(pm_note) prev_velocities[note] = 0 pm.instruments.append(instrument) # Write out the MIDI data pm.write(args.midi_results_path + "interpolation.mid")
except IOError: print("Could not open file ", est_file_name) exit() print("Transcription: Generating MIDI to ", out_file_name) est = np.loadtxt(est_file_name) t1 = est[:, 0].reshape((est.shape[0], )) t2 = est[:, 1].reshape((est.shape[0], )) f = est[:, 2].reshape((est.shape[0], )) # Create a PrettyMIDI object piano_chord = pretty_midi.PrettyMIDI() # Create an Instrument instance for a piano instrument piano_program = pretty_midi.instrument_name_to_program('Acoustic Grand Piano') piano = pretty_midi.Instrument(program=piano_program) # Iterate over note names, which will be converted to note number later for f_idx in range(f.shape[0]): # Retrieve the MIDI note number for this note name note_pitch = int(round(pretty_midi.hz_to_note_number(f[f_idx]))) if note_pitch > 127 or note_pitch < 0: print(note_pitch) input("OMG !!") note_pitch = 0 if note_pitch < 0 else 127 #note_number = pretty_midi.note_name_to_number(note_name) # Create a Note instance, starting at 0s and ending at .5s note = pretty_midi.Note(velocity=100, pitch=note_pitch, start=t1[f_idx], end=t2[f_idx]) # Add it to our cello instrument
sp = s[-2:] fixed_flats.append(sp) flat_free_tone_row = [s for s in tone_row if not ("/" in s)] flatty_tone_row = fixed_flats + flat_free_tone_row random_tone_row = random.sample(flatty_tone_row, len(flatty_tone_row)) main_list += random_tone_row numbered_list = [s + str(random.randint(0, 8)) for s in main_list] print(numbered_list) compo = pretty_midi.PrettyMIDI() compo_program = pretty_midi.instrument_name_to_program('Cello') compo_c = pretty_midi.Instrument(program=compo_program) start = 0 end = .5 for note_name in numbered_list: note_number = pretty_midi.note_name_to_number(note_name) note = pretty_midi.Note(velocity=random.randint(0, 100), pitch=note_number, start=start, end=end) compo_c.notes.append(note) start = random.randint(0, 1000) * 0.1 end = random.randint(1, 20) * 0.1 compo.instruments.append(compo_c)
def mainFunction(): tempo = randint(80, 160) beatLength = 60 / tempo print("Tempo: " + str(tempo) + " BPM") # randomly chooses key and scale scaleType = generateScale.scales[randrange(len(generateScale.scales))] keyChoice = generateScale.notes[randrange(len(generateScale.notes))] print("Key: " + keyChoice + " " + scaleType + "\n") # determines notes based on key and scale if scaleType == "Minor": scaleNotes = generateScale.minorScale(keyChoice) elif scaleType == "Major": scaleNotes = generateScale.majorScale(keyChoice) # creates the pretty_midi object pianoChords = pretty_midi.PrettyMIDI(initial_tempo=tempo) # sets the name based on MIDI standards piano_program = pretty_midi.instrument_name_to_program( "Acoustic Grand Piano") piano = pretty_midi.Instrument(program=piano_program) startTime = 0 previousNoteNumber = 0 chordProgressionRoots = [] for x in range(1, 5): chordProgressionRoots.append(scaleNotes[randrange(1, 7)]) chordDict = chordMaker.buildChord(chordProgressionRoots, scaleNotes) startTime = 0 for key, value in chordDict.items(): for note_name in value: nameWithoutOct = note_name lowestOctave = randint(3, 4) for x in range(lowestOctave, 6): # plays the notes in multiple octaves note_name = nameWithoutOct + str(x) note_number = pretty_midi.note_name_to_number(note_name) note = pretty_midi.note_name_to_number(note_name) velocity = randint(105, 127) delay = round( uniform(0, 0.05), 3 ) # generates a random amount of delay to make it sound more natural/realistic note = pretty_midi.Note(velocity=velocity, pitch=note_number, start=(startTime + delay), end=startTime + (4 * beatLength)) piano.notes.append(note) startTime += 4 * beatLength # each chord plays for 4 beats, which is equal to 1 measure since it's in 4/4 pianoChords.instruments.append(piano) pianoChords.write("chords.mid") # creates the pretty_midi object pianoMelody = pretty_midi.PrettyMIDI(initial_tempo=tempo) # sets the name based on MIDI standards piano_program = pretty_midi.instrument_name_to_program( "Acoustic Grand Piano") piano = pretty_midi.Instrument(program=piano_program) for x in range(0, 4): startTime = beatLength / 2 + (beatLength * x * 4 ) # makes it start at the next measure # ensures that it doesn't play after the new chord starts until supposed to: while startTime < (beatLength * 4 * (x + 1)): noteIndex = randrange(len(scaleNotes)) note_name = scaleNotes[noteIndex] + "5" note_number = pretty_midi.note_name_to_number(note_name) note = pretty_midi.note_name_to_number(note_name) velocity = randint(105, 127) delay = round( uniform(0, 0.05), 3 ) # generates a random amount of delay to make it sound more natural/realistic length = (beatLength / 2) * (randint(1, 4)) note = pretty_midi.Note(velocity=velocity, pitch=note_number, start=(startTime + delay), end=(startTime + length)) piano.notes.append(note) startTime += length pianoMelody.instruments.append(piano) pianoMelody.write("melody.mid") # synthesizes the MIDI using the soundfont system("fluidsynth -ni %s chords.mid -F chords.wav -r 44100 2>/dev/null" % chordSfDir) system("fluidsynth -ni %s melody.mid -F melody.wav -r 44100 2>/dev/null" % melodySfDir) chords = AudioSegment.from_wav("chords.wav") melody = AudioSegment.from_wav("melody.wav") mixed = chords.overlay(melody) return mixed
def arpeggiate_instrument(instrument, arpeggio_time): ''' Arpeggiate the notes of an instrument. Parameters ---------- inst : pretty_midi.Instrument Instrument object. arpeggio_time : float Time, in seconds, of each note in the arpeggio Returns ------- inst_arpeggiated : pretty_midi.Instrument Instrument with the notes arpeggiated. ''' # Make a copy of the instrument inst_arpeggiated = pretty_midi.Instrument(program=instrument.program, is_drum=instrument.is_drum) for bend in instrument.pitch_bends: inst_arpeggiated.pitch_bends.append(bend) n = 0 while n < len(instrument.notes): # Collect notes which are in this chord chord_notes = [(instrument.notes[n].pitch, instrument.notes[n].velocity)] m = n + 1 while m < len(instrument.notes): # It's in the chord if it starts before the current note ends if instrument.notes[m].start < instrument.notes[n].end: # Add in the pitch and velocity chord_notes.append( (instrument.notes[m].pitch, instrument.notes[m].velocity)) # Move the start time of the note up so it gets used next time if instrument.notes[m].end > instrument.notes[n].end: instrument.notes[m].start = instrument.notes[n].end m += 1 # Arpeggiate the collected notes time = instrument.notes[n].start pitch_index = 0 if len(chord_notes) > 2: while time < instrument.notes[n].end: # Get the pitch and velocity of this note, but mod the index # to circulate pitch, velocity = chord_notes[pitch_index % len(chord_notes)] # Add this note to the new instrument inst_arpeggiated.notes.append( pretty_midi.Note(velocity, pitch, time, time + arpeggio_time)) # Next pitch next time pitch_index += 1 # Move forward by the supplied amount time += arpeggio_time else: inst_arpeggiated.notes.append(instrument.notes[n]) time = instrument.notes[n].end n += 1 # Find the next chord while (n < len(instrument.notes) and instrument.notes[n].start + arpeggio_time <= time): n += 1 return inst_arpeggiated
def swap(): print(request.form) chord = json.loads(request.form['chd']) midi_in = request.form['midi_in'] chord_in = request.form['chd_in'] for c in chord: c[0] = int(c[0]) c[2] = int(c[2]) for i in range(len(c[1])): c[1][i] = (int(c[1][i]) + c[0]) % 12 chord = simpleChd_to_chd(chord) chd_mat_swapped = chord.tolist() chord_out = chd_to_str(chord) chord_in = chord_in[1:-1].replace("'", '').split(',') data = np.load('static/' + midi_in[:-3] + 'npz') pr_mat = data['pr_mat'] c_out = data['chord'] pr_mat = torch.from_numpy(pr_mat).float().to(device) chord = torch.from_numpy(chord).float().unsqueeze(0).to(device) c = torch.from_numpy(c_out).float().unsqueeze(0).to(device) print(pr_mat.shape, c.shape) for i in range(SAMPLE_LEN // 8): pr_mat_i = pr_mat[:, 32 * i:32 * i + 32, :] c_i = c[:, 8 * i:8 * i + 8, :] chord_i = chord[:, 8 * i:8 * i + 8, :] try: ptree_out_i = model.swap(pr_mat_i, pr_mat_i, c_i, chord_i, fix_rhy=True, fix_chd=False) pr_out_i, notes_out_i = model.decoder.grid_to_pr_and_notes( ptree_out_i.squeeze(0)) pr_out = np.concatenate((pr_out, pr_out_i), axis=0) for note in notes_out_i: notes_out.append( pretty_midi.Note(note.velocity, note.pitch, note.start + 8 * i, min([note.end + 8 * i, SAMPLE_LEN]))) except: ptree_out_i = model.swap(pr_mat_i, pr_mat_i, c_i, chord_i, fix_rhy=True, fix_chd=False) pr_out, notes_out = model.decoder.grid_to_pr_and_notes( ptree_out_i.squeeze(0)) for i in range(SAMPLE_LEN): notes_out.append(pretty_midi.Note(1, 30, i, i + 1)) out_midi = pretty_midi.PrettyMIDI() out_midi.instruments = [pretty_midi.Instrument(0)] out_midi.instruments[0].notes = notes_out midi_out = 'static/' + midi_in[:-4] + str( datetime.datetime.today()).replace("-", "").replace(" ", "").replace( ":", "").replace(".", "") + ".mid" out_midi.write(midi_out) return {"midi_out": midi_out, "chd_mat_swapped": chd_mat_swapped}
def output_midi_file_from_note_list( note_list, output_file_path, note_numerizer, sampling_frequency=common_config.SAMPLING_FREQUENCY_OUTPUT, start_idx=common_config.SLIDING_WINDOW_SIZE - 2, # start from the last note of the seed n_note_generate=common_config.N_NOTE_GENERATE): note_string_list = [ note_numerizer.note_string_by_number[num] for num in note_list ] # 0 at the start + last note of the seed + n_note_generate generated notes piano_roll = np.zeros((128, n_note_generate + 2), dtype=np.int8) # create the piano roll print('Create the piano roll') for time_idx, note_string in enumerate(note_string_list[start_idx:]): if note_string == common_config.SILENT_CHAR: continue splitted_note = note_string.split(',') for i in splitted_note: piano_roll[int(i)][time_idx] = 1 # create pretty_midi object from piano roll n_notes, n_time_frames = piano_roll.shape pretty_midi_obj = pretty_midi.PrettyMIDI() # channel 0 for piano instrument = pretty_midi.Instrument(program=0) piano_roll = np.pad(piano_roll, [(0, 0), (1, 1)], 'constant') velocity_changes = np.nonzero(np.diff(piano_roll).T) # keep track of velocity and note start time velocity_by_note = np.zeros(n_notes, dtype=int) start_time_by_note = np.zeros(n_notes) print('Finalizing MIDI data') for time, note in zip(*velocity_changes): # use time + 1 because we did some padding above velocity = piano_roll[note][time + 1] time = time / sampling_frequency if velocity > 0: if velocity_by_note[note] == 0: start_time_by_note[note] = time velocity_by_note[note] = velocity else: prerry_midi_note = pretty_midi.Note( velocity=velocity_by_note[note], pitch=note, start=start_time_by_note[note], end=time) instrument.notes.append(prerry_midi_note) velocity_by_note[note] = 0 pretty_midi_obj.instruments.append(instrument) for note in pretty_midi_obj.instruments[0].notes: #-should be ~ forte note.velocity = 100 # write to file print('Writing to file') pretty_midi_obj.write(output_file_path)
def convertMethodBDataToMidi(data, tokens, model_name, timestep_resolution): print("Converting raw notes to MIDI") mid = pretty_midi.PrettyMIDI() inst = pretty_midi.Instrument(0) timestepCounter = 0 # what notes are currently being played current_notes = {} # unnormalize the data at each step for d in data: for timestep in d: # for all notes in this timestep rounded_timestep = [round(x) for x in timestep] for msg in rounded_timestep: # if we encounter a new note start counting its duration if msg not in current_notes: current_notes[msg] = [] current_notes[msg].append(timestepCounter) current_notes[msg].append(1) else: current_notes[msg][1] = current_notes[msg][1] + 1 # if any of the currently playing notes are not # being played at this timestep, remove it from current notes7 notesToRemove = [] for note, timing in current_notes.items(): if note not in rounded_timestep: # print("Logic is sound, this is being called :) ") currentToken = abs(int(note)) if note >= 1: pitch, velocity = tokens[currentToken] if pitch > 127: pitch = np.uint8(127) if velocity > 127: velocity = np.uint8(127) start = timing[0] / timestep_resolution duration = timing[1] / timestep_resolution # print("Note start time = %d, note duration = %d" % (start, duration)) new_note = pretty_midi.Note(velocity, pitch, start, start + duration) inst.notes.append(new_note) notesToRemove.append(note) for note in notesToRemove: current_notes.pop(note) timestepCounter += 1 if bool(current_notes) == True: for note, timing in current_notes.items(): currentToken = abs(int(note)) if currentToken != 0: pitch, velocity = tokens[currentToken] if pitch > 127: pitch = np.uint8(127) if velocity > 127: velocity = np.uint8(127) start = timing[0] / timestep_resolution duration = timing[1] / timestep_resolution # print("Note start time = %d, note duration = %d" % (start, duration)) new_note = pretty_midi.Note(velocity, pitch, start, start + duration) inst.notes.append(new_note) del current_notes print("total number of notes = %d" % len(inst.notes)) mid.instruments.append(inst) cleanMidiB(mid) mid.write(getMidiRunName(model_name))
def create_midi_from_piece( piece: Piece, midi_path: str, measure_in_seconds: float, instruments: List[int], velocity: int, opening_silence_in_seconds: int = 1, trailing_silence_in_seconds: int = 1 ) -> None: """ Create MIDI file from a piece created by this package. :param piece: musical piece :param midi_path: path where resulting MIDI file is going to be saved :param measure_in_seconds: duration of one measure in seconds :param instruments: IDs of instruments (according to General MIDI specification) that play corresponding melodic lines :param velocity: one common velocity for all notes :param opening_silence_in_seconds: number of seconds with silence to add at the start of the composition :param trailing_silence_in_seconds: number of seconds with silence to add at the end of the composition :return: None """ numeration_shift = pretty_midi.note_name_to_number('A0') pretty_midi_instruments = [] for melodic_line, instrument in zip(piece.melodic_lines, instruments): pretty_midi_instrument = pretty_midi.Instrument(program=instrument) for element in melodic_line: start_time = element.start_time * measure_in_seconds start_time += opening_silence_in_seconds end_time = start_time + element.duration * measure_in_seconds pitch = element.position_in_semitones + numeration_shift note = pretty_midi.Note( start=start_time, end=end_time, pitch=pitch, velocity=velocity ) pretty_midi_instrument.notes.append(note) pretty_midi_instrument.notes.sort(key=lambda x: (x.start, x.pitch)) pretty_midi_instruments.append(pretty_midi_instrument) trailing_silence_start = piece.n_measures * measure_in_seconds trailing_silence_start += opening_silence_in_seconds note = pretty_midi.Note( velocity=0, pitch=1, # Arbitrary value that affects nothing. start=trailing_silence_start, end=trailing_silence_start + trailing_silence_in_seconds ) pretty_midi_instruments[0].notes.append(note) composition = pretty_midi.PrettyMIDI() for pretty_midi_instrument in pretty_midi_instruments: composition.instruments.append(pretty_midi_instrument) composition.write(midi_path)
import pretty_midi # Create a PrettyMIDI object cello_c_chord = pretty_midi.PrettyMIDI() # Create an Instrument instance for a cello instrument cello_program = pretty_midi.instrument_name_to_program('Cello') cello = pretty_midi.Instrument(program=cello_program) # Iterate over note names, which will be converted to note number later for note_name in ['C5', 'E5', 'G5']: # Retrieve the MIDI note number for this note name note_number = pretty_midi.note_name_to_number(note_name) # Create a Note instance, starting at 0s and ending at .5s note = pretty_midi.Note(velocity=100, pitch=note_number, start=0, end=.5) # Add it to our cello instrument cello.notes.append(note) # Add the cello instrument to the PrettyMIDI object cello_c_chord.instruments.append(cello) # Write out the MIDI data print(cello.notes) cello_c_chord.write('cello-C-chord.mid')
import os import sys import math import shutil import pretty_midi import numpy as np import pandas as pd from tqdm import tqdm # Making a file using pretty_midi instead of MIDO for easier npy file generation pretty_mid = pretty_midi.PrettyMIDI() piano = pretty_midi.Instrument(program=1) note = pretty_midi.Note(velocity=64, pitch=60, start=0.0, end=1.0) piano.notes.append(note) note = pretty_midi.Note(velocity=65, pitch=65, start=1.0, end=2.0) piano.notes.append(note) note = pretty_midi.Note(velocity=66, pitch=66, start=2.0, end=2.2) piano.notes.append(note) note = pretty_midi.Note(velocity=69, pitch=69, start=2.0, end=2.5) piano.notes.append(note) pretty_mid.instruments.append(piano) savedir = '/Users/sorensabet/Desktop/MSC/CSC2506_Project/data/Generated MIDI' pretty_mid.write(savedir + '/' + 'PRETTYMIDI_TEST.mid') print('Generated pretty_midi file!')
def emit_nesmdb_midi_examples( midi_fp, output_dir, min_num_instruments=1, filter_mid_len_below_seconds=5., filter_mid_len_above_seconds=600., filter_mid_bad_times=True, filter_ins_max_below=21, filter_ins_min_above=108, filter_ins_duplicate=True, output_include_drums=True, output_max_num=16, output_max_num_seconds=180.): midi_name = os.path.split(midi_fp)[1].split('.')[0] if min_num_instruments <= 0: raise ValueError() # Ignore unusually large MIDI files (only ~25 of these in the dataset) if os.path.getsize(midi_fp) > (512 * 1024): #512K return try: midi = pretty_midi.PrettyMIDI(midi_fp) except: return # Filter MIDIs with extreme length midi_len = midi.get_end_time() if midi_len < filter_mid_len_below_seconds or midi_len > filter_mid_len_above_seconds: return # Filter out negative times and quantize to audio samples for ins in midi.instruments: for n in ins.notes: if filter_mid_bad_times: if n.start < 0 or n.end < 0 or n.end < n.start: return n.start = round(n.start * 44100.) / 44100. n.end = round(n.end * 44100.) / 44100. instruments = midi.instruments # Filter out drum instruments drums = [i for i in instruments if i.is_drum] instruments = [i for i in instruments if not i.is_drum] # Filter out instruments with bizarre ranges instruments_normal_range = [] for ins in instruments: pitches = [n.pitch for n in ins.notes] min_pitch = min(pitches) max_pitch = max(pitches) if max_pitch >= filter_ins_max_below and min_pitch <= filter_ins_min_above: instruments_normal_range.append(ins) instruments = instruments_normal_range if len(instruments) < min_num_instruments: return # Sort notes for polyphonic filtering and proper saving for ins in instruments: ins.notes = sorted(ins.notes, key=lambda x: x.start) if output_include_drums: for ins in drums: ins.notes = sorted(ins.notes, key=lambda x: x.start) # Filter out polyphonic instruments instruments = [i for i in instruments if instrument_is_monophonic(i)] if len(instruments) < min_num_instruments: return # Filter out duplicate instruments if filter_ins_duplicate: uniques = set() instruments_unique = [] for ins in instruments: pitches = ','.join(['{}:{:.1f}'.format(str(n.pitch), n.start) for n in ins.notes]) if pitches not in uniques: instruments_unique.append(ins) uniques.add(pitches) instruments = instruments_unique if len(instruments) < min_num_instruments: return # TODO: Find instruments that have a substantial fraction of the number of total notes """ min_notes_frac = num_instruments_to_min_notes_frac(num_instruments) total_num_notes = sum([len(i.notes) for i in instruments]) instruments = [i for i in instruments if (len(i.notes) / float(total_num_notes)) >= min_notes_frac] num_instruments = len(instruments) if num_instruments < min_num_instruments: return """ # TODO: ensure tempo and other metadata is alright # TODO: ensure number of notes is alright # Create assignments of MIDI instruments to NES instruments num_instruments = len(instruments) if num_instruments == 1: instrument_perms = [(0, -1, -1), (-1, 0, -1), (-1, -1, 0)] elif num_instruments == 2: instrument_perms = [(-1, 0, 1), (-1, 1, 0), (0, -1, 1), (0, 1, -1), (1, -1, 0), (1, 0, -1)] elif num_instruments > 32: instrument_perms = list(itertools.permutations(random.sample(range(num_instruments), 32), 3)) else: instrument_perms = list(itertools.permutations(range(num_instruments), 3)) if len(instrument_perms) > output_max_num: instrument_perms = random.sample(instrument_perms, output_max_num) num_drums = len(drums) if output_include_drums else 0 instrument_perms_plus_drums = [] for perm in instrument_perms: selection = -1 if num_drums == 0 else random.choice(range(num_drums)) instrument_perms_plus_drums.append(perm + (selection,)) instrument_perms = instrument_perms_plus_drums # Emit midi files for i, perm in enumerate(instrument_perms): # Create MIDI instruments p1_prog = pretty_midi.instrument_name_to_program('Lead 1 (square)') p2_prog = pretty_midi.instrument_name_to_program('Lead 2 (sawtooth)') tr_prog = pretty_midi.instrument_name_to_program('Synth Bass 1') no_prog = pretty_midi.instrument_name_to_program('Breath Noise') p1 = pretty_midi.Instrument(program=p1_prog, name='p1', is_drum=False) p2 = pretty_midi.Instrument(program=p2_prog, name='p2', is_drum=False) tr = pretty_midi.Instrument(program=tr_prog, name='tr', is_drum=False) no = pretty_midi.Instrument(program=no_prog, name='no', is_drum=True) # Filter out invalid notes perm_mid_ins_notes = [] for mid_ins_id, nes_ins_name in zip(perm, ['p1', 'p2', 'tr', 'no']): if mid_ins_id < 0: perm_mid_ins_notes.append(None) else: if nes_ins_name == 'no': mid_ins = drums[mid_ins_id] mid_ins_notes_valid = mid_ins.notes else: mid_ins = instruments[mid_ins_id] mid_ins_notes_valid = [n for n in mid_ins.notes if n.pitch >= nes_ins_name_to_min_pitch[nes_ins_name] and n.pitch <= nes_ins_name_to_max_pitch[nes_ins_name]] perm_mid_ins_notes.append(mid_ins_notes_valid) assert len(perm_mid_ins_notes) == 4 # Calculate length of this ensemble start = None end = None for notes in perm_mid_ins_notes: if notes is None or len(notes) == 0: continue ins_start = min([n.start for n in notes]) ins_end = max([n.end for n in notes]) if start is None or ins_start < start: start = ins_start if end is None or ins_end > end: end = ins_end if start is None or end is None: continue # Clip if needed if (end - start) > output_max_num_seconds: end = start + output_max_num_seconds # Create notes for mid_ins_notes, nes_ins_name, nes_ins in zip(perm_mid_ins_notes, ['p1', 'p2', 'tr', 'no'], [p1, p2, tr, no]): if mid_ins_notes is None: continue if nes_ins_name == 'no': random_noise_mapping = [random.randint(1, 16) for _ in range(128)] last_nend = -1 for ni, n in enumerate(mid_ins_notes): nvelocity = n.velocity npitch = n.pitch nstart = n.start nend = n.end # Drums are not necessarily monophonic so we need to filter if nes_ins_name == 'no' and nstart < last_nend: continue last_nend = nend assert nstart >= start if nend > end: continue assert nend <= end nvelocity = 1 if nes_ins_name == 'tr' else int(round(1. + (14. * nvelocity / 127.))) assert nvelocity > 0 if nes_ins_name == 'no': npitch = random_noise_mapping[npitch] nstart = nstart - start nend = nend - start nes_ins.notes.append(pretty_midi.Note(nvelocity, npitch, nstart, nend)) # Add instruments to MIDI file midi = pretty_midi.PrettyMIDI(initial_tempo=120, resolution=22050) midi.instruments.extend([p1, p2, tr, no]) # Create indicator for end of song eos = pretty_midi.TimeSignature(1, 1, end - start) midi.time_signature_changes.append(eos) # Save MIDI file out_fp = '{}_{}.mid'.format(midi_name, str(i).zfill(3)) out_fp = os.path.join(output_dir, out_fp) midi.write(out_fp)
def infer_midi(interval, agg_f0, t_unit=0.02): """Inference the given interval and aggregated F0 to MIDI file. Parameters ---------- interval: list[tuple[float, float]] The return value of ``infer_interval`` function. List of onset/offset pairs in seconds. agg_f0: list[dict] Aggregated f0 information. Each elements in the list should contain three columns: *start_time*, *end_time*, and *frequency*. Time units should be in seonds, and pitch should be Hz. t_unit: float Time unit of each frame. Returns ------- midi: pretty_midi.PrettyMIDI The inferred MIDI object. """ fs = round(1 / t_unit) max_secs = max(record["end_time"] for record in agg_f0) total_frames = round(max_secs) * fs + 10 flat_f0 = np.zeros(total_frames) for record in agg_f0: start_idx = int(round(record["start_time"] * fs)) end_idx = int(round(record["end_time"] * fs)) flat_f0[start_idx:end_idx] = record["frequency"] notes = [] drum_notes = [] skip_num = 0 for onset, offset in interval: start_idx = int(round(onset * fs)) end_idx = int(round(offset * fs)) freqs = flat_f0[start_idx:end_idx] avg_hz = _conclude_freq(freqs) if avg_hz < 1e-6: skip_num += 1 note = pretty_midi.Note(velocity=80, pitch=77, start=onset, end=offset) drum_notes.append(note) continue note_num = int(round(pretty_midi.hz_to_note_number(avg_hz))) if not (0 <= note_num <= 127): logger.warning( "Caught invalid note number: %d (should be in range 0~127). Skipping.", note_num) skip_num += 1 continue note = pretty_midi.Note(velocity=80, pitch=note_num, start=onset, end=offset) notes.append(note) if skip_num > 0: logger.warning( "A total of %d notes are skipped due to lack of corressponding pitch information.", skip_num) inst = pretty_midi.Instrument(program=0) inst.notes += notes drum_inst = pretty_midi.Instrument(program=1, is_drum=True, name="Missing Notes") drum_inst.notes += drum_notes midi = pretty_midi.PrettyMIDI() midi.instruments.append(inst) midi.instruments.append(drum_inst) return midi
def _get_chroma(notes, sampling_rate): midi = pretty_midi.Instrument(0) midi.notes[:] = notes return midi.get_chroma(fs=sampling_rate)
def interpolation(args, model, dataset, x_a=None, x_b=None, output='output/', fs=25, program=0): if (x_a is None): x_a, x_b = dataset[random.randint( 0, len(dataset) - 1)], dataset[random.randint(0, len(dataset) - 1)] x_a, x_b = x_a.to(args.device), x_b.to(args.device) # Encode samples to the latent space z_a, z_b = model.encode(x_a.unsqueeze(0)), model.encode(x_b.unsqueeze(0)) # Run through alpha values interp = [] alpha_values = np.linspace(0, 1, args.n_steps) for alpha in alpha_values: z_interp = (1 - alpha) * z_a[0] + alpha * z_b[0] interp.append(model.decode(z_interp)) # Draw interpolation step by step i = 0 stack_interp = [] for step in interp: if args.num_classes > 1: step = torch.argmax(step[0], dim=0) stack_interp.append(step) # plt.matshow(step.cpu().detach(), alpha=1) # plt.title("Interpolation " + str(i)) # plt.savefig(args.figures_path + "interpolation" + str(i) + ".png") # plt.close() i += 1 stack_interp = torch.cat(stack_interp, dim=1) # Draw stacked interpolation plt.figure() plt.matshow(stack_interp.cpu(), alpha=1) plt.title("Interpolation") plt.savefig(output + "_interpolation.png") plt.close() # Generate MIDI from interpolation pm = pretty_midi.PrettyMIDI() notes, frames = stack_interp.shape instrument = pretty_midi.Instrument(program=program) # Pad 1 column of zeros to acknowledge initial and ending events piano_roll = np.pad(stack_interp.cpu().detach(), [(0, 0), (1, 1)], 'constant') # Use changes in velocities to find note on/note off events velocity_changes = np.nonzero(np.diff(piano_roll).T) # Keep track on velocities and note on times prev_velocities = np.zeros(notes, dtype=int) note_on_time = np.zeros(notes) # Do prettier representation fig = plt.figure(figsize=(18, 4), dpi=80) ax = plt.subplot(1, 1, 1) min_pitch = np.inf max_pitch = 0 cmap = plt.get_cmap('inferno', args.n_steps + 3) for time, note in zip(*velocity_changes): # Use time + 1s because of padding above velocity = piano_roll[note, time + 1] time = time / fs if velocity > 0: if prev_velocities[note] == 0: note_on_time[note] = time prev_velocities[note] = 75 else: pm_note = pretty_midi.Note(velocity=prev_velocities[note], pitch=note + args.min_pitch, start=note_on_time[note], end=time) instrument.notes.append(pm_note) prev_velocities[note] = 0 rect = patches.Rectangle( (note_on_time[note] * fs, note + args.min_pitch - 0.5), (time - note_on_time[note]) * fs, 1, linewidth=1.5, edgecolor='k', facecolor=cmap(int(note_on_time[note] * fs / 64)), alpha=0.8) min_pitch = min(min_pitch, note + args.min_pitch) max_pitch = max(max_pitch, note + args.min_pitch) ax.add_patch(rect) ax.set_ylim([min_pitch - 5, max_pitch + 5]) ax.set_xticks(np.arange(64, 64 * args.n_steps, 64)) ax.set_xticklabels(np.arange(1, args.n_steps, 1)) ax.set_xlim([0, time * fs]) ax.set_xlabel('Interpolated measures') ax.set_ylabel('Pitch') ax.grid() plt.tight_layout() plt.savefig(output + "_interpolation.pdf") pm.instruments.append(instrument) # Write out the MIDI data pm.write(output + "_interpolation.mid")
def run(self): sequence = music_pb2.NoteSequence() player = self._midi_hub.start_playback(sequence, allow_updates=True) player._channel = self._midi_channel pretty_midi = pm.PrettyMIDI() pretty_midi.instruments.append(pm.Instrument(0)) # Wait for the dreamer and store the time with the delta wall_start_time = time.time() self._bar_start_event.wait() bar_count = 0 while not self._stop_signal: # Number of seconds we should be at the beginning of this loop expected_start_time = self._timing.get_expected_start_time(bar_count) # Number of actual seconds since we started this thread from wall clock, # which is smaller then the expected start time # The difference is between: the actual wakeup time and the expected # (calculated) start time. By keeping this we can adjust the sequence # according to the drift. diff_time = self._timing.get_diff_time(wall_start_time, bar_count) tf.logging.debug("Playing " + str(self._timing.get_timing_args( wall_start_time, bar_count))) # Player sequence_adjusted = music_pb2.NoteSequence() sequence_adjusted.CopyFrom(sequence) sequence_adjusted = adjust_sequence_times(sequence_adjusted, wall_start_time - diff_time) player.update_sequence(sequence_adjusted, start_time=expected_start_time) # Plotter pretty_midi = mm.midi_io.note_sequence_to_pretty_midi(sequence) self._plotter.save(pretty_midi, self._output_plot) pretty_midi.write(self._output_midi) # Sets timing seconds_per_bar = self._timing.get_seconds_per_bar() seconds_per_loop = self._bar_per_loop * seconds_per_bar loop_start_time = expected_start_time loop_end_time = loop_start_time + seconds_per_loop generation_start_time = loop_end_time generation_end_time = generation_start_time + seconds_per_loop action = self._action_server.context.get(self.name, None) tf.logging.debug(str(action) + " " + str([ ("expected_start_time", expected_start_time), ("loop_start_time", loop_start_time), ("loop_end_time", loop_end_time), ("generation_start_time", generation_start_time), ("generation_end_time", generation_end_time)])) if not action: pass elif action is ActionType.LOOP: sequence = sequences.loop(sequence, loop_start_time, loop_end_time, seconds_per_loop) elif action is ActionType.GENERATE: sequence = sequences.generate(sequence, self.name, self._bundle_filename, self._config_name, generation_start_time, generation_end_time) elif action is ActionType.GENERATE_ONCE: sequence = sequences.generate(sequence, self.name, self._bundle_filename, self._config_name, generation_start_time, generation_end_time) self._action_server.context[self.name] = ActionType.LOOP elif action is ActionType.RESET_ONCE: sequence = sequences.reset(sequence, loop_start_time, loop_end_time, seconds_per_loop) self._action_server.context[self.name] = ActionType.LOOP elif action is ActionType.RESET_GENERATE: sequence = sequences.reset(sequence, loop_start_time, loop_end_time, seconds_per_loop) self._action_server.context[self.name] = ActionType.GENERATE_ONCE else: raise Exception(f"Unknown action {action}") while True: # Unlock at the start of the bar self._bar_start_event.wait() bar_count += 1 if bar_count % self._bar_per_loop == 0: break
import pretty_midi extracted_drum = pretty_midi.PrettyMIDI() generated_drum = pretty_midi.Instrument(program=1) generated_drum.is_drum = False for i in range(10): new_note = pretty_midi.Note(velocity=110, pitch=35, start=i * 2, end=i * 2 + .3) generated_drum.notes.append(new_note) extracted_drum.instruments.append(generated_drum) extracted_drum.write('pitch_test.mid') # 25 ~ 85
def write_MIDI(name, loop): GMKeymap = { "kick": [35, 36], "snare": [37, 38, 40], "closed hihat": [42, 44], "open hihat": [46], "low tom": [41, 43, 45] } #LSTM = load_model("JAKI_Encoder_Decoder_14-6-20_2") #oneHotGrooves = np.load("One-Hot-Drum-Loops.npy") #oneBarGrooves = oneHotGrooves[:,0:16,:] midiloop = pretty_midi.PrettyMIDI() #loop = convertOneHotToList(oneHotGrooves[2,:,:]) drumkit_program = pretty_midi.instrument_name_to_program('Cello') drumkit = pretty_midi.Instrument(program=drumkit_program) time = 0.0 for i in range(len(loop)): if 'k' in loop[i]: note = pretty_midi.Note(velocity=100, pitch=35, start=time, end=time + 0.125) drumkit.notes.append(note) if 'c' in loop[i]: note = pretty_midi.Note(velocity=100, pitch=42, start=time, end=time + 0.125) drumkit.notes.append(note) if 'o' in loop[i]: note = pretty_midi.Note(velocity=100, pitch=46, start=time, end=time + 0.125) drumkit.notes.append(note) if 't' in loop[i]: note = pretty_midi.Note(velocity=100, pitch=43, start=time, end=time + 0.125) drumkit.notes.append(note) if 's' in loop[i]: note = pretty_midi.Note(velocity=100, pitch=37, start=time, end=time + 0.125) drumkit.notes.append(note) try: drumkit.notes.append(note) except: pass time += 0.125 # semiquaver length at 120bpm midiloop.instruments.append(drumkit) midiloop.write(name)
def note_sequence_to_pretty_midi(sequence, drop_events_n_seconds_after_last_note=None): """Convert NoteSequence to a PrettyMIDI. Time is stored in the NoteSequence in absolute values (seconds) as opposed to relative values (MIDI ticks). When the NoteSequence is translated back to PrettyMIDI the absolute time is retained. The tempo map is also recreated. Args: sequence: A NoteSequence. drop_events_n_seconds_after_last_note: Events (e.g., time signature changes) that occur this many seconds after the last note will be dropped. If None, then no events will be dropped. Returns: A pretty_midi.PrettyMIDI object or None if sequence could not be decoded. """ ticks_per_quarter = sequence.ticks_per_quarter or constants.STANDARD_PPQ max_event_time = None if drop_events_n_seconds_after_last_note is not None: max_event_time = (max([n.end_time for n in sequence.notes] or [0]) + drop_events_n_seconds_after_last_note) # Try to find a tempo at time zero. The list is not guaranteed to be in order. initial_seq_tempo = None for seq_tempo in sequence.tempos: if seq_tempo.time == 0: initial_seq_tempo = seq_tempo break kwargs = {} if initial_seq_tempo: kwargs['initial_tempo'] = initial_seq_tempo.qpm else: kwargs['initial_tempo'] = constants.DEFAULT_QUARTERS_PER_MINUTE pm = pretty_midi.PrettyMIDI(resolution=ticks_per_quarter, **kwargs) # Create an empty instrument to contain time and key signatures. instrument = pretty_midi.Instrument(0) pm.instruments.append(instrument) # Populate time signatures. for seq_ts in sequence.time_signatures: if max_event_time and seq_ts.time > max_event_time: continue time_signature = pretty_midi.containers.TimeSignature( seq_ts.numerator, seq_ts.denominator, seq_ts.time) pm.time_signature_changes.append(time_signature) # Populate key signatures. for seq_key in sequence.key_signatures: if max_event_time and seq_key.time > max_event_time: continue key_number = seq_key.key if seq_key.mode == seq_key.MINOR: key_number += _PRETTY_MIDI_MAJOR_TO_MINOR_OFFSET key_signature = pretty_midi.containers.KeySignature( key_number, seq_key.time) pm.key_signature_changes.append(key_signature) # Populate tempos. # TODO(douglaseck): Update this code if pretty_midi adds the ability to # write tempo. for seq_tempo in sequence.tempos: # Skip if this tempo was added in the PrettyMIDI constructor. if seq_tempo == initial_seq_tempo: continue if max_event_time and seq_tempo.time > max_event_time: continue tick_scale = 60.0 / (pm.resolution * seq_tempo.qpm) tick = pm.time_to_tick(seq_tempo.time) # pylint: disable=protected-access pm._tick_scales.append((tick, tick_scale)) pm._update_tick_to_time(0) # pylint: enable=protected-access # Populate instrument names by first creating an instrument map between # instrument index and name. # Then, going over this map in the instrument event for loop inst_infos = {} for inst_info in sequence.instrument_infos: inst_infos[inst_info.instrument] = inst_info.name # Populate instrument events by first gathering notes and other event types # in lists then write them sorted to the PrettyMidi object. instrument_events = collections.defaultdict( lambda: collections.defaultdict(list)) for seq_note in sequence.notes: instrument_events[(seq_note.instrument, seq_note.program, seq_note.is_drum)]['notes'].append( pretty_midi.Note(seq_note.velocity, seq_note.pitch, seq_note.start_time, seq_note.end_time)) for seq_bend in sequence.pitch_bends: if max_event_time and seq_bend.time > max_event_time: continue instrument_events[(seq_bend.instrument, seq_bend.program, seq_bend.is_drum)]['bends'].append( pretty_midi.PitchBend(seq_bend.bend, seq_bend.time)) for seq_cc in sequence.control_changes: if max_event_time and seq_cc.time > max_event_time: continue instrument_events[(seq_cc.instrument, seq_cc.program, seq_cc.is_drum)]['controls'].append( pretty_midi.ControlChange( seq_cc.control_number, seq_cc.control_value, seq_cc.time)) for ta in sequence.text_annotations: from magenta.music.chords_lib import CHORD_SYMBOL if ta.annotation_type == CHORD_SYMBOL and ta.text != constants.NO_CHORD: pm.lyrics.append(pretty_midi.Lyric(ta.text, ta.time)) # timing_track.append(mido.MetaMessage( # 'end_of_track', time=timing_track[-1].time + 1)) for (instr_id, prog_id, is_drum) in sorted(instrument_events.keys()): # For instr_id 0 append to the instrument created above. if instr_id > 0: instrument = pretty_midi.Instrument(prog_id, is_drum) pm.instruments.append(instrument) else: instrument.is_drum = is_drum # propagate instrument name to the midi file instrument.program = prog_id if instr_id in inst_infos: instrument.name = inst_infos[instr_id] instrument.notes = instrument_events[(instr_id, prog_id, is_drum)]['notes'] instrument.pitch_bends = instrument_events[(instr_id, prog_id, is_drum)]['bends'] instrument.control_changes = instrument_events[(instr_id, prog_id, is_drum)]['controls'] return pm
def fami_to_mid(input_txt_file, output_mid_file): """ Returns the duration of the track """ f = open(input_txt_file, 'r') d = f.read() f.close() d = d.replace('\t', '') channels = d.split('Channel Type') channels_list = [] instances_list = [] for i, channel in enumerate(channels): patterns = channel.split('Pattern Name') patterns_list = [] instances = {} for j, pattern in enumerate(patterns): pattern_list = [] notes = pattern.split('\n') for note in notes: if note.startswith('Note ') or note.startswith( 'PatternInstance '): if note.startswith('Note '): params_raw = note.split('Note ')[1] + '\n' else: params_raw = note.split('PatternInstance ')[1] + '\n' open_value = False temp = '' params = [] for c in params_raw: if c == '"': if open_value: open_value = False else: open_value = True if c in [' ', '\n'] and not open_value: params.append(temp) temp = '' else: temp += c if note.startswith('Note '): notes_values = [] for param in params: key, value = param.split('=') value = value[1:-1] notes_values.append((key, value)) pattern_list.append((pattern_name, notes_values)) else: instance = {} for param in params: key, value = param.split('=') value = value[1:-1] instance[key] = value instances[instance['Pattern']] = instance else: if note.startswith('="Pattern '): pattern_name = note[2:-1] patterns_list.append(pattern_list) channels_list.append(patterns_list) instances_list.append(instances) values_table = { 'C': 0, 'C#': 1, 'D': 2, 'D#': 3, 'E': 4, 'F': 5, 'F#': 6, 'G': 7, 'G#': 8, 'A': 9, 'A#': 10, 'B': 11 } notes_times = [] for c in channels_list: for p in c: for name, n in p: time = None for k, v in n: if k == 'Time': time = v if k == 'Value': notes_times.append(time) # Average Volumes notes_volumes = [] current_volume = 11 was_stop = True num_events = 0 volume = 0 for c in channels_list: for p in c: for name, n in p: # create dict from list of key values d = {} for k, v in n: d[k] = v # end of note if 'Value' in d: # TWO AGGREGATION METHODS: prev_volume = None if was_stop else int(volume) # prev_volume = None if was_stop else int(volume / num_events) notes_volumes.append(prev_volume) volume = 0 num_events = 0 if not d['Value'] == 'Stop': was_stop = False # means it's not a Stop or other: aggregate if 'Volume' in d: v = int(d['Volume']) # TWO AGGREGATION METHODS: volume = max(v, volume) # volume += v current_volume = v num_events += 1 else: if ('Value' in d): # if it's a true note, but without volume change or indication if (not d['Value'] == 'Stop'): # TWO AGGREGATION METHODS: volume = max(current_volume, volume) # volume += current_volume num_events += 1 was_stop = False else: was_stop = True # Write midi # Constants: channel_index_to_prog = {1: 80, 2: 81, 3: 38, 4: 121} prog_to_instrument_name = {80: 'p1', 81: 'p2', 38: 'tr', 121: 'no'} # Midi midi = pretty_midi.PrettyMIDI(initial_tempo=120, resolution=22050) current_note = 0 max_end = 0 for channel_index, c in enumerate(channels_list): if channel_index not in channel_index_to_prog: continue # Instrument prog = channel_index_to_prog[channel_index] instrument_name = prog_to_instrument_name[prog] instrument_notes = [] instrument = pretty_midi.Instrument(program=prog, name=instrument_name, is_drum=(prog >= 112)) insts = instances_list[channel_index] for i, p in enumerate(c): for note_index, (name, n) in enumerate(p): inst = insts[name] inst_time = int(inst['Time']) * 256 time = 0 value = None # create dict from list of key values d = {} for k, v in n: d[k] = v if 'Time' in d: v = d['Time'] time = int(v) + inst_time try: time_end = int( notes_times[current_note + 1]) + inst_time length = time_end - time if length < 0: length = time_end - (time - 256) except: length = 1 try: volume = notes_volumes[current_note + 1] if volume is not None: last_volume = volume except: # TODO pb with the last event # print('Should only be the last character') volume = last_volume if 'Value' in d: current_note += 1 v = d['Value'] if v == 'Stop': value = None else: value = values_table[v[0:-1]] + 12 * (int(v[-1]) + 1) # TODO never used # elif k == 'FinePitch': # pitch = -(int(v) / 128) * 100 * 12 if (not value is None): time = float(time) / 256 * 4 length = float(length) / 256 * 4 note = pretty_midi.Note(velocity=volume, start=time, end=time + length, pitch=value) instrument_notes.append(note) if time + length > max_end: max_end = time + length instrument.notes = instrument_notes midi.instruments.append(instrument) ts = pretty_midi.TimeSignature(4, 4, 0) eos = pretty_midi.TimeSignature(1, 1, max_end) midi.time_signature_changes.extend([ts, eos]) midi.write(output_mid_file) return max_end
# wiki # http://craffel.github.io/pretty-midi/#pretty-midi-prettymidi import pretty_midi pm = pretty_midi.PrettyMIDI(resolution=960, initial_tempo=120) #pretty_midiオブジェクトを作ります instrument = pretty_midi.Instrument(0) #instrumentはトラックみたいなものです。 instrument2 = pretty_midi.Instrument(1) #instrumentはトラックみたいなものです。 note_number = pretty_midi.note_name_to_number('G4') note = pretty_midi.Note(velocity=100, pitch=note_number, start=0, end=1) #noteはNoteOnEventとNoteOffEventに相当します。 instrument.notes.append(note) pm.instruments.append(instrument) pm.write('making/test.mid') ################################################################ # # MIDIファイルの解析、操作、および合成の使用例: # ################################################################ #midiをロード midi_data = pretty_midi.PrettyMIDI('making/test.mid') # Print an empirical estimate of its global tempo #速さを出力する print midi_data.estimate_tempo() # Compute the relative amount of each semitone across the entire song,
def to_pretty_midi(self, constant_tempo=None, constant_velocity=100): """ Convert to a :class:`pretty_midi.PrettyMIDI` instance. Notes ----- - Only constant tempo is supported by now. - The velocities of the converted pianorolls are clipped to [0, 127], i.e. values below 0 and values beyond 127 are replaced by 127 and 0, respectively. - Adjacent nonzero values of the same pitch will be considered a single note with their mean as its velocity. Parameters ---------- constant_tempo : int The constant tempo value of the output object. Defaults to use the first element of `tempo`. constant_velocity : int The constant velocity to be assigned to binarized tracks. Defaults to 100. Returns ------- pm : `pretty_midi.PrettyMIDI` object The converted :class:`pretty_midi.PrettyMIDI` instance. """ self.check_validity() pm = pretty_midi.PrettyMIDI(initial_tempo=self.tempo[0]) # TODO: Add downbeat support -> time signature change events # TODO: Add tempo support -> tempo change events if constant_tempo is None: constant_tempo = self.tempo[0] time_step_size = 60.0 / constant_tempo / self.beat_resolution for track in self.tracks: instrument = pretty_midi.Instrument(program=track.program, is_drum=track.is_drum, name=track.name) copied = track.copy() if copied.is_binarized(): copied.assign_constant(constant_velocity) copied.clip() clipped = copied.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_size * note_ons note_offs = np.nonzero((diff < 0).T)[1] note_off_times = time_step_size * 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=lambda x: x.start) pm.instruments.append(instrument) return pm
def test_get_beats(): pm = pretty_midi.PrettyMIDI() # Add a note to force get_end_time() to be non-zero i = pretty_midi.Instrument(0) i.notes.append(pretty_midi.Note(100, 100, 0.3, 10.4)) pm.instruments.append(i) # pretty_midi assumes 120 bpm unless otherwise specified assert np.allclose(pm.get_beats(), np.arange(0, pm.get_end_time(), 60. / 120.)) # Testing starting from a different beat time assert np.allclose(pm.get_beats(.2), np.arange(0, pm.get_end_time(), 60. / 120.) + .2) # Testing a tempo change change_bpm = 93. change_time = 4.4 pm._tick_scales.append( (pm.time_to_tick(change_time), 60. / (change_bpm * pm.resolution))) pm._update_tick_to_time(pm.time_to_tick(pm.get_end_time())) # Track at 120 bpm up to the tempo change time expected_beats = np.arange(0, change_time, 60. / 120.) # BPM switches (4.5 - 4.4)/(60./120.) of the way through expected_beats = np.append( expected_beats, change_time + (4.5 - change_time) / (60. / 120.) * 60. / change_bpm) # From there, use the new bpm expected_beats = np.append( expected_beats, np.arange(expected_beats[-1] + 60. / change_bpm, pm.get_end_time(), 60. / change_bpm)) assert np.allclose(pm.get_beats(), expected_beats) # When requesting a start_time after the tempo change, make sure we just # track as normal assert np.allclose( pm.get_beats(change_time + .1), np.arange(change_time + .1, pm.get_end_time(), 60. / change_bpm)) # Add a time signature change, which forces beat tracking to restart pm.time_signature_changes.append(pretty_midi.TimeSignature(3, 4, 2.1)) # Track at 120 bpm up to time signature change expected_beats = np.arange(0, 2.1, 60. / 120.) # Now track, restarting from time signature change time expected_beats = np.append(expected_beats, np.arange(2.1, change_time, 60. / 120.)) # BPM switches (4.6 - 4.4)/(60./120.) of the way through expected_beats = np.append( expected_beats, change_time + (4.6 - change_time) / (60. / 120.) * 60. / change_bpm) # From there, use the new bpm expected_beats = np.append( expected_beats, np.arange(expected_beats[-1] + 60. / change_bpm, pm.get_end_time(), 60. / change_bpm)) assert np.allclose(pm.get_beats(), expected_beats) # When there are two time signature changes, make sure both get included pm.time_signature_changes.append(pretty_midi.TimeSignature(5, 4, 1.9)) expected_beats[expected_beats == 2.] = 1.9 assert np.allclose(pm.get_beats(), expected_beats) # Request a start time after time time signature change expected_beats = np.arange(2.2, change_time, 60. / 120.) expected_beats = np.append( expected_beats, change_time + (4.7 - change_time) / (60. / 120.) * 60. / change_bpm) expected_beats = np.append( expected_beats, np.arange(expected_beats[-1] + 60. / change_bpm, pm.get_end_time(), 60. / change_bpm)) assert np.allclose(pm.get_beats(2.2), expected_beats)
# -*- coding: utf-8 -*- import pretty_midi from common import * initial_tempo = 76.0 melody_c_melody = pretty_midi.PrettyMIDI(initial_tempo=initial_tempo) ###################################################### melody melody_program = pretty_midi.instrument_name_to_program('Guitar harmonics') melody = pretty_midi.Instrument(program=melody_program) # 心跳乱了节奏 add_instrument_note(instrument=melody, note_name='C3', range=2) add_instrument_note(instrument=melody, note_name='C2', range=1) add_instrument_note(instrument=melody, note_name='D2', range=1) add_instrument_note(instrument=melody, note_name='E2', range=2) add_instrument_note(instrument=melody, note_name='A2', range=2) add_instrument_note(instrument=melody, note_name='G2', range=8) # 梦也不自由 add_instrument_note(instrument=melody, note_name='F2', range=2) add_instrument_note(instrument=melody, note_name='E2', range=1) add_instrument_note(instrument=melody, note_name='C2', range=2) add_instrument_note(instrument=melody, note_name='E2', range=2) add_instrument_note(instrument=melody, note_name='D2', range=9) # 爱是个绝对承诺不 add_instrument_note(instrument=melody, note_name='C3', range=2) add_instrument_note(instrument=melody, note_name='C2', range=1) add_instrument_note(instrument=melody, note_name='D2', range=1)