def build_midi(pitches: Dict, durations, onsets, selection=None, tempo=120) -> MIDIFile: # create your MIDI object midi_file = MIDIFile(1) # only 1 track track = 0 # the only track time = 0 # start at the beginning midi_file.addTrackName(track, time, "Sample Track") midi_file.addTempo(track, time, tempo) channel = 0 volume = 100 keys = pitches.keys() min_onset = 0 if selection is not None: keys = [k for k in keys if k in selection] min_onset = min([onsets[k] for k in keys if k in onsets]) for objid in keys: if (objid in onsets) and (objid in durations): pitch = pitches[objid] onset = onsets[objid] - min_onset duration = durations[objid] midi_file.addNote(track, channel, pitch, onset, duration, volume) return midi_file
def save_genome_to_midi(filename: str, genome: Genome, num_bars: int, num_notes: int, num_steps: int, pauses: bool, key: str, scale: str, root: int, bpm: int): melody = genome_to_melody(genome, num_bars, num_notes, num_steps, pauses, key, scale, root) if len(melody["notes"][0]) != len(melody["beat"]) or len( melody["notes"][0]) != len(melody["velocity"]): raise ValueError mf = MIDIFile(1) track = 0 channel = 0 time = 0.0 mf.addTrackName(track, time, "Sample Track") mf.addTempo(track, time, bpm) for i, vel in enumerate(melody["velocity"]): if vel > 0: for step in melody["notes"]: mf.addNote(track, channel, step[i], time, melody["beat"][i], vel) time += melody["beat"][i] os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, "wb") as f: mf.writeFile(f)
def getNoteGroupCluster(vsqxPath): # Encode info into vector df = None params = None noteClusterList = [] path = PurePath(vsqxPath) vsqx = xml.dom.minidom.parse(str(path)) TEMPO = int( vsqx.getElementsByTagName('tempo') [0].childNodes[1].firstChild.data[:-2]) mf = MIDIFile(len(vsqx.getElementsByTagName('vsTrack')), removeDuplicates=False) time = 0 for trackNo, track in enumerate(vsqx.getElementsByTagName('vsTrack')): mf.addTrackName(trackNo, time, "Track {}".format(str(trackNo))) #print('track: ',trackNo) #i = 0 timeOffset = 0 prevTime = 0 durTime = 0 for noteCount, note in enumerate(track.getElementsByTagName('note')): #print(noteCount) params, noteClusterList = createNoteCluster( note, params, noteClusterList, track) #mf.addNote(trackNo, 0, getNoteData(note, 'n'), currTime / 480, getNoteData(note, 'dur') / 480, 64) #mf.addTempo(trackNo, time, TEMPO) return (params, noteClusterList)
def turnToMidi(musicls): midi = MIDIFile(1) track = 0 time = 0 channel = 0 pitch = 0 duration = 1 volume = 100 midi.addTrackName(track, time, "test") midi.addTempo(track, time, 60) music = [] for i, pitch in enumerate(musicls): if pitch[1] == True: duration = 1 / 2 midi.addNote(track, channel, pitch[0], time, duration, volume) time += 1 / 2 music.append([pitch[0], 1 / 2]) else: duration = 1 midi.addNote(track, channel, pitch[0], time, duration, volume) time += 1 music.append([pitch[0], 1]) print(music) midi_file = open("mary.mid", 'wb') midi.writeFile(midi_file) midi_file.close()
def save_melody_to_midi(melody, filename: str): if len(melody["notes"][0]) != len(melody["beat"]) or len( melody["notes"][0]) != len(melody["velocity"]): raise ValueError mf = MIDIFile(1) track = 0 channel = 0 time = 0.0 mf.addTrackName(track, time, "Sample Track") mf.addTempo(track, time, bpm) for i, vel in enumerate(melody["velocity"]): if vel > 0: for step in melody["notes"]: mf.addNote(track, channel, step[i], time, melody["beat"][i], vel) time += melody["beat"][i] os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, "wb") as f: mf.writeFile(f)
def write_midi(melody, id): old_pitch_list = melody.strip().split(' ') pitch_list = [] for i in range(len(old_pitch_list)): if i % 2 == 0: pitch_list.append(old_pitch_list[i]) # return pitch_list # create your MIDI object mf = MIDIFile(1) # only 1 track track = 0 # the only track time = 0 # start at the beginning mf.addTrackName(track, time, "Sample Track" + str(id)) mf.addTempo(track, time, 120) # add some notes channel = 0 volume = 100 for note in pitch_list: pitch = pitch_dict[note] duration = 1 # 1 beat long mf.addNote(track, channel, pitch, time, duration, volume) time += 2 # write it to disk with open("/home/ubuntu/team15/midi/record/" + str(id) + '.txt', 'w') as outtxt: for pitch in pitch_list: outtxt.write("%s\n" % pitch) midi_name = str(id) + ".mid" with open("/home/ubuntu/team15/midi/" + midi_name, 'wb') as outf: mf.writeFile(outf) return midi_name
async def make_midi(self, tempo: int, data: str) -> MIDIFile: midi_file = MIDIFile(1) midi_file.addTrackName(0, 0, 'beep boop') midi_file.addTempo(0, 0, tempo) channel_datas = data.split('|') log.debug(f'creating MIDI out of "{data}"') for channel_index, channel_data in enumerate(channel_datas): await self.add_channel(midi_file, channel_index, channel_data) log.info('successfully created MIDI') return midi_file
def writeToMIDI(self, path, tempo=120, duration=1): # Loop through all notes Melody = list(zip(self.MIDIvalues, self.notesLoc)) MIDInotes = [] MIDItimes = [] # Creating two lists of the MIDIvalues and corresponding times for note, cord in Melody: # MIDInotes will store the track on the first slot and the noteValue on the 2nd slot if (note == 'S'): MIDInotes.append([1, 37]) else: MIDInotes.append([0, note]) # we multiply cord[0] by 16 since there are 16 counts in each row MIDItimes.append(cord[0] * 16 + cord[1]) # create your MIDI object (fixed values at the moment) mf = MIDIFile(2) # 2 tracks # tempo = 120 volume = 100 # duration = 1 time = 0 track = 0 mf.addTrackName(track, time, "Sample Track") mf.addTempo(track, time, tempo) # Adding Notes to Channel 0 channel = 0 melody = list(zip(MIDInotes, MIDItimes)) # If track is zero it will store on channel zero (Piano) # If track is one it will store on channel nine (Drums) for pitch, time in melody: # print('Adding to track {}, channel {}, note {}, time {}'.format(pitch[0], pitch[0]*9, pitch[1], time/4)) # Dividing time by 4 seems to get it to work mf.addNote(pitch[0], pitch[0] * 9, pitch[1], time / 4, duration, volume) # MyMIDI.addNote(track, channel, pitch, time, duration, volume) with open(path, 'wb') as outf: mf.writeFile(outf) return mf
def midi_gen(self, track_minutes = 2, tempo = 120, track=0, start_time=0, channel=0): MyMIDI = MIDIFile(1, adjust_origin=False) # One track, defaults to format 1 (tempo track is created automatically) MyMIDI.addTempo(track, start_time, self.tempo) # duration_list = [] elapsed_time = 0 data = zip(self.note_lengths, self.note_spacings, self.mapped_notes, self.note_velocities) for i, tup in enumerate(data): note_length, note_spacing, mapped_note, note_velocity = tup elapsed_time += note_spacing MyMIDI.addNote(track, channel, mapped_note, start_time + elapsed_time, note_spacing, note_velocity) MyMIDI.addTrackName(0,0,self.name) # duration_list += [note_spacing] if elapsed_time > track_minutes * tempo: break with open(self.name, "wb") as output_file: MyMIDI.writeFile(output_file)
def write_midi_file(self, notes): now = gmtime() midi_content = MIDIFile(1) midi_content.addTrackName(0, 0, strftime("%#m/%d %H:%M:%S", now)) # filtered_notes = {k: notes[k] for k in notes.keys() if any(xk in k for xk in ['g2', 'g3', 'g4'])} filtered_notes = notes [[ midi_content.addNote(n.track, n.channel, n.pitch, n.start, n.duration, n.volume) for n in v ] for v in filtered_notes.values()] with open('c:/temp/' + strftime("%Y%m%d %H%M%S", now) + '.mid', "wb+") as _: midi_content.writeFile(_) _.close()
def music_generation(matrix, index): FILE = MIDIFile(1) TRACK = 0 TIME = 0 FILE.addTrackName(TRACK, TIME, "Sample Track") FILE.addTempo(TRACK, TIME, 120) CHANNEL = 0 VOLUME = 100 for beat in range(16): for i in range(36): if matrix[beat][i] == 1: note = range(36)[i] + 45 FILE.addNote(TRACK, CHANNEL, note, beat, NEGRA, VOLUME) with open("output" + str(index) + ".mid", 'wb') as outf: FILE.writeFile(outf)
def create_track(midi_instance: MIDIFile, track: int, channel: int, tempo: int, track_name: str = ''): """ :param midi_instance: :param track: :param channel: :param tempo: :param track_name :return: Track """ # assume a static tempo midi_instance.addTempo(track=track, time=0, tempo=tempo) midi_instance.addTrackName(track=track, time=0, trackName=track_name) return Track(midi_instance, track, channel, tempo, track_name)
def convert(self, tune: Tune, output_file_path: str): midi_file = MIDIFile( numTracks=len(tune.tracks) ) midi_file.addTempo(0, 0, tune.bpm) length_of_quarter_seconds = 60 / tune.bpm for idx, track in enumerate(tune.tracks): midi_file.addTrackName(idx, 0.0, 'Track ' + str(idx)) midi_file.addProgramChange(idx, idx, 0.0, self._generate_program_number(track.timbre)) for note in track.notes: start_time_in_quarters = note.start_time_seconds / length_of_quarter_seconds length_in_quarters = (note.end_time_seconds - note.start_time_seconds) / length_of_quarter_seconds midi_file.addNote(idx, idx, note.note, start_time_in_quarters, length_in_quarters, round(note.velocity * 127)) with open(output_file_path, "wb") as output_file: midi_file.writeFile(output_file)
def write_midi(input_data, output_file, mode="pitch"): midi = MIDIFile(1) midi.addTrackName(track=0, time=0, trackName="Sample Track") midi.addTempo(track=0, time=0, tempo=BPM) for track in range(len(input_data)): if mode == "both" and track >= len(input_data) // 2: break midi.addProgramChange(0, track, 0, program=INSTRUMENTS[track]) track_data = input_data[track] time_per_note = SONG_LEN / len(track_data) for i, note in enumerate(track_data): z = percentile(track_data, note) if mode == "both": volume_track = input_data[track + len(input_data) // 2] index = int(i * len(volume_track) / len(track_data)) volume_z = percentile(volume_track, volume_track[index]) volume = int(volume_z * 100) + 1 assert 127 > volume >= 0 midi.addNote(track=0, channel=track, pitch=get_pitch(z * TOTAL_RANGE), time=time_per_note * i, duration=time_per_note, volume=volume) elif mode == "pitch": midi.addNote(track=0, channel=track, pitch=get_pitch(z * TOTAL_RANGE), time=time_per_note * i, duration=time_per_note, volume=100) elif mode == "volume": midi.addNote(track=0, channel=track, pitch=60 + 12 * track, time=time_per_note * i, duration=time_per_note, volume=int(z * 100)) with open(output_file, 'wb') as binfile: midi.writeFile(binfile)
def simulate_drum_track(pattern: List[int]): """Stitches together a series of drum patterns into a MIDI file for use elsewhere.""" drum_track_idxs, drum_groups = read_drum_groups(READ_PATH) num_tracks = max(drum_track_idxs) + 1 # Generate the core measures to work with measures = list() # Note, there must be a worksheet defined for each unique measure generated. The suffix of the worksheet name # must match the identifier in the pattern list. num_unique_measures = max(pattern) + 1 for i in range(num_unique_measures): worksheet_name = HITS_SHEET + '_' + str(i) drum_hits = read_drum_hits(READ_PATH, worksheet_name) measure = generate_measure(num_tracks, drum_groups, drum_hits) measures.append(measure) # Setup final MIDI container for the file that will be written to disk midi_file = MIDIFile(num_tracks) for idx in drum_track_idxs: # Pull the details of the track name from the name of the drum group and augment with date time info track_name = ', '.join([dg.name for dg in drum_groups if dg.track == idx] + [strftime("%m%d %H%M", now)]) midi_file.addTrackName(idx, 0, track_name) # Assemble the final set from the individual patterns # Each 'p' in the pattern reflects the measure identifier to use in the pattern for i, p in enumerate(pattern): mx = measures[p] measure_tick = mx.ticks_per_quarternote * beats_measure * i # Transfer the NoteOn events from measure container to the final container as defined by the measure pattern. # Adjust the timing to account for the measure. Effectively an in place operation. # for idx in range(1, len(mx.tracks)): for idx, track in enumerate(mx.tracks): for evt in filter(lambda e: e.evtname == 'NoteOn', track.eventList): midi_file.addNote(track=idx, channel=0, pitch=evt.pitch, time=mx.tick_to_quarter(measure_tick + evt.tick), duration=mx.tick_to_quarter(evt.duration), volume=evt.volume) with open('c:/temp/' + strftime("%Y%m%d %H%M%S", now) + '.mid', "wb+") as f: midi_file.writeFile(f) f.close()
def make_midi_file(tempo, list): # list een lijst met sequences voor elk spoor (stapjes zijn 16e noten) midi_seq = MIDIFile(1) # maakt een track track = 0 # eertse track midi_time = 0 # begin aan het begin (is de tijd in 16e noten) midi_seq.addTrackName(track, midi_time, 'Euclidean Sequence') # geef naam midi_seq.addTempo(track, midi_time, tempo) # geef tempo channel = 9 # zet alles op midi channel 10 volume = 100 # alle vel. waardes op 100 pitch = 36 # starting pitch op 36 for i in list: # pak een sequence uit de lijst midi_time = 0 # reset time for j in i: # ga elk stapje in de sequence af midi_seq.addNote(track, channel, pitch, midi_time / 4, j / 4, volume) # voeg noot toe (per 16e ipv kwart) midi_time = midi_time + j # update tijd voor de midifile door er de stapgrootte bij op te tellen pitch = pitch + 1 # laat nieuwe sequence op de pitch value boven de vorige sequence beginnen with open('Euclidean Sequence.mid', 'wb') as output: midi_seq.writeFile(output) # maak de MIDI-file
def save_midi(outfile, notes, tempo): track = 0 time = 0 midifile = MIDIFile(1) # Add track name and tempo. midifile.addTrackName(track, time, "MIDI TRACK") midifile.addTempo(track, time, tempo) channel = 0 volume = 100 for note in notes: onset = note[0] * (tempo / 60.) duration = note[1] * (tempo / 60.) # duration = 1 pitch = int(note[2]) midifile.addNote(track, channel, pitch, onset, duration, volume) with open(outfile, 'wb') as file: midifile.writeFile(file)
def turnToMidi(musicls, connected): midi = MIDIFile(1) track = 0 time = 0 channel = 0 pitch = 0 duration = 1 volume = 100 midi.addTrackName(track, time, "test") midi.addTempo(track, time, 60) music = [] for i, pitch in enumerate(musicls): if i in connected2 and pitch != musicls[i - 1]: duration = 1 / 4 midi.addNote(track, channel, pitch, time, duration, volume) time += 1 / 4 music.append([pitch, 1 / 4]) elif i in connected and i + 1 in connected2 and pitch != musicls[i + 1]: duration = 3 / 4 midi.addNote(track, channel, pitch, time, duration, volume) time += 3 / 4 music.append([pitch, 3 / 4]) elif i in connected or i - 1 in connected: duration = 1 / 2 midi.addNote(track, channel, pitch, time, duration, volume) time += 1 / 2 music.append([pitch, 1 / 2]) else: duration = 1 midi.addNote(track, channel, pitch, time, duration, volume) time += 1 music.append([pitch, 1]) print(music) midi_file = open("mary.mid", 'wb') midi.writeFile(midi_file) midi_file.close()
while going: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() if event.type == pygame.MOUSEBUTTONUP: pos = pygame.mouse.get_pos() x, y = pos #If record button is pressed, make a new midi file to record the notes in, #set the current time as start time to keep track of note timings, #change the button to recording, and toggle recording and going variables so #the program enters the recording loop if 125 > x > 75 and 145 > y > 95: mf = MIDIFile(1) starttime = time.time() mf.addTrackName(track, 0, "Track") mf.addTempo(track, 0, 60) pygame.draw.rect(screen, bright_red, (60, 80, 80, 80)) text_surface = my_font.render("RECORDING", True, WHITE) rect = text_surface.get_rect(center=(100, 120)) screen.blit(text_surface, rect) RECORDING = True going = False #If play button is pressed if 225 > x > 175 and 145 > y > 95: #If it was playing, stop playing the recorded file and change the button #to play. Set playing to False so the music would not play again. if playing: pygame.mixer.music.stop() playing = False pygame.draw.rect(screen, green, (160, 80, 80, 80))
# # Demo program for asking user for some note(s), then write them to # a MIDI file using midiutil # https://pypi.org/project/MIDIUtil # from midiutil import MIDIFile note = int(input("Enter a note: ")) velocity = int(input("Velocity: ")) mf = MIDIFile(1) track = 0 time = 0 mf.addTrackName(track, time, "Beat Sample Track") mf.addTempo(track, time, 120) # # Format: # mf.addNote(track, channel, pitch, time, duration, velocity) # mf.addNote(0, 0, note, 2, 1, velocity) with open("symphony.midi", 'wb') as outf: mf.writeFile(outf)
r.draw(img, (0, 0, 255), 2) cv2.imwrite("res.png", img) open_file("res.png") for note_group in note_groups: print([note.note + " " + note.sym for note in note_group]) midi = MIDIFile(1) track = 0 time = 0 channel = 0 volume = 100 midi.addTrackName(track, time, "Track") midi.addTempo(track, time, 140) for note_group in note_groups: duration = None for note in note_group: note_type = note.sym if note_type == "1": duration = 4 elif note_type == "2": duration = 2 elif note_type == "4,8": duration = 1 if len(note_group) == 1 else 0.5 pitch = note.pitch midi.addNote(track, channel, pitch, time, duration, volume) time += duration
capo = parse_data['capo'] # create midi object number_of_tracks = parse_data['number_of_tracks'] MyMIDI = MIDIFile( number_of_tracks ) # One track, defaults to format 1 (tempo track is created automatically) track = 0 # channel can have multiple tracks # for each stream/track for stream in list(parse_data['streams'].keys()): time = 0 # In beats ( quarter notes ) # add track name MyMIDI.addTrackName(track, time, stream) # add tempo MyMIDI.addTempo(track, time, tempo) # add notes and chords for note_chord in parse_data['streams'][stream]: if note_chord[0] == 'note': string = note_chord[1] fret = note_chord[2] pitch = strings[string] + capo + fret MyMIDI.addNote(track, channel, pitch, time, duration, volume) elif note_chord[0] == 'chord':
step_size += direction logging.debug(f'step_size: {step_size}') else: logging.info('accepted proposal') result.append(prop_sp) prev_interval = prop_interval break return result sm = cg.ScaleManager() cp_scale = sm.build_scale() midi_content = MIDIFile(2) midi_content.addTrackName(0, 0, 'cantus firmus') midi_content.addTrackName(1, 0, 'counterpoint') cf_tune = cg.Tune( cp_scale, ['C1', 'D1', 'F1', 'E1', 'F1', 'G1', 'A1', 'G1', 'E1', 'D1', 'C1']) cp_tune = cg.Tune(cp_scale, real_cp2(cp_scale, cf_tune)) for i, v in enumerate(cf_tune.mps): midi_content.addNote(0, 0, v, i, 1, 100) for i, v in enumerate(cp_tune.mps): midi_content.addNote(1, 0, v, i + 0.25, 1, 100) with open('c:/temp/test.mid', "wb+") as f: midi_content.writeFile(f)
midiTrackCount = args.tracks if args.tempo: tempo = args.tempo if args.volume: volume = args.volume if args.output: outputFileName = args.output convert = args.convert_to_mp3 # Define the MIDI info MyMIDI = MIDIFile(midiTrackCount) MyMIDI.addTempo(0, 0, tempo) for i in range(0, midiTrackCount): print("Core #" + str(i + 1)) MyMIDI.addTrackName(i, 0, "Core #" + str(i + 1)) # Define clamp function def clamp(n, smallest, largest): return max(smallest, min(n, largest)) def genNote(pitch_core, duration_core, track): # pitch_core = CPU core to use for note pitch # duration_core = CPU core to use for note duration # channel = MIDI channel for note # track = MIDI track for note # Set pitch based on CPU core usage pitch = int(psutil.cpu_percent(interval=0.1, percpu=True)[pitch_core]) + 15
############################################################################ # A sample program to create a single-track MIDI file, add a note, # and write to disk. ############################################################################ from midiutil import MIDIFile # import random # Create the MIDIFile Object MyMIDI = MIDIFile(1) # Add track name and tempo. The first argument to addTrackName and # addTempo is the time to write the event. track = 0 time = 0 name = input("Enter Name:") MyMIDI.addTrackName(track, time, name) MyMIDI.addTempo(track, time, 212) MyMIDI.addProgramChange(track, 0, 0, 0) # 40 48 50 while True: time = 0 sequence = input("Enter Sequence, Q To Quit: \n") if sequence == 'Q': break chords_r = sequence.split("\n") chords = [chord.split(",") for chord in chords_r] for i in range(len(chords)): # Add a note. addNote expects the following information: channel = 0 volume = 100 for note in chords[i]: length = 1
def create_midi_file(staves, track_name): # Create the MIDIFile Object MyMIDI = MIDIFile(1) # Add track name and tempo. The first argument to addTrackName and # addTempo is the time to write the event. track = 0 time = 0 MyMIDI.addTrackName(track, time, "Sample Track") MyMIDI.addTempo(track, time, 120) for stave in staves: #create_midi_per_stave(stave.symbols,MyMIDI,track) # Add a note. addNote expects the following information: channel = 0 duration = 1 volume = 100 i = 0 """symbols = [Symbol("G-clef",0),Symbol("quarter-note",6),Symbol("quarter-note",6),Symbol("quarter-note",7),Symbol("quarter-note",8), Symbol("quarter-note",8),Symbol("quarter-note",7),Symbol("quarter-note",6),Symbol("quarter-note",5),Symbol("quarter-note",4), Symbol("quarter-note",4),Symbol("quarter-note",5),Symbol("quarter-note",6),Symbol("quarter-note",6),Symbol("quarter-note",5),Symbol("half-note",5)]""" G_clef = { 1: notes.D4, 2: notes.E4, 3: notes.F4, 4: notes.G4, 5: notes.A4, 6: notes.B4, 7: notes.C5, 8: notes.D5, 9: notes.E5, 10: notes.F5 } F_clef = { 1: notes.F3, 2: notes.G3, 3: notes.A3, 4: notes.B3, 5: notes.C4, 6: notes.D4, 7: notes.E4, 8: notes.F4, 9: notes.G4, 10: notes.A4 } clef = G_clef for symbol in stave.symbols: if symbol.label == "G_clef": clef = G_clef # elif symbol.label == "F_clef": # clef = F_clef for i in range(len(stave.symbols)): print(i) if stave.symbols[i].position_in_stave == 0: continue if stave.symbols[i].label == "sixteenth_note": duration = 0.25 pitch = clef[stave.symbols[i].position_in_stave].value MyMIDI.addNote(track, channel, pitch, time, duration, volume) time = time + duration if stave.symbols[i].label == "eighth_note": duration = 0.5 pitch = clef[stave.symbols[i].position_in_stave].value MyMIDI.addNote(track, channel, pitch, time, duration, volume) time = time + duration elif stave.symbols[i].label == "quarter_note": duration = 1 pitch = clef[stave.symbols[i].position_in_stave].value MyMIDI.addNote(track, channel, pitch, time, duration, volume) time = time + duration elif stave.symbols[i].label == "half_note": duration = 2 pitch = clef[stave.symbols[i].position_in_stave].value MyMIDI.addNote(track, channel, pitch, time, duration, volume) time = time + duration elif stave.symbols[i].label == "whole_note": duration = 4 pitch = clef[stave.symbols[i].position_in_stave].value MyMIDI.addNote(track, channel, pitch, time, duration, volume) time = time + duration """if i != 0 : if symbols[i-1].label == "sharp": pitch=stave[symbols[i].position_in_stave ].value+1 elif symbols[i-1].label == "flat": pitch = stave[symbols[i].position_in_stave ].value-1""" print("anything") # And write it to disk. with open("media\\" + track_name + ".mid", 'wb') as binfile: MyMIDI.writeFile(binfile)
def handle(self, argv=None): """ Main function. Parses command, load settings and dispatches accordingly. """ help_message = "Please supply chord progression!. See --help for more options." parser = argparse.ArgumentParser( description= 'chords2midi - Create MIDI files from written chord progressions.\n' ) parser.add_argument('progression', metavar='U', type=str, nargs='*', help=help_message) parser.add_argument('-B', '--bassline', action='store_true', default=False, help='Throw an extra bassline on the pattern') parser.add_argument('-b', '--bpm', type=int, default=80, help='Set the BPM (default 80)') parser.add_argument('-t', '--octave', type=str, default='4', help='Set the octave(s) (ex: 3,4) (default 4)') parser.add_argument('-i', '--input', type=str, default=None, help='Read from an input file.') parser.add_argument('-k', '--key', type=str, default='C', help='Set the key (default C)') parser.add_argument('-n', '--notes', type=int, default=99, help='Notes in each chord (default all)') parser.add_argument('-N', '--name', type=str, default='track', help='Set a name for the MIDI track') parser.add_argument('-d', '--duration', type=float, default=1.0, help='Set the chord duraction (default 1)') parser.add_argument( '-D', '--directory', action='store_true', default=False, help= 'Output the contents to the directory of the input progression.') parser.add_argument( '-H', '--humanize', type=float, default=0.0, help= 'Set the amount to "humanize" (strum) a chord, in ticks - try .11 (default 0.0)' ) parser.add_argument( '-o', '--output', type=str, help= 'Set the output file path. Default is the current key and progression in the current location.' ) parser.add_argument( '-O', '--offset', type=float, default=0.0, help='Set the amount to offset each chord, in ticks. (default 0.0)' ) parser.add_argument('-p', '--pattern', type=str, default=None, help='Set the pattern. Available patterns: ' + (', '.join(patterns.keys()))) parser.add_argument( '-r', '--reverse', action='store_true', default=False, help='Reverse a progression from C-D-E format into I-II-III format' ) parser.add_argument('-v', '--version', action='store_true', default=False, help='Display the current version of chords2midi') args = parser.parse_args(argv) self.vargs = vars(args) if self.vargs['version']: version = pkg_resources.require("chords2midi")[0].version print(version) return # Support `c2m I III V and `c2m I,III,V` formats. if not self.vargs['input']: if len(self.vargs['progression']) < 1: print("You need to supply a progression! (ex I V vi IV)") return if len(self.vargs['progression']) < 2: progression = self.vargs['progression'][0].split(',') else: progression = self.vargs['progression'] else: with open(self.vargs['input']) as fn: content = ''.join(fn.readlines()).strip() content = content.replace('\n', ' ').replace(',', ' ') progression = content.split(' ') og_progression = progression # If we're reversing, we don't need any of the MIDI stuff. if self.vargs['reverse']: result = "" key = self.vargs['key'] for item in progression: comps = pychord.Chord(item).components() position = determine(comps, key, True)[0] if 'M' in position: position = position.upper() position = position.replace('M', '') if 'm' in position: position = position.lower() position = position.replace('m', '') if 'B' in position: position = position + "b" position = position.replace('B', '') result = result + position + " " print(result) return track = 0 channel = 0 ttime = 0 duration = self.vargs['duration'] # In beats tempo = self.vargs['bpm'] # In BPM volume = 100 # 0-127, as per the MIDI standard bar = 0 humanize_interval = self.vargs['humanize'] directory = self.vargs['directory'] num_notes = self.vargs['notes'] offset = self.vargs['offset'] key = self.vargs['key'] octaves = self.vargs['octave'].split(',') root_lowest = self.vargs.get('root_lowest', False) bassline = self.vargs['bassline'] pattern = self.vargs['pattern'] # Could be interesting to do multiple parts at once. midi = MIDIFile(1) midi.addTempo(track, ttime, tempo) midi.addTrackName(0, 0, self.vargs["name"]) ## # Main generator ## has_number = False progression_chords = [] # Apply patterns if pattern: if pattern not in patterns.keys(): print("Invalid pattern! Must be one of: " + (', '.join(patterns.keys()))) return new_progression = [] input_progression = progression[:] # 2.7 copy pattern_mask = patterns[pattern] pattern_mask_index = 0 current_chord = None while True: pattern_instruction = pattern_mask[pattern_mask_index] if pattern_instruction == "N": if len(input_progression) == 0: break current_chord = input_progression.pop(0) new_progression.append(current_chord) elif pattern_instruction == "S": new_progression.append(current_chord) elif pattern_instruction == "X": new_progression.append("X") if pattern_mask_index == len(pattern_mask) - 1: pattern_mask_index = 0 else: pattern_mask_index = pattern_mask_index + 1 progression = new_progression # We do this to allow blank spaces for chord in progression: # This is for # 'I', 'VI', etc progression_chord = to_chords(chord, key) if progression_chord != []: has_number = True # This is for 'C', 'Am', etc. if progression_chord == []: try: progression_chord = [pychord.Chord(chord).components()] except Exception: # This is an 'X' input progression_chord = [None] chord_info = {} chord_info['notes'] = progression_chord[0] if has_number: chord_info['number'] = chord else: chord_info['name'] = chord if progression_chord[0]: chord_info['root'] = progression_chord[0][0] else: chord_info['root'] = None progression_chords.append(chord_info) # For each input.. previous_pitches = [] for chord_index, chord_info in enumerate(progression_chords): # Unpack object chord = chord_info['notes'] # NO_OP if chord == None: bar = bar + 1 continue root = chord_info['root'] root_pitch = pychord.utils.note_to_val( notes.int_to_note(notes.note_to_int(root))) # Reset internals humanize_amount = humanize_interval pitches = [] all_new_pitches = [] # Turns out this algorithm was already written in the 1800s! # https://en.wikipedia.org/wiki/Voice_leading#Common-practice_conventions_and_pedagogy # a) When a chord contains one or more notes that will be reused in the chords immediately following, then these notes should remain, that is retained in the respective parts. # b) The parts which do not remain, follow the law of the shortest way (Gesetze des nachsten Weges), that is that each such part names the note of the following chord closest to itself if no forbidden succession XXX GOOD NAME FOR A BAND XXX arises from this. # c) If no note at all is present in a chord which can be reused in the chord immediately following, one must apply contrary motion according to the law of the shortest way, that is, if the root progresses upwards, the accompanying parts must move downwards, or inversely, if the root progresses downwards, the other parts move upwards and, in both cases, to the note of the following chord closest to them. root = None for i, note in enumerate(chord): # Sanitize notes sanitized_notes = notes.int_to_note(notes.note_to_int(note)) pitch = pychord.utils.note_to_val(sanitized_notes) if i == 0: root = pitch if root: if root_lowest and pitch < root: # or chord_index is 0: pitch = pitch + 12 # Start with the root lowest all_new_pitches.append(pitch) # Reuse notes if pitch in previous_pitches: pitches.append(pitch) no_melodic_fluency = False # XXX: vargify if previous_pitches == [] or all_new_pitches == [] or pitches == [] or no_melodic_fluency: pitches = all_new_pitches else: # Detect the root direction root_upwards = None if pitches[0] >= all_new_pitches[0]: root_upwards = True else: root_upwards = False # Move the shortest distance if pitches != []: new_remaining_pitches = list(all_new_pitches) old_remaining_pitches = list(previous_pitches) for i, new_pitch in enumerate(all_new_pitches): # We're already there if new_pitch in pitches: new_remaining_pitches.remove(new_pitch) old_remaining_pitches.remove(new_pitch) continue # Okay, so need to find the overall shortest distance from the remaining pitches - including their permutations! while len(new_remaining_pitches) > 0: nearest_distance = 9999 previous_index = None new_index = None pitch_to_add = None for i, pitch in enumerate(new_remaining_pitches): # XXX: DRY # The Pitch pitch_to_test = pitch nearest = min(old_remaining_pitches, key=lambda x: abs(x - pitch_to_test)) old_nearest_index = old_remaining_pitches.index( nearest) if nearest < nearest_distance: nearest_distance = nearest previous_index = old_nearest_index new_index = i pitch_to_add = pitch_to_test # +12 pitch_to_test = pitch + 12 nearest = min(old_remaining_pitches, key=lambda x: abs(x - pitch_to_test)) old_nearest_index = old_remaining_pitches.index( nearest) if nearest < nearest_distance: nearest_distance = nearest previous_index = old_nearest_index new_index = i pitch_to_add = pitch_to_test # -12 pitch_to_test = pitch - 12 nearest = min(old_remaining_pitches, key=lambda x: abs(x - pitch_to_test)) old_nearest_index = old_remaining_pitches.index( nearest) if nearest < nearest_distance: nearest_distance = nearest previous_index = old_nearest_index new_index = i pitch_to_add = pitch_to_test # Before we add it - just make sure that there isn't a better place for it. pitches.append(pitch_to_add) del old_remaining_pitches[previous_index] del new_remaining_pitches[new_index] # This is for the C E7 type scenario if len(old_remaining_pitches) == 0: for x, extra_pitch in enumerate( new_remaining_pitches): pitches.append(extra_pitch) del new_remaining_pitches[x] # Final check - can the highest and lowest be safely folded inside? max_pitch = max(pitches) min_pitch = min(pitches) index_max = pitches.index(max_pitch) folded_max = max_pitch - 12 if (folded_max > min_pitch) and (folded_max not in pitches): pitches[index_max] = folded_max max_pitch = max(pitches) min_pitch = min(pitches) index_min = pitches.index(min_pitch) folded_min = min_pitch + 12 if (folded_min < max_pitch) and (folded_min not in pitches): pitches[index_min] = folded_min # Make sure the average can't be improved # XXX: DRY if len(previous_pitches) != 0: previous_average = sum(previous_pitches) / len( previous_pitches) # Max max_pitch = max(pitches) min_pitch = min(pitches) index_max = pitches.index(max_pitch) folded_max = max_pitch - 12 current_average = sum(pitches) / len(pitches) hypothetical_pitches = list(pitches) hypothetical_pitches[index_max] = folded_max hypothetical_average = sum(hypothetical_pitches) / len( hypothetical_pitches) if abs(previous_average - hypothetical_average) <= abs(previous_average - current_average): pitches[index_max] = folded_max # Min max_pitch = max(pitches) min_pitch = min(pitches) index_min = pitches.index(min_pitch) folded_min = min_pitch + 12 current_average = sum(pitches) / len(pitches) hypothetical_pitches = list(pitches) hypothetical_pitches[index_min] = folded_min hypothetical_average = sum(hypothetical_pitches) / len( hypothetical_pitches) if abs(previous_average - hypothetical_average) <= abs(previous_average - current_average): pitches[index_min] = folded_min # Apply contrary motion else: print("Applying contrary motion!") for i, new_pitch in enumerate(all_new_pitches): if i == 0: pitches.append(new_pitch) continue # Root upwards, the rest move down. if root_upwards: if new_pitch < previous_pitches[i]: pitches.append(new_pitch) else: pitches.append(new_pitch - 12) else: if new_pitch > previous_pitches[i]: pitches.append(new_pitch) else: pitches.append(new_pitch + 12) # Bassline if bassline: pitches.append(root_pitch - 24) # Melody # Octave is a simple MIDI offset counter for octave in octaves: for note in pitches: pitch = int(note) + (int(octave.strip()) * 12) # Don't humanize bassline note if bassline and (pitches.index(note) == len(pitches) - 1): midi_time = offset + bar else: midi_time = offset + bar + humanize_amount # Write the note midi.addNote(track=track, channel=channel, pitch=pitch, time=midi_time, duration=duration, volume=volume) humanize_amount = humanize_amount + humanize_interval if i + 1 >= num_notes: break bar = bar + 1 previous_pitches = pitches ## # Output ## if self.vargs['output']: filename = self.vargs['output'] elif self.vargs['input']: filename = self.vargs['input'].replace('.txt', '.mid') else: if has_number: key_prefix = key + '-' else: key_prefix = '' filename = key_prefix + '-'.join(og_progression) + '-' + str(tempo) if bassline: filename = filename + "-bassline" if pattern: filename = filename + "-" + pattern if os.path.exists(filename): filename = key_prefix + '-'.join(og_progression) + '-' + str( tempo) + '-' + str(int(time.time())) filename = filename + '.mid' if directory: directory_to_create = '-'.join(og_progression) try: os.makedirs(directory_to_create) except OSError as exc: # Python >2.5 if exc.errno == errno.EEXIST and os.path.isdir( directory_to_create): pass else: raise filename = directory_to_create + '/' + filename with open(filename, "wb") as output_file: midi.writeFile(output_file)
if Percussion == 82: Percussion = 35 Drums[(xNote, yNote)] = Percussion Percussion += 1 track = 0 # Midi allows for multiple tracks to be written. 0 is one track, 1 is an additional track, and so on. count = 0 # This declares where the note will be placed based on beats. duration = 1 # How long a note will last (in beats). tempo = 144 # Beats Per Minute (BPM) volume = 127 # 0-127, as per the MIDI standard midi = MIDIFile(1) #Calling of the midiutil module midi.addTempo(track, count, tempo) midi.addTrackName( track, count, "Langton's Launch Jams." ) #Title of the midi file (can only be viewed in notation software) midi.addProgramChange(track, 0, count, 107) def writeMidi(ant): #Function to write the chords in the midi file x, y = (ant.curpos['x'] / 64), ( ant.curpos['y'] / 64 ) #Takes the ant's current x and y position and divides both values by 64, #this is so because the ant's position increments 64 pixels at a time. chord = Notes[int(x)][int( y)] #finds the chord in Notes based on the x and y value of the ant for i in chord: midi.addNote(track, 0, i, ant.turns, 2, volume) #Function to add the note to the midi file.
playEvent(event) #turn off the while loop to go to the next step running = False else: ti.sleep(0.001) #___________MIDISETUP____________ BPM = askUserBPM() midiFile = MIDIFile(1) track = 0 time = 0 channel = 0 duration = 1 volume = 100 midiFile.addTrackName(track, time, "eindopdracht") midiFile.addTempo(track, time, BPM) def retrievePitch(event): return event['midiNote'] def retrieveTime(event, sixteenthStep): return (int(event['timestamp'] / sixteenthStep) / 4) def addMidiNote(pitch, time): midiFile.addNote(track, channel, pitch, time, duration, volume)
############################################################################ # A sample program to create a single-track MIDI file, add a note, # and write to disk. ############################################################################ # Import the library from midiutil import MIDIFile # Create the MIDIFile Object MyMIDI = MIDIFile(1) # Add track name and tempo. The first argument to addTrackName and # addTempo is the time to write the event. track = 0 time = 0 MyMIDI.addTrackName(track, time, "Sample Track") MyMIDI.addTempo(track, time, 120) # Add a note. addNote expects the following information: channel = 0 pitch = 60 duration = 1 volume = 100 # Now add the note. MyMIDI.addNote(track, channel, pitch, time, duration, volume) # And write it to disk. with open("output.mid", 'wb') as binfile: MyMIDI.writeFile(binfile)