def csv_to_midi(self, fpath): track = midi.Track() track.append(midi.SequencerSpecificEvent(tick=0, data=[5, 15, 9, 70, 200])) track.append(midi.SequencerSpecificEvent(tick=0, data=[5, 15, 6, 71, 101, 110, 101, 114, 97, 108, 32, 77, 73, 68, 73])) track.append(midi.TrackNameEvent(tick=0, text='Acoustic Grand Piano High', data=[65, 99, 111, 117, 115, 116, 105, 99, 32, 71, 114, 97, 110, 100, 32, 80, 105, 97, 110, 111, 32, 72, 105, 103, 104])) track.append(midi.ProgramChangeEvent(tick=0, channel=0, data=[0])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[10, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[10, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[10, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[7, 127])) track.append(midi.ControlChangeEvent(tick=3, channel=0, data=[100, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[101, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[100, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[101, 64])) track.append(midi.ControlChangeEvent(tick=1, channel=0, data=[6, 12])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[6, 12])) track.append(midi.ControlChangeEvent(tick=1, channel=0, data=[38, 0])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[38, 0])) track.append(midi.NoteOnEvent(tick=5, channel=0, data=[67, 69])) df = pd.read_csv(fpath, index_col=0, names=["Tick", "Data1", "Data2","Evt_Type"], header=0) nrows = len(df.iloc[:, 0]) for i in range(nrows): if df.Evt_Type[i] == "p": evt = midi.events.ProgramChangeEvent(tick=int(df.Tick[i]), data=[int(df.Data1[i]) + 50, int(df.Data2[i])]) track.append(evt) if df.Evt_Type[i] == "c": evt = midi.events.ControlChangeEvent(tick=int(df.Tick[i]), data=[int(df.Data1[i]), int(df.Data2[i])]) track.append(evt) if df.Evt_Type[i] == "n": evt = midi.events.NoteOnEvent(tick=int(df.Tick[i]), data=[int(df.Data1[i]), int(df.Data2[i])]) track.append(evt) track.append(midi.events.EndOfTrackEvent()) for t in track: print(t) self.tracks_to_mid([track], "output_test.mid")
def generate_audio_track(data, note_phrases, length, instrument=None): notes = data[0]["note_matrix"] if instrument is None: valid_instruments = list( set(notes.keys()).intersection(note_phrases.keys())) instrument = random.choice(valid_instruments) note_mats = [d["note_matrix"][instrument] for d in data] if len(note_phrases[instrument]) == 0: return None phrases = generate_note_sequence(note_phrases[instrument], note_mats, length, tick_max=160) track = midi.Track() track.append(midi.TrackNameEvent()) prog = midi.ProgramChangeEvent() prog.set_value(instrument) track.append(prog) for i in xrange(0, len(phrases)): for j in xrange(0, len(phrases[i]["tick"])): pitch = phrases[i]["pitch"][j] velocity = phrases[i]["velocity"][j] note_type = phrases[i]["type"][j] tick = phrases[i]["tick"][j] obj = midi.NoteOnEvent(channel=0) if note_type == "off": obj = midi.NoteOffEvent(channel=0) obj.set_pitch(pitch) obj.set_velocity(velocity) obj.tick = tick track.append(obj) track.append(midi.EndOfTrackEvent()) return track
def finalize_midi_sequence(ptrn, name="Track 1", inst=0, channel=0, tsig=(4, 4), bpm=120): """ Makes a geenrated midi sequnce valid for most players by adding TimeSignature, SetTempo and EndOfTrack events. """ has_tsig = False has_tempo = False has_end = False for evnt in utils.evnt_gen(ptrn): if isinstance(evnt, midi.SetTempoEvent): has_tsig = True if isinstance(evnt, midi.TimeSignatureEvent): has_tempo = True if isinstance(evnt, midi.EndOfTrackEvent): has_end = True if not has_tsig: ptrn[0].insert(0, midi.TimeSignatureEvent(tick=0)) ptrn[0][0].data[:2] = tsig ptrn[0][0].data[2:] = 24, 8 if not has_tempo: ptrn[0].insert(0, midi.SetTempoEvent(tick=0)) ptrn[0][0].set_bpm(bpm) if not has_end: ptrn[0].append(midi.EndOfTrackEvent(tick=0)) ptrn[0].insert(0, midi.TrackNameEvent(tick=0, text=name, data=[])) ptrn[0].insert( 0, midi.ProgramChangeEvent(tick=0, channel=channel, data=[inst])) return ptrn
def generate_audio_track(notes,length,all_instruments= None): if all_instruments is None: instrument = random.choice(notes.keys()) else: ai = [a for a in all_instruments if a<42 and a>55] if len(ai)==0: instrument = random.choice(all_instruments) else: instrument = random.choice(ai) tick = generate_tick_seq(notes[instrument]['tick']['mat'],notes[instrument]['tick']['inds'],length,tick_max=160) length = len(tick) pitch = generate_markov_seq(notes[instrument]['pitch']['mat'],notes[instrument]['pitch']['inds'],length) velocity = generate_markov_seq(notes[instrument]['velocity']['mat'],notes[instrument]['velocity']['inds'],length) for i in xrange(0,len(velocity)): if velocity[i]>100: velocity[i]=100 track = midi.Track() track.append(midi.TrackNameEvent()) prog = midi.ProgramChangeEvent() prog.set_value(instrument) track.append(prog) for i in xrange(0,length): on = midi.NoteOnEvent(channel=0) on.set_pitch(pitch[i]) on.set_velocity(velocity[i]) on.tick = tick[i] track.append(on) track.append(midi.EndOfTrackEvent()) return track
def generate_tempo_track(data, length, mpqn=20): track = midi.Track() track.append(midi.TrackNameEvent()) track.append(midi.TextMetaEvent()) te = midi.SetTempoEvent() te.tick = length te.set_mpqn(mpqn) track.append(te) track.append(midi.EndOfTrackEvent()) return track
def generate_tempo_track(tempos,length): tick = generate_tick_seq(tempos['tick']['mat'],tempos['tick']['inds'],length) length = len(tick) mpqn = generate_markov_seq(tempos['mpqn']['mat'],tempos['mpqn']['inds'],length) track = midi.Track() track.append(midi.TrackNameEvent()) track.append(midi.TextMetaEvent()) for i in xrange(0,length): if mpqn[i]!=0: te = midi.SetTempoEvent() te.tick = tick[i] te.set_mpqn(mpqn[i]) track.append(te) track.append(midi.EndOfTrackEvent()) return track
def notes_only_csv_to_mid(self, fpath): track = midi.Track() track.append(midi.SequencerSpecificEvent(tick=0, data=[5, 15, 9, 70, 200])) track.append(midi.SequencerSpecificEvent(tick=0, data=[5, 15, 6, 71, 101, 110, 101, 114, 97, 108, 32, 77, 73, 68, 73])) track.append(midi.TrackNameEvent(tick=0, text='Acoustic Grand Piano High', data=[65, 99, 111, 117, 115, 116, 105, 99, 32, 71, 114, 97, 110, 100, 32, 80, 105, 97, 110, 111, 32, 72, 105, 103, 104])) track.append(midi.ProgramChangeEvent(tick=0, channel=0, data=[0])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[10, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[10, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[10, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[7, 127])) track.append(midi.ControlChangeEvent(tick=3, channel=0, data=[100, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[101, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[100, 64])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[101, 64])) track.append(midi.ControlChangeEvent(tick=1, channel=0, data=[6, 12])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[6, 12])) track.append(midi.ControlChangeEvent(tick=1, channel=0, data=[38, 0])) track.append(midi.ControlChangeEvent(tick=0, channel=0, data=[38, 0])) track.append(midi.NoteOnEvent(tick=5, channel=0, data=[67, 69])) df = pd.read_csv(fpath, index_col=0, names=["Tick", "Data1", "Data2","Evt_Type"], header=0) nrows = len(df.iloc[:, 0]) oor = False for i in range(nrows): tick = int(abs(df.iloc[i, 0])) d1 = int(abs(df.iloc[i, 1])) d2 = int(abs(df.iloc[i, 2])) if tick > 256 or tick < 0 or d1 > 256 or d1 < 0 or d2 > 256 or d2 < 0: print("Note in position {} out of range".format(str(i))) break evt = midi.events.NoteOnEvent(tick=tick, data=[d1, d2]) track.append(evt) track.append(midi.events.EndOfTrackEvent()) for t in track: print(t) self.tracks_to_mid([track], "output_test.mid")
def change_music_to_pattern(music): music.parse_track_msg() # music._init_main_trank() pattern = midi.Pattern() pattern.resolution = music.get_resolution() pattern.format = music.get_play_format() for track in reversed(music.track): t = midi.Track() for event in track: event_tick = int(event[0]) event_event = event[1] state_code = event_event["state_code"] if state_code == 255: if event_event["name"] == 'Set Tempo': eve = midi.SetTempoEvent(tick=event_tick, bpm=event_event["bpm"]) elif event_event["name"] == 'Trank Name': eve = midi.TrackNameEvent(tick=event_tick, text=event_event["text"]) elif event_event["name"] == 'Copyright Notice': eve = midi.CopyrightMetaEvent(tick=event_tick, text=event_event["text"]) elif event_event["name"] == 'SMPTE Offset': eve = midi.SmpteOffsetEvent(tick=event_tick, text=event_event["text"]) elif event_event["name"] == 'Time Signature': eve = midi.TimeSignatureEvent( tick=event_tick, numerator=event_event["numerator"], denominator=event_event["denominator"], metronome=event_event["metronome"], thirtyseconds=event_event["thirtyseconds"]) elif event_event["name"] == "End of Track": eve = midi.EndOfTrackEvent(tick=event_tick) else: continue elif 240 <= state_code <= 254: # 系统码 eve = midi.SysexEvent() elif 224 <= state_code <= 239: # 滑音 eve = midi.PitchWheelEvent(tick=event_tick, channel=event_event["channel"], pitch=event_event["pitch"]) elif 208 <= state_code <= 223: # After Touch eve = midi.AfterTouchEvent() elif 192 <= state_code <= 207: # 乐器转换 eve = midi.ProgramChangeEvent(tick=event_tick, channel=event_event["channel"], data=[event_event["program"]]) elif 176 <= state_code <= 191: # midi控制器 eve = midi.ControlChangeEvent( tick=event_tick, channel=event_event["channel"], data=[event_event["control"], event_event["value"]]) elif 160 <= state_code <= 175: continue elif 144 <= state_code <= 159: # note on eve = midi.NoteOnEvent(tick=event_tick, channel=event_event["channel"], velocity=event_event["velocity"], pitch=event_event["pitch"]) elif 128 <= state_code <= 143: # note off eve = midi.NoteOffEvent(tick=event_tick, channel=event_event["channel"], velocity=event_event["velocity"], pitch=event_event["pitch"]) elif state_code <= 127: continue t.append(eve) pattern.append(t) return pattern
def numpy2midi(n): """Convert a numpy array n to a midi pattern in python-midi format, quantised etc.""" # print(n) # print(n.shape) resolution = 4 p = midi.Pattern(resolution=resolution) #, tick_relative=False) track = midi.Track() #track = midi.Track(tick_relative=False) p.append(track) set_tempo = midi.SetTempoEvent() set_tempo.set_bpm(120) set_tempo.set_mpqn(120) track_name = midi.TrackNameEvent(trackname="Track name") time_sig = midi.TimeSignatureEvent() time_sig.set_numerator(4) time_sig.set_denominator(4) time_sig.set_metronome(180) # time_sig.set_thirtyseconds(32) end = midi.EndOfTrackEvent() end.tick = nsteps * resolution #track.append(set_tempo) #track.append(track_name) #track.append(time_sig) for step in range(nsteps): tick = 0 for drum in range(len(names)): # print(n[drum, step]) if n[drum, step] > 0: on = midi.NoteOnEvent() on.channel = 9 on.pitch = dm2[drum] on.velocity = int(n[drum, step]) on.tick = tick track.append(on) # print(on) tick = 0 tick = resolution for drum in range(len(names)): if True: #elif step > 0 and n[drum, step-1] > 0: off = midi.NoteOffEvent() off.channel = 9 off.pitch = dm2[drum] off.velocity = 100 off.tick = tick track.append(off) # print(off) tick = 0 track.append(end) #p.make_ticks_rel() return p
def writemidi( self, filedir="" ): # sort the events by absoluteticks # put all tempo, time signature data in track 0, as well as any instrument or track names # first grab the track name if self.texts[0][0].text != "": trackname = MIDI.TrackNameEvent(text=self.texts[0][0].text, tick=0) trackname.absoluteticks = 0 # for some reason, the data doesn't get through via the text above. trackname.data = [ ] i = 0 while i < len(self.texts[0][0].text): trackname.data.append( ord( self.texts[0][0].text[i] ) ) i+= 1 tracks = [[ trackname]] del trackname # so that when we reuse this variable later it doesn't change the above else: tracks = [[]] # put all tempo, time signature data in track 0 tracks[0] += self.texts[0][1:] + self.tempos+self.timesignatures+self.notes[0] # sort everything tracks[0].sort(key=operator.attrgetter('absoluteticks')) # then grab the instrument if self.channels[0] != 9 and self.instruments[0]: tracks[0].insert(0, MIDI.ProgramChangeEvent( value=self.instruments[0], channel=self.channels[0] ) ) for i in range(1,len(self.notes)): # sort each track separately # first grab the track name if self.texts[i][0].text != "": trackname = MIDI.TrackNameEvent(text=self.texts[i][0].text, tick=0) # for some reason, the data doesn't get through via the text above. trackname.data = [ ] trackname.absoluteticks = 0 j = 0 while j < len(self.texts[i][0].text): trackname.data.append( ord( self.texts[i][0].text[j] ) ) j += 1 tracks.append( [ trackname ] ) del trackname # so that when we reuse this variable later it doesn't change the above else: tracks.append( [] ) # then grab the instrument tracks[i] += self.texts[i][1:] + self.notes[i] tracks[i].sort(key=operator.attrgetter('absoluteticks')) if self.channels[i] != 9 and self.instruments[i]: tracks[i].insert(0, MIDI.ProgramChangeEvent( value=self.instruments[i], channel=self.channels[i] )) # now that everything is sorted globally, # make sure that the local ticks are correct. tickdivisor = config.EDITresolution for i in range(len(tracks)): tracks[i].insert(0, MIDI.ControlChangeEvent( tick=0, channel=self.channels[i], data=[7,127]) ) for track in tracks: previouseventabsoluteticks = 0 for event in track: try: thiseventabsoluteticks = int(event.absoluteticks) except AttributeError: thiseventabsoluteticks = 0 # number of ticks between previous event and the current event tickmeoff = thiseventabsoluteticks - previouseventabsoluteticks event.tick = tickmeoff # check to see how small we can get the resolution tickdivisor = gcd( tickdivisor, tickmeoff ) # set up the ticks for next event previouseventabsoluteticks = thiseventabsoluteticks if config.EDITresolution % tickdivisor: Error(" min RESOLUTION does not divide our EDITresolution. something is funky ") # prep the new pattern for creating newpattern = MIDI.Pattern( resolution=config.EDITresolution/tickdivisor ) for track in tracks: if tickdivisor > 1: for event in track: # divide up the relative ticks event.tick /= tickdivisor # keep absolute ticks in the EDITresolution if track[-1].name != "End of Track": # add an end of track if it isn't there track.append( MIDI.EndOfTrackEvent( tick=config.EDITresolution/tickdivisor ) ) newpattern.append( MIDI.Track(track) ) if filedir == "": MIDI.write_midifile(self.midifile, newpattern) else: MIDI.write_midifile(filedir, newpattern)
def writemidi(self, filedir=""): # sorteer de events van abs ticks # gooit alle tracks en time signatures in track [0] # pak de track naam if self.texts[0][0].text != "": trackname = MIDI.TrackNameEvent(text=self.texts[0][0].text, tick=0) trackname.absoluteticks = 0 # dunno werkt niet voor een of andere reden trackname.data = [] i = 0 while i < len(self.texts[0][0].text): trackname.data.append(ord(self.texts[0][0].text[i])) i += 1 tracks = [[trackname]] del trackname # verwijderd de naam als de hierboven genoteerde naam opnieuw wordt gebruikt else: tracks = [[]] # gooi alles in track [0] tracks[0] += self.texts[0][ 1:] + self.tempos + self.timesignatures + self.notes[0] # sorteer alles tracks[0].sort(key=operator.attrgetter('absoluteticks')) # pakt de instrument if self.channels[0] != 9 and self.instruments[0]: tracks[0].insert( 0, MIDI.ProgramChangeEvent(value=self.instruments[0], channel=self.channels[0])) for i in range(1, len(self.notes)): # sorteer de tracks # pak de track naam if self.texts[i][0].text != "": trackname = MIDI.TrackNameEvent(text=self.texts[i][0].text, tick=0) # dunno dit werkt niet voor een of andere reden trackname.data = [] trackname.absoluteticks = 0 j = 0 while j < len(self.texts[i][0].text): trackname.data.append(ord(self.texts[i][0].text[j])) j += 1 tracks.append([trackname]) del trackname # verwijderd de naam als de hierboven genoteerde naam opnieuw wordt gebruikt else: tracks.append([]) # pak de instrument tracks[i] += self.texts[i][1:] + self.notes[i] tracks[i].sort(key=operator.attrgetter('absoluteticks')) if self.channels[i] != 9 and self.instruments[i]: tracks[i].insert( 0, MIDI.ProgramChangeEvent(value=self.instruments[i], channel=self.channels[i])) # kijk of de lokale ticks goed zijn tickdivisor = config.EDITresolution for i in range(len(tracks)): tracks[i].insert( 0, MIDI.ControlChangeEvent(tick=0, channel=self.channels[i], data=[7, 127])) for track in tracks: previouseventabsoluteticks = 0 for event in track: try: thiseventabsoluteticks = int(event.absoluteticks) except AttributeError: thiseventabsoluteticks = 0 # aantal ticks in vergelijking tot voorgaande ticks en current ticks tickmeoff = thiseventabsoluteticks - previouseventabsoluteticks event.tick = tickmeoff # om te kijken hoe klein de resolutie is tickdivisor = gcd(tickdivisor, tickmeoff) # set de ticks voor de volgende event(midi) previouseventabsoluteticks = thiseventabsoluteticks if config.EDITresolution % tickdivisor: Error( " min RESOLUTON kan niet gedeeld worden door EDITresolution. er is iets gaande " ) newpattern = MIDI.Pattern(resolution=config.EDITresolution / tickdivisor) for track in tracks: if tickdivisor > 1: for event in track: # deel de relatieve ticks event.tick /= tickdivisor # laat abs ticks in de edit resolution if track[-1].name != "End of Track": # voeg het einde van een track hier als het er niet is track.append( MIDI.EndOfTrackEvent(tick=config.EDITresolution / tickdivisor)) newpattern.append(MIDI.Track(track)) if filedir == "": MIDI.write_midifile(self.midifile, newpattern) else: MIDI.write_midifile(filedir, newpattern)
def toMidi(gspattern, midiMap=None, folderPath="output/", name=None): """ Function to write GSPattern instance to MIDI. Args: midiMap: mapping used to translate tags to MIDI pitch folderPath: folder where MIDI file is stored name: name of the file """ import midi # Instantiate a MIDI Pattern (contains a list of tracks) pattern = midi.Pattern(tick_relative=False,format=1) pattern.resolution=getattr(gspattern,'resolution' , 960) # Instantiate a MIDI Track (contains a list of MIDI events) track = midi.Track(tick_relative=False) track.append(midi.TimeSignatureEvent(numerator = gspattern.timeSignature[0],denominator=gspattern.timeSignature[1])) # obscure events # timeSignatureEvent.set_metronome(32) # timeSignatureEvent.set_thirtyseconds(4) track.append(midi.TrackNameEvent(text= gspattern.name)) track.append(midi.SetTempoEvent(bpm=gspattern.bpm)) # Append the track to the pattern pattern.append(track) beatToTick = pattern.resolution for e in gspattern.events: startTick = int(beatToTick * e.startTime) endTick = int(beatToTick * e.getEndTime()) pitch = e.pitch channel=1 if midiMap: pitch = midiMap[e.tag[0]] if midiMap is None: track.append(midi.NoteOnEvent(tick=startTick, velocity=e.velocity, pitch=pitch,channel=channel)) track.append(midi.NoteOffEvent(tick=endTick, velocity=e.velocity, pitch=pitch,channel=channel)) track.append(midi.EndOfTrackEvent(tick=int(gspattern.duration * beatToTick))) # make tick relatives track.sort(key=lambda e:e.tick) track.make_ticks_rel() # Save the pattern to disk if(not os.path.exists(folderPath)) : os.makedirs(folderPath) name = name or gspattern.name name = name or "test" if not ".mid" in name: name+=".mid" exportedPath = os.path.join(folderPath,name) midi.write_midifile(exportedPath, pattern) return exportedPath
#write a simplistic example midi.write_midifile("{}.mid".format(name), pattern) #write the same example that utileDemo.py writes, but without using pattern repetition #It was created by copying the output.mid file to the python3-midi folder and cd'ing there #and using python3-midi for generating the code from an existing binary MIDI file. #I then pasted the generated code in here # #midi.write_midifile("{}.mid".format(name), pattern) pattern1 = midi.Pattern(format=1, resolution=960, tracks=\ [midi.Track(\ [midi.SetTempoEvent(tick=0, data=[7, 161, 32]), midi.EndOfTrackEvent(tick=0, data=[])]), midi.Track(\ [midi.TrackNameEvent(tick=0, text='Treble', data=[84, 114, 101, 98, 108, 101]), midi.NoteOnEvent(tick=0, channel=0, data=[76, 100]), midi.NoteOffEvent(tick=960, channel=0, data=[76, 100]), midi.NoteOnEvent(tick=0, channel=0, data=[74, 100]), midi.NoteOffEvent(tick=960, channel=0, data=[74, 100]), midi.NoteOnEvent(tick=0, channel=0, data=[72, 100]), midi.NoteOffEvent(tick=960, channel=0, data=[72, 100]), midi.NoteOnEvent(tick=0, channel=0, data=[71, 100]), midi.NoteOffEvent(tick=960, channel=0, data=[71, 100]), midi.NoteOnEvent(tick=0, channel=0, data=[69, 100]), midi.NoteOffEvent(tick=2880, channel=0, data=[69, 100]), midi.NoteOnEvent(tick=960, channel=0, data=[77, 100]), midi.NoteOffEvent(tick=960, channel=0, data=[77, 100]), midi.NoteOnEvent(tick=0, channel=0, data=[76, 100]), midi.NoteOffEvent(tick=960, channel=0, data=[76, 100]), midi.NoteOnEvent(tick=0, channel=0, data=[74, 100]),
def write_midifile(melody, chords, pattern, filename): beat = 4 def get_chord_pitches(chord): base = chord_base[chord[0]] if 'm' in chord: return (base, base + 3, base + 7) else: return (base, base + 4, base + 7) pattern = copy.deepcopy(pattern) del pattern[1] track_melody = midi.Track() pattern.append(track_melody) track_melody.append(midi.ProgramChangeEvent(tick=0, value=0, channel=0)) track_melody.append( midi.TrackNameEvent(tick=0, text='Track 1#', data=[84, 114, 97, 99, 107, 32, 49])) pre_note = None for note in melody: if pre_note != None: tick = int( (note.position - pre_note.position) * pattern.resolution) track_melody.append( midi.NoteOffEvent(tick=tick, pitch=pre_note.pitch, channel=0)) track_melody.append( midi.NoteOnEvent(tick=0, velocity=100, pitch=note.pitch, channel=0)) pre_note = note track_melody.append( midi.NoteOffEvent(tick=pattern.resolution * 1, pitch=pre_note.pitch, channel=0)) track_melody.append(midi.EndOfTrackEvent(tick=0, channel=0)) track_chord = midi.Track() pattern.append(track_chord) track_chord.append(midi.ProgramChangeEvent(tick=0, value=0, channel=1)) track_chord.append( midi.TrackNameEvent(tick=0, text='Track 2#', data=[84, 114, 97, 99, 107, 32, 49], channel=1)) pre_chord = None for chord in chords: if pre_chord != None: tick = int((chord[0] - pre_chord[0]) * pattern.resolution) track_chord.append( midi.NoteOnEvent(tick=tick, velocity=0, pitch=0, channel=1)) for pitch in get_chord_pitches(pre_chord[1]): track_chord.append( midi.NoteOnEvent(tick=0, velocity=0, pitch=pitch, channel=1)) for pitch in get_chord_pitches(chord[1]): track_chord.append( midi.NoteOnEvent(tick=0, velocity=80, pitch=pitch, channel=1)) pre_chord = chord for i, pitch in enumerate(get_chord_pitches(pre_chord[1])): track_chord.append( midi.NoteOnEvent(tick=pattern.resolution * beat if i == 0 else 0, velocity=0, pitch=pitch, channel=1)) track_chord.append(midi.EndOfTrackEvent(tick=0, channel=1)) midi.write_midifile(filename, pattern)