Example #1
3
def roll2midi(roll, notesMap, reductionRatio=128): #roll is a (1, ts, input_dim) tensor
	mid = MidiFile()

	track = MidiTrack()
	mid.tracks.append(track)

	tones = np.zeros(roll.shape[1])
	ticks = 0
	for ts in roll:
		for i in range(ts.shape[0]-1):

			if ts[i] == 1 and tones[i] == 0:
				#record note_on event
				track.append(Message('note_on', velocity=127, note=notesMap[i], time=ticks*reductionRatio))
				tones[i] = 1
				ticks = 0

			if ts[i] == 0 and tones[i] == 1:
				#record note_off event
				track.append(Message('note_off', velocity=127, note=notesMap[i], time=ticks*reductionRatio))
				tones[i] = 0
				ticks = 0

		ticks += 1

	#last pass for notes off (end of track)	
	for i in range(roll.shape[1]):
		if tones[i] == 1:
			track.append(Message('note_off', note=notesMap[i], time=ticks*reductionRatio))
			ticks = 0

	return mid
Example #2
0
def comptineN2():
    """Generate the midi file of the comptine d'un autre été"""
    mid = MidiFile()
    trackl = MidiTrack()
    trackl.name = "Left hand"
    for i in range(8):
        trackl = comp_lh1(trackl)
        trackl = comp_lh1(trackl)
        trackl = comp_lh2(trackl)
        trackl = comp_lh2(trackl)
    trackl.append(Message('note_on', note=52))
    trackl.append(Message('note_off', note=52, time=200))
    mid.tracks.append(trackl)

    trackr = MidiTrack()
    trackr.name = 'Right hand'
    trackr.append(Message('note_on', note=67, velocity=0, time=3200))
    trackr = comp_rh1(trackr)
    trackr = comp_rh2(trackr)
    trackr = comp_rh2(trackr)
    trackr = comp_rh3(trackr)
    trackr = comp_rh3(trackr, end=True)
    trackr = comp_rh4(trackr)
    trackr.append(Message('note_on', note=71))
    trackr.append(Message('note_off', note=71, time=200))
    mid.tracks.append(trackr)

    mid.ticks_per_beat = 100
    vols = generate_vol()
    mid = volume(mid, vols)
    return mid
Example #3
0
def save_to_midi(midi_info, sub_div, filename) -> None:
    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)

    Rhythm = []
    note_event = []
    BEATS = []
    for beat, event in enumerate(midi_info):
        note = event[1]
        tat_loc = event[0]

        for i in zip(tat_loc, note):
            note_event.append(i)
        BEATS.append(note_event)
        note_event = []

    ## iterate over the arrays
    for event, decode in enumerate(BEATS):
        Beat_frame = np.zeros(16)

        for element in decode:
            Beat_frame[element[0]] = element[1]

        Rhythm.append(Beat_frame)

    for Ry in Rhythm:
        for y in Ry:
            y = int((y / 1000) * 127)
            message = 'note_{}'.format('on' if y != 0 else 'off')
            track.append(Message(message, note=y, time=sub_div))

    mid.save(filename)
Example #4
0
def drum_pattern_repeat_recursion(level: Dict[str,
                                              Union[str, Dict[str,
                                                              Union[str,
                                                                    list]],
                                                    int]],
                                  drum_track: MidiTrack,
                                  ticks_per_measure: int,
                                  ticks_per_beat: int) -> None:
    """Parses, recurisvely, a drum pattern and adds note events

    :param level: The current level of the nested pattern
    :type level: Dict[str, Union[str, Dict[str, Union[str, list]], int]]
    :param drum_track: The drum track to add note events to
    :type drum_track: mido.MidiTrack
    :param ticks_per_measure: how many ticks in a measure of this pattern
    :type ticks_per_measure: int
    :param ticks_per_beat: how many ticks per beat of this file
    :type ticks_per_beat: int
    """
    if "repeat_count" in level:
        for _ in range(0, cast(int, level["repeat_count"])):
            for b in cast(
                    List[Dict[str, Union[str, Dict[str, Union[str, list]],
                                         int]]], level["subpattern"]):
                drum_pattern_repeat_recursion(b, drum_track, ticks_per_measure,
                                              ticks_per_beat)
    else:
        drum_track.append(
            Message(cast(str, level['note_event']),
                    note=drum_types[cast(str, level["drum_type"])],
                    channel=9,
                    time=int(
                        round(
                            cast(int, level["time"]) * ticks_per_beat * 4 /
                            ticks_per_measure))))
Example #5
0
def toMidi(Indexes, ticks):
    #print(Indexes)
    moments = [[] for i in range(len(Indexes) + 4)]
    current = 0
    for note in Indexes:
        decoded = indexToNote(note)
        moments[current].append(decoded[0])
        #print(current, decoded[1], len(Indexes))
        moments[current + decoded[1]].append(-decoded[0])
        current += 1
    newMid = MidiFile()
    track = MidiTrack()
    newMid.tracks.append(track)
    tick_time = round(ticks * 0.1) * 2
    for moment in moments:
        for ivent in moment:
            if (ivent < 0):
                track.append(
                    Message('note_off',
                            note=-ivent,
                            velocity=0,
                            time=tick_time))
            else:
                track.append(
                    Message('note_on', note=ivent, velocity=64,
                            time=tick_time))
    return newMid
Example #6
0
class SaveMIDI:
    def __init__(self):
        self.isrecording = False
        self.start_time = time.time()
    def start_recording(self):
        self.mid = MidiFile()
        self.track = MidiTrack()
        self.mid.tracks.append(self.track)
        self.isrecording = True
        menu.render_message("Recording started", "", 1500)
        self.restart_time()
        
    def cancel_recording(self):
        self.isrecording = False
        menu.render_message("Recording canceled", "", 1500)
        
    def add_track(self, status, note, velocity, time):
        self.track.append(Message(status, note=int(note), velocity=int(velocity), time=int(time)))
        
    def add_control_change(self, status, channel, control, value, time):
            self.track.append(Message(status, channel=int(channel), control=int(control),  value=int(value), time=int(time)))
      
    def save(self, filename):
        self.isrecording = False
        self.mid.save('Songs/'+filename+'.mid')
        menu.render_message("File saved", filename+".mid", 1500)
        
    def restart_time(self):
        self.start_time = time.time()
Example #7
0
 def handle_recording(self):
     self.log.info('Starting recording thread')
     self.log.info('Getting a handle to the sequencer...')
     self.midi_recording = self.get_midi_sequencer()
     self.log.info('Got sequencer.')
     mid = MidiFile()
     track = MidiTrack()
     mid.tracks.append(track)
     self.log.info('About to enter loop, output file: %s' % repr(self.output_file))
     last_event_time = None
     while True:
         for event in self.midi_recording.iter_pending():
             now_time = current_milli_time()
             if last_event_time is not None:
                 event.time = now_time - last_event_time
                 # Otherwise event.time stays at 0.
             last_event_time = now_time
             track.append(event)
             self.log.info('Appending event to track: %s' % event)
         if self.mode != RECORD:
             break
         time.sleep(0.001)
     self.log.info('Saving to output_file %s (filename %s)' % (repr(self.output_file), self.output_filename))
     mid.save(self.output_file)
     self.midi_recording.close()
     self.log.info('Exiting recording thread')
Example #8
0
def save_midi(path, pitches, intervals, velocities):
    """
    Save extracted notes as a MIDI file
    Parameters
    ----------
    path: the path to save the MIDI file
    pitches: np.ndarray of bin_indices
    intervals: list of (onset_index, offset_index)
    velocities: list of velocity values
    """
    file = MidiFile()
    track = MidiTrack()
    file.tracks.append(track)
    ticks_per_second = file.ticks_per_beat * 2.0

    events = []
    for i in range(len(pitches)):
        events.append(dict(type='on', pitch=pitches[i], time=intervals[i][0], velocity=velocities[i]))
        events.append(dict(type='off', pitch=pitches[i], time=intervals[i][1], velocity=velocities[i]))
    events.sort(key=lambda row: row['time'])

    last_tick = 0
    for event in events:
        current_tick = int(event['time'] * ticks_per_second)
        velocity = int(event['velocity'] * 127)
        if velocity > 127:
            velocity = 127
        pitch = int(round(hz_to_midi(event['pitch'])))
        track.append(Message('note_' + event['type'], note=pitch, velocity=velocity, time=current_tick - last_tick))
        last_tick = current_tick

    file.save(path)
Example #9
0
def guitar_pattern_repeat_recursion(level: Dict[str, Union[str, int, Dict[str, Union[str, list]]]], track: MidiTrack, sequences: List[List[List[int]]], a: int, b: int, ticks_per_measure: int, ticks_per_beat: int) -> None:
    """Parses, recurisvely, a guitar pattern and adds note_events

    :param level: The current level of the nested pattern
    :type level: Dict[str, Union[str, Dict[str, Union[str, list]], int]]
    :param track: The guitar track to add note events to
    :type track: mido.MidiTrack
    :param sequences: The array of notes
    :type sequences: List[List[List[int]]]
    :param a: The current sequence
    :type a: int
    :param b: The current chord in the sequence
    :type b: int
    :param ticks_per_measure: how many ticks in a measure of this pattern
    :type ticks_per_measure: int
    :param ticks_per_beat: how many ticks per beat of this file
    :type ticks_per_beat: int
    """
    if "repeat_count" in level:
        for _ in range(0, cast(int, level["repeat_count"])):
            for c in cast(List[Dict[str, Union[str, int, Dict[str, Union[str, list]]]]], level["subpattern"]):
                guitar_pattern_repeat_recursion(c, track, sequences, a, b, ticks_per_measure, ticks_per_beat)
    else:
        if "pitchIndex" in level:
            track.append(Message(cast(str, level['note_event']), note=sequences[a][b][cast(int, level["pitchIndex"])] + C_VAL, channel=1, time=int(round(cast(int, level["time"]) * ticks_per_beat * 4 / ticks_per_measure))))
        else:
            track.append(Message(cast(str, level['note_event']), note=sequences[a][b][0] + cast(int, level["pitch"]), channel=1, time=int(round(cast(int, level["time"]) * ticks_per_beat * 4 / ticks_per_measure))))
Example #10
0
def apply_mutation(mutantnotelist, midino, snote=50):

	mid = MidiFile(type=0) # type0 can have only one track
    
	track = MidiTrack() # note list (kind of)

	mid.tracks.append(track)
    
	time = 100
    
	# Create mutant music folder if it does not exist
	if not os.path.exists('mutantmusic'):
		os.makedirs('mutantmusic')
    
	# add the octaves back
	mutantnotelist2 = [x+snote for x in mutantnotelist]
	
	for note in mutantnotelist2:
        
		#print(note)
        
		track.append(Message('note_on', channel=0, note=int(note), time=time))
		track.append(Message('note_off', channel=0, note=int(note), time=time))
        
        
	mid.save('mutantmusic/random' + str(midino) + '.mid')
Example #11
0
    def melo_to_midi(self, input_melo):
        """ Convert Melo to Midi.
        Melo need to be sorted by time within each track,
        or negative time will occur.
        Melo can have multiple tracks though.
        
        Args:
            input_melo (Melo)
        Output:
            midifile (MidiFile)
        """
        midifile = MidiFile()
        ticks_per_beat = midifile.ticks_per_beat
        rel_melo = self._convert_melo_to_relative_time(input_melo)

        for melo_track in rel_melo.tracks:
            midi_track = MidiTrack()
            midi_track.append(Message('program_change', program=0, time=0))
            for note in melo_track.notes:
                msg = Message(note.type,
                              note=note.pitch,
                              velocity=127,
                              time=note.time * ticks_per_beat //
                              self.args.prepare_resolution)
                midi_track.append(msg)
            midifile.tracks.append(midi_track)
        return midifile
Example #12
0
def df_to_midi(dfc, ticks_per_beat, filename):
    """
    Function to write midi dataframes returned by midi_to_df() back to a midi
    file

    :param dfc: dataframe containing the meta event information returned by midi_to_df
    :type dfc: pandas.DataFrame
    :param ticks_per_beat: integer containing the ticks_per_beat information returned by mido.MidiFile
    :type ticks_per_beat: integer
    :param filename: string containing the name of the midi file to be written
    :type filename: string
    """
    outfile = MidiFile()
    outfile.ticks_per_beat = ticks_per_beat
    track = MidiTrack()
    outfile.tracks.append(track)
    for index, row in dfc.iterrows():
        if row['meta'] == True:
            if row['msg']['type'] == 'track_name':
                track = MidiTrack()
                outfile.tracks.append(track)
            track.append(MetaMessage(**row['msg']))
        else:
            track.append(Message(**row['msg']))
    outfile.save(filename)
Example #13
0
def main():
    MAX_SONG_LEN = 60
    genre_dir = '_data/midifiles/clean_midi/genres/rock/'
    all_chains = []
    for song_path in glob.glob(
            ".\\_data\\midifiles\\clean_midi\\genres\\rock\\*.mid")[1:10]:
        print(song_path)
        mid = MidiFile(song_path)
        values = []
        for i, track in enumerate(mid.tracks):
            #print('Track {}: {}'.format(i, track.name))
            for message in track:
                if not isinstance(message, MetaMessage):
                    values.append(message)
        chain = make_model(values)
        all_chains.extend(chain)

    state_map = markov_dictify(all_chains)

    segments = [START]

    while segments[
            -1] != END:  #taking the last part found and pulling the prob out of state map
        start_part = tuple(segments[-1:])

        next_probabilities = state_map[start_part]
        weights = next_probabilities.values()
        winner = weighted_choice_sub(weights)
        next_part = list(next_probabilities.keys())[winner]
        segments.append(next_part)
    mid = MidiFile()
    track = MidiTrack()
    curr = []
    last_delay = 0
    mid.tracks.append(track)
    ticks = 0
    in_use = []
    is_in_use = {}
    for i in range(len(segments)):
        if isinstance(
                segments[i], tuple
        ):  #START and END are objects and I can't index/key through them
            #getting mem error for some reason
            #I wanted to see what the song would look like without me attempting to detect changes
            segment = segments[i]

            note_list = segment[0]
            for note in note_list:
                #generate a message and turn on
                track.append(Message('turn_on', note=note, time=segment[1]))

                curr = note_list
                #if we do this all the time how can i move to the next item and call a diff on it?
                #use segments of -1? no thats not it i-1?

            ticks += segment[1]

        if ticks > MAX_SONG_LEN:
            break
    mid.save('some.mid')
Example #14
0
def record(midi_file, bpm):
    ctx = zmq.Context()
    sock = ctx.socket(zmq.SUB)
    sock.connect(INPUT_ZMQ_URL)
    sock.subscribe(b'')

    track = MidiTrack()
    track.append(
        MetaMessage('track_name',
                    name=f'MIDIate Recorder {str(datetime.now())}',
                    time=0))
    midi_file.tracks.append(track)

    print('Recording...')
    try:
        while True:
            data = sock.recv()
            current_ts, msg = data[:8], data[8:]
            current_ts, = struct.unpack("<Q", current_ts)
            msg = Message.from_bytes(msg)
            msg.time = int(
                second2tick(current_ts / NANOSECONDS_IN_SECONDS,
                            TICKS_PER_BEAT, bpm2tempo(bpm)))
            track.append(msg)
    except KeyboardInterrupt:
        print('Recorder stopped.')
def merge_midi(midis, input_dir, output, default_tempo=500000):
    '''Merge midi files into one'''
    pairs = [(int(x[:-4].split('_')[-1]), x) for x in midis]
    pairs = sorted(pairs, key=lambda x: x[0])
    midis = [join(input_dir, x[1]) for x in pairs]

    mid = MidiFile(midis[0])
    # identify the meta messages
    metas = []
    # tempo = default_tempo
    tempo = default_tempo // 2
    for msg in mid:
        if msg.type is 'set_tempo':
            tempo = msg.tempo
        if msg.is_meta:
            metas.append(msg)
    for meta in metas:
        meta.time = int(mido.second2tick(meta.time, mid.ticks_per_beat, tempo))

    target = MidiFile()
    track = MidiTrack()
    track.extend(metas)
    target.tracks.append(track)
    for midi in midis:
        mid = MidiFile(midi)
        for msg in mid:
            if msg.is_meta:
                continue
            if msg.type is not 'end_of_track':
                msg.time = int(
                    mido.second2tick(msg.time, mid.ticks_per_beat, tempo))
                track.append(msg)

    track.append(MetaMessage('end_of_track'))
    target.save(output)
def generate_midi(mkv_order=4):
    """
    Generates and saves a midi file using an Nth order markov chain trained on midi files from training_music/single_track.
    Generated midi file is saved in the generated directory.
    Args:
        mkv_order (int): The order of the markov chain that should be used to generate the file
    """
    corpus_files = (MidiFile(f'training_music/single_track/{file_name}',
                             clip=True)
                    for file_name in listdir('training_music/single_track'))

    messages = (message for f in corpus_files
                for message in ['START'] + f.tracks[0] + ['END'])

    mkv = MarkovModel(midi_data=messages, order=mkv_order)

    # Type 0 single track file
    gen_midi = MidiFile(type=0)
    track = MidiTrack()
    gen_midi.tracks.append(track)

    for message in mkv.sample():
        track.append(message)

    gen_midi.save(f'generated/generated{mkv_order}.mid')
Example #17
0
    def write_song(self, file_name):
        mid = MidiFile(type=1)  # 0 type means all messages are on one track
        track_pitch = [0, -12]
        track_num = 2

        tracks = []
        for i in range(track_num):
            track = MidiTrack()
            tracks.append(track)
            mid.tracks.append(track)
            track.append(
                MetaMessage("set_tempo", tempo=mido.bpm2tempo(self.bpm)))

        for i, note in enumerate(self.notes):
            tracks[i % track_num].append(
                Message("note_on",
                        note=note.pitch + track_pitch[i % track_num],
                        velocity=127,
                        time=0))
            tracks[i % track_num].append(
                Message("note_on",
                        note=note.pitch + track_pitch[i % track_num],
                        velocity=0,
                        time=note.duration * mid.ticks_per_beat))

        mid.save(file_name)
Example #18
0
def samples_to_midi(samples, fname, ticks_per_sample, thresh=0.5):
    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)
    ticks_per_beat = mid.ticks_per_beat
    ticks_per_measure = 4 * ticks_per_beat
    ticks_per_sample = ticks_per_measure / samples_per_measure
    abs_time = 0
    last_time = 0
    for sample in samples:
        for y in range(sample.shape[0]):
            abs_time += ticks_per_sample
            for x in range(sample.shape[1]):
                note = x + (128 - num_notes) / 2
                if sample[y, x] >= thresh and (y == 0
                                               or sample[y - 1, x] < thresh):
                    delta_time = abs_time - last_time
                    track.append(
                        Message('note_on',
                                note=note,
                                velocity=127,
                                time=delta_time))
                    last_time = abs_time
                if sample[y, x] >= thresh and (y == sample.shape[0] - 1
                                               or sample[y + 1, x] < thresh):
                    delta_time = abs_time - last_time
                    track.append(
                        Message('note_off',
                                note=note,
                                velocity=127,
                                time=delta_time))
                    last_time = abs_time
    mid.save(fname)
Example #19
0
def midi_from_indexes(indexes, max_dur_note, amount_dur, each_dur):
    time_now = 0
    events = []
    for i in range(len(indexes)):
        if (indexes[i] == '<EOS>'):
            note = -1
        elif (indexes[i] == 128 * amount_dur):
            note = -1
        else:
            note = indexes[i] % 128

            type_dur = (indexes[i] - note) / 128
            dur = max_dur_note / amount_dur * (type_dur + 1)
        if (note != -1):
            events.append([time_now, 'note_on', note])
            events.append([time_now + dur, 'note_off', note])
        time_now += each_dur
    events = sorted(events, key=itemgetter(0))
    for i in range(len(events) - 1, 0, -1):
        events[i][0] -= events[i - 1][0]
    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)
    for ev in events:
        track.append(
            Message(ev[1],
                    note=ev[2],
                    velocity=64,
                    time=int(ev[0] / 0.0013354687499999999)))
    return mid
Example #20
0
def combine_tracks(metadata, instrument_tracks):
    """
    Combines array of instruments to MidiFile object
    :param
    instrument_tracks: array of instruments
    metadata: metadata of the conditioning file so that the output is in the same style and key

    :return MidFile object:
    """
    mid = MidiFile()
    header = []
    for data in metadata:
        for msg in data:
            if msg.type == 'smpte_offset' or msg.type == 'time_signature' or msg.type == 'key_signature'\
                    or msg.type == 'set_tempo':
                header.append(data)
                break

    for data in header:
        track = MidiTrack()
        mid.tracks.append(track)
        for elements in data:
            track.append(elements)

    for data in instrument_tracks:
        track = MidiTrack()
        mid.tracks.append(track)
        for elements in data:
            track.append(elements)

    return mid
def oneDimArrayToMidi(oneDimArr, name):
	#orig = MidiFile('Midi/rh.mid')

	mid = MidiFile()
	track = MidiTrack()
	mid.tracks.append(track)

	# for tr in orig.tracks:
	# 	for msg in tr:
	# 		msg_count = msg_count + 1
	# 		if msg.type == 'note_on':
	# 			if (counter < len(oneDimArr)):
	# 				msg.note = int(oneDimArr[counter])
	# 			else:
	# 				msg.note = 0
	# 			track.append(msg)
	# 			counter = counter + 1

	for i in range(len(oneDimArr)):
		if (oneDimArr[i] > 0.0 and oneDimArr[i] < 127.0):
			msg1 = mido.Message('note_on', note=int(oneDimArr[i]), velocity=60, time=0)
			msg2 = mido.Message('note_on', note=int(oneDimArr[i]), velocity=0, time=80)
			track.append(msg1)
			track.append(msg2)

	mid.save(name)
Example #22
0
class MIDI_writer:
    def __init__(self, ticks_per_beat=480, tempo=500000, start_time=None, folder='', filename=''):

        self.ticks_per_beat = ticks_per_beat
        self.tempo = tempo
        self.folder = folder
        self.filename = filename

        self.midi_file = MidiFile()
        self.track = MidiTrack()
        self.midi_file.tracks.append(self.track)
        self.track.append(MetaMessage("set_tempo", tempo=500000))
        if start_time is None:
            self.t0 = time.time()
        else:
            self.t0 = start_time

    def add_to_midi(self, msgs):
        start_time = msgs[0][1]
        for msg, msg_time in msgs:
            msg.time = int(mido.second2tick(msg_time-start_time, self.ticks_per_beat, self.tempo))
            self.track.append(msg)
            start_time = msg_time

    def write(self):
        self.midi_file.save("{}{}".format(self.folder, self.filename))
def merge_tracksFIXED(tracks):
    """Returns a MidiTrack object with all messages from all tracks.

    The messages are returned in playback order with delta times
    as if they were all in one track.
    """
    now = 0 # REMOVE THIS
    messages = MidiTrack()
    for track in tracks:
        now = 0 # ADD THIS
        for message in track:
            now += message.time
            if message.type not in ('track_name', 'end_of_track'):
                messages.append(message.copy(time=now))
            if message.type == 'end_of_track':
                break

    messages.sort(key=lambda x: x.time)
    messages.append(MetaMessage('end_of_track', time=now))

    # Convert absolute time back to delta time.
    last_time = 0
    for message in messages:
        message.time -= last_time
        last_time += message.time

    return messages
Example #24
0
File: bar.py Project: NKlug/musiGAN
def to_temporal_midi_track(notes):
    track = MidiTrack()
    notes = np.asarray(notes, dtype=np.int)
    for note in notes:
        track.append(Message('note_on', note=note[0], time=0))
        track.append(Message('note_off', note=note[0], time=note[1]))
    return track
Example #25
0
def transpose(track, factor):
    new_track = MidiTrack()
    for msg in track:
        if msg.type == "note_on" or msg.type == "note_off":
            msg = msg.copy(note=msg.note + factor)
        new_track.append(msg)
    return new_track
Example #26
0
def write_note(track: MidiTrack, note: Note, rest_val: Union[Rest, None] = None, channel: int = 0) -> None:
    """
    Writes a note to the provided midi track

    :param track: track to write to
    :param note: note to add to track
    :param rest_val: how long of a rest to how in ticks per quarter note
    :param channel: which channel it takes on MIDI file (possible values 0..15)
    """
    if isinstance(note.value, str):
        note_val = const.NOTE_MIDI_MAP[note.value]
    else:
        note_val = note.value
    time_l = rest_val or 0
    track.append(
        Message(
            "note_on",
            note=note_val,
            velocity=note.velocity,
            time=time_l,
            channel=channel,
        )
    )
    track.append(
        Message(
            "note_off",
            note=note_val,
            velocity=note.velocity,
            time=note.duration,
            channel=channel,
        )
    )
def matrix_to_mid(matrix, outfile_name):

	mid = MidiFile()
	
	track = MidiTrack()
	mid.tracks.append(track)
	mid.ticks_per_beat = 24

	cumulative_step = 0

	for m in range(16):
		for s in range(96):

			current_step = s + (96 * m)
			notes_at_step = matrix[m, :, s]
			notes = [(i, v) for (i, v) in enumerate(notes_at_step) if v != 0]

			for note, velocity in notes:
				# note that delta_time won't change after the first note is added 
				# which is what we're looking for. All notes are sounded at the same 
				# time, so we want all but the first note of a step to 
				delta_time = current_step - cumulative_step
				# make a new attack at specified notes
				track.append(Message('note_on', channel = 0, note = 116 - note, velocity = int(velocity), time = delta_time))

				cumulative_step += delta_time

			for note, velocity in notes:
				#release all of the notes
				track.append(Message('note_on', channel = 0, note = 116 - note, velocity = 0, time = 0))


	# meta_track.append(MetaMessage('end_of_track'))

	mid.save(outfile_name)
Example #28
0
def change_midi_file_tempo(input_file, output_file, ratio=1.0):
    """
    Change the tempo in a midi file
    """
    infile = MidiFile(input_file)

    with MidiFile() as outfile:

        outfile.type = infile.type
        outfile.ticks_per_beat = infile.ticks_per_beat

        for msg_idx, track in enumerate(infile.tracks):

            out_track = MidiTrack()
            outfile.tracks.append(out_track)

            for message in track:
                if message.type == 'set_tempo':
                    bpm = tempo2bpm(message.tempo)
                    new_bpm = ratio * bpm
                    message.tempo = bpm2tempo(new_bpm)

                out_track.append(message)

    outfile.save(output_file)
Example #29
0
def reconstructFromBeats(filename, sequence, ticks_per_beat, subdivisions = 2):
	mid = MidiFile()
	track = MidiTrack()
	mid.tracks.append(track)
	mid.ticks_per_beat = ticks_per_beat
	divisions = int(ticks_per_beat / subdivisions)

	numticks = 0
	curTone = 0
	curVel = 0

	for beat in sequence:
		tone, velocity = binToNote(beat)
		# print(tone, velocity)
		if tone != curTone:
			if curTone != 0:
				track.append(Message('note_off', note = curTone, velocity = 0, time = numticks))
				numticks = 0
			track.append(Message('note_on', note = tone, velocity = velocity, time = numticks))
			numticks = 0
			curTone = tone
		numticks += divisions

	mid.save('output/' + filename)
	return mid
Example #30
0
def samples_to_midi(samples, fname, thresh=0.5):
    samples = samples.numpy()
    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)
    ticks_per_sample = (mid.ticks_per_beat * 4) / N_MEASURES
    abs_time = 0
    last_time = 0
    last_tick = samples[0].shape[0] - 1

    for j, sample in enumerate(samples):
        s = np.argwhere(sample>thresh)
        for i in range(len(s)):
            y, x = s[i]
            abs_time = y * ticks_per_sample + (j*N_NOTES*ticks_per_sample)
            note = int(x + (128 - N_NOTES)/2)
            if y == 0 or sample[y-1,x] < thresh:
                delta_time = int(abs_time - last_time)
                track.append(Message('note_on', note=note, velocity=127, time=delta_time))
                last_time = abs_time
            if y == last_tick or sample[y+1, x] < thresh:
                delta_time = int(abs_time - last_time)
                track.append(Message('note_off', note=note, velocity=127, time=delta_time))
                last_time = abs_time

    mid.save(fname)
    print("Midi saved to:", fname)
Example #31
0
def writeSong(predictionList):
    from mido import Message, MidiFile, MidiTrack

    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)

    onNotes = set()
    last_i = 0
    for i, prediction in enumerate(predictionList):
        for note in prediction:
            if (prediction[note] > 0.9):
                if (note not in onNotes):
                    track.append(
                        Message('note_on',
                                channel=9,
                                note=note,
                                velocity=int(prediction[note] * 127),
                                time=last_i))
                    onNotes.add(note)
                    last_i = 0
            else:
                if (note in onNotes):
                    track.append(
                        Message('note_on',
                                channel=9,
                                note=note,
                                velocity=0,
                                time=last_i))
                    onNotes.remove(note)
                    last_i = 0
            last_i += 1

    return mid
Example #32
0
def gen_sample_file(n, name):
    print('\n\tGenerating sample file')
    ry = np.array([[utils.track_seed()]])
    rh = np.zeros([1, INTERNALSIZE * NLAYERS])
    mid = MidiFile()
    trk = MidiTrack()
    mid.tracks.append(trk)
    flubbs = 0
    cur_notes = 0
    non_zero = 0
    for _ in range(n):
        # print(mido_utils.vec2msg(ry[0][0]))
        # generate a new state and output vec
        ryo, rh = sess.run([Yo, H], feed_dict={Xo: ry, Hin: rh, batchsize: 1, pkeep: 1})
        if True in np.isnan(ryo[0]):
            continue
        # sample the output vec into an argmaxed version
        rc = utils.prep_vec(ryo)
        if rc[0] > 0:
            non_zero += 1
        if rc[0]==0:
            cur_notes += 1
            if cur_notes > 20:
                rc = utils.random_note(dt=256)
                cur_notes = 0
                flubbs+=1
        # append this to our midi file as a mido.Message
        trk.append(mido_utils.vec2msg(rc))
        ry = np.array([[rc]])
    mid.save('samples/{}_{}.mid'.format(run_timestamp, name))
    print('flubbs/n {:04.4f}%, nonzero: {:04.4f}%'.format(100*flubbs/n, 100*non_zero/n))
def output_messages(filename, *messages):
	# Takes the name of a MIDI file to create and fill with the list of messages.
	# Returns nothing.
	with MidiFile() as outfile:
		for message_track in messages:
			track = MidiTrack()
			outfile.tracks.append(track)
			for message in message_track:
				track.append(message)
	outfile.save(filename)
Example #34
0
def generate_random(snote=50, mlength=12, numofmidi=10, time=150, filename='random', pitchrnd=False):
    
    notes = range(snote, snote+mlength)
    
    noterange = range(mlength)

    # pitch range for random pitch value ;
    pitches = range(-8192,8191)
    
    # Create music folder if it does not exist
    if not os.path.exists('music'):
        os.makedirs('music')

    for j in range(numofmidi):
    
        mid = MidiFile(type=0) # type0 can have only one track
    
        track = MidiTrack() # note list (kind of)

        mid.tracks.append(track)
    
        # the note which the pitch will change for
        pitchnote = random.choice(noterange)
        numofpnote = random.choice(noterange)
    
        for i in noterange:
        
            note = random.choice(notes)
            pitch = random.choice(pitches)
        
            if pitchrnd:
                if i == pitchnote: # Change the pitch on the note
                    track.append(Message('pitchwheel', pitch=pitch))
                if i == (pitchnote+numofpnote): # Change the pitch back to default
                    track.append(Message('pitchwheel'))
        
            track.append(Message('note_on', note=note, velocity = 127, time=time))
            track.append(Message('note_off', note=note, velocity = 127, time=time))
            
        note = random.choice(notes)
        track.append(Message('note_on', note=note, velocity = 127, time=time))
        track.append(Message('note_off', note=note, velocity = 127, time=500))
        

        mid.save('music/' + filename + str(j) + '.mid')
Example #35
0
def time_warp(source_path, dest_path, ratio):
    # Read a midi file and return a dictionnary {track_name : pianoroll}
    mid_in = MidiFile(source_path)
    mid_out = MidiFile()
    # The two files need to have the same ticks per beat
    ticks_per_beat = mid_in.ticks_per_beat
    mid_out.ticks_per_beat = ticks_per_beat

    # Parse track by track
    for i, track_in in enumerate(mid_in.tracks):
        track_out = MidiTrack()
        mid_out.tracks.append(track_out)
        for message_in in track_in:
            time_in = message_in.time
            time_out = int(round(time_in * ratio))
            # For absolutely every message, just mutliply the time by the ratio
            message_out = message_in.copy(time=time_out)
            track_out.append(message_out)
    mid_out.save(dest_path)
    return
Example #36
0
def apply_mutation(mutantnotelist, midino, snote=50, time=150, filename='random'):

    mid = MidiFile(type=0) # type0 can have only one track
    
    track = MidiTrack() # note list (kind of)

    mid.tracks.append(track)
    
    # Create mutant music folder if it does not exist
    if not os.path.exists('mutantmusic'):
        os.makedirs('mutantmusic')
    
    # add the octaves back
    mutantnotelist2 = [x+snote for x in mutantnotelist]
    
    for note in mutantnotelist2[:len(mutantnotelist2)-2]:
        
        #print(note)
        
        track.append(Message('note_on', note=int(note), velocity = 127, time=time))
        track.append(Message('note_off', note=int(note), velocity = 127, time=time))
        
    track.append(Message('note_on', note=mutantnotelist2[len(mutantnotelist2)-1], velocity = 127, time=time))
    track.append(Message('note_off', note=mutantnotelist2[len(mutantnotelist2)-1], velocity = 127, time=500))
        
        
    mid.save('mutantmusic/' + filename + str(midino) + '.mid')
def SaveVelocityDatatoMIDIFile(vData, fileName):

    with MidiFile(ticks_per_beat = 24) as mFile:
        track = MidiTrack()
        mFile.tracks.append(track)

        for n in MIDINotes:
            if (vData[0,n]>0):
                event = Message("note_on", velocity=int(vData[0,n]), note = int(n), time = int(0))
                track.append(event)

        timeOfLastEvent = 0

        for t in range(1,vData.shape[0]-1):
            for n in MIDINotes:
                if vData[t,n] != vData[t-1,n]:
                    relativeTick = t - timeOfLastEvent
                    timeOfLastEvent = t
                    event = Message("note_on", velocity=int(vData[t,n]), note = int(n), time = int(relativeTick))
                    track.append(event)

        mFile.save(fileName)
        print("MIDI file was saved.  Events: {} Length in ticks: {} Data dimensions: {}".format(len(track), timeOfLastEvent, vData.shape))
def toMIDI(filename, ch, notes, rms, onset_start_times, onset_end_times, nOnsets):

    print 'Transcribing to MIDI in ' + filename

    delta = 0
    with MidiFile() as outfile:
        track = MidiTrack()
        outfile.tracks.append(track)

        for i in range(nOnsets):
            stime = int((onset_start_times[i] - delta) * 1000)
            message = Message('note_on', note=int(notes[i]), velocity=int(rms[i] * 127), time=stime)
            message.channel = ch
            track.append(message)
            etime = int((onset_end_times[i] - delta) * 1000)
            off_message = Message('note_off', note=int(notes[i]), velocity=int(rms[i] * 127), time=etime)
            off_message.channel = ch
            track.append(off_message)
            delta = onset_end_times[i]

        outfile.print_tracks()
        outfile.save('/media/sf_VMshare/' + filename)

    print 'Transcription successfull!'
Example #39
0
	def toMidi(self, fname):
		with MidiFile() as outfile:
			track = MidiTrack()
			outfile.tracks.append(track)
			track.append(Message('program_change', program=12))
			for note in self.getNotes():
				for pitch in note.pitches:
					track.append(Message('note_on', note=pitch, velocity=100, time=0))
				delta = note.duration
				for pitch in note.pitches:
					track.append(Message('note_off', note=pitch, velocity=100, time=delta))
					delta = 0
			outfile.save(fname)
def createMidiFromPianoRoll(piano_roll, lowest_note, directory, mel_test_file, threshold, res_factor=1):
    
    ticks_per_beat = int(96/res_factor)
    mid = MidiFile(type=0, ticks_per_beat=ticks_per_beat)
    track = MidiTrack()
    mid.tracks.append(track)

    mid_files = []
    

    delta_times = [0]
    for k in range(piano_roll.shape[1]):#initial starting values
        if piano_roll[0, k] == 1:
            track.append(Message('note_on', note=k+lowest_note, velocity=100, time=0))
            delta_times.append(0)
        
    for j in range(piano_roll.shape[0]-1):#all values between first and last one
        set_note = 0 #Check, if for the current timestep a note has already been changed (set to note_on or note_off)
        
        for k in range(piano_roll.shape[1]):
            if (piano_roll[j+1, k] == 1 and piano_roll[j, k] == 0) or (piano_roll[j+1, k] == 0 and piano_roll[j, k] == 1):#only do something if note_on or note_off are to be set
                if set_note == 0:
                    time = j+1 - sum(delta_times)          
                    delta_times.append(time)
                else:
                    time = 0
                    
                if piano_roll[j+1, k] == 1 and piano_roll[j, k] == 0:
                    set_note += 1
                    track.append(Message('note_on', note=k+lowest_note, velocity=100, time=time))
                if piano_roll[j+1, k] == 0 and piano_roll[j, k] == 1:
                    set_note += 1
                    track.append(Message('note_off', note=k+lowest_note, velocity=64, time=time))
                           
    mid.save('%s%s_th%s.mid' %(directory, mel_test_file, threshold))
    mid_files.append('%s.mid' %(mel_test_file))
       
    return
Example #41
0
"""
Create a new MIDI file with some random notes.

The file is saved to test.mid.
"""
from __future__ import division
import random
import sys
from mido import Message, MidiFile, MidiTrack, MAX_PITCHWHEEL

notes = [64, 64+7, 64+12]

outfile = MidiFile()

track = MidiTrack()
outfile.tracks.append(track)

track.append(Message('program_change', program=12))

delta = 300
ticks_per_expr = int(sys.argv[1]) if len(sys.argv) > 1 else 20
for i in range(4):
    note = random.choice(notes)
    track.append(Message('note_on', note=note, velocity=100, time=delta))
    for j in range(delta // ticks_per_expr):
        pitch = MAX_PITCHWHEEL * j * ticks_per_expr // delta
        track.append(Message('pitchwheel', pitch=pitch, time=ticks_per_expr))
    track.append(Message('note_off', note=note, velocity=100, time=0))

outfile.save('test.mid')
Example #42
0
#!/usr/bin/env python

import mido
from mido import Message, MidiFile, MidiTrack

import time

tracks = []

with MidiFile() as outfile:
    track = MidiTrack()

    outfile.tracks.append(track)

    # track.append(Message('program_change', program=12, time=0))
    track.append(Message("note_on", note=64, velocity=64, time=0))
    track.append(Message("note_off", note=64, velocity=127, time=1000))

    outfile.save("new_song.mid")
Example #43
0
import ROOT
tb = ROOT.TBrowser()
f = ROOT.TFile("/afs/cern.ch/user/y/yijiang/SA_test_ttH_ttHemjets10.root")
t = f.Get("METree")
for event in t:
 n1= event.ME_Sig_Max_Likelihoods

import mido
from mido import Message, MidiFile, MidiTrack

with MidiFile() as mid:
 track = MidiTrack()
 mid.tracks.append(track)
 track.append(mido.Message('program_change', program=12, time=0))
 for val in n1 :
  track.append(mido.Message('note_on', note=int(val), velocity=64, time=100))
  track.append(mido.Message('note_off', note=int(val), velocity=127, time=100))
 mid.save('/afs/cern.ch/user/y/yijiang/new_song.mid')
Example #44
0
from mido import Message, MetaMessage, MidiFile, MidiTrack

# MIDI test objects

# Track that is already quantized.
track0 = MidiTrack()
track0.append(MetaMessage('track_name', name='test0', time=0))
track0.append(Message('note_on', note=60, velocity=64, time=0))
track0.append(Message('note_off', note=60, velocity=64, time=50))
track0.append(MetaMessage('end_of_track', time=0))

# Simple track that is not quantized.
track1 = MidiTrack()
track1.append(MetaMessage('track_name', name='test1', time=0))
track1.append(Message('note_on', note=60, velocity=64, time=2))
track1.append(Message('note_off', note=60, velocity=64, time=50))
track1.append(MetaMessage('end_of_track', time=0))

# Track with notes that, when quantized to 32nd notes, would run over
# the original end time of the track.
track2 = MidiTrack()
track2.append(MetaMessage('track_name', name='test2', time=0))
track2.append(Message('note_on', note=60, velocity=64, time=29))
track2.append(Message('note_off', note=60, velocity=64, time=31))
track2.append(MetaMessage('end_of_track', time=0))

meta_track = MidiTrack()
meta_track.append(MetaMessage('track_name', name='meta-track', time=0))
midi_notes_in_track0 = MidiFile()
midi_notes_in_track0.tracks.append(track0)
Example #45
0
def quantize_track(track, ticks_per_quarter, quantization):
    '''Return the differential time stamps of the note_on, note_off, and
    end_of_track events, in order of appearance, with the note_on events
    quantized to the grid given by the quantization.

    Arguments:
    track -- MIDI track containing note event and other messages
    ticks_per_quarter -- The number of ticks per quarter note
    quantization -- The note duration, represented as
      1/2**quantization.'''

    pp = pprint.PrettyPrinter()

    # Message timestamps are represented as differences between
    # consecutive events. Annotate messages with cumulative timestamps.

    # Assume the following structure:
    # [header meta messages] [note messages] [end_of_track message]
    first_note_msg_idx = None
    for i, msg in enumerate(track):
        if msg.type == 'note_on':
            first_note_msg_idx = i
            break

    cum_msgs = zip(
        np.cumsum([msg.time for msg in track[first_note_msg_idx:]]),
        [msg for msg in track[first_note_msg_idx:]])
    end_of_track_cum_time = cum_msgs[-1][0]

    quantized_track = MidiTrack()
    quantized_track.extend(track[:first_note_msg_idx])
    # Keep track of note_on events that have not had an off event yet.
    # note number -> message
    open_msgs = defaultdict(list)
    quantized_msgs = []
    for cum_time, msg in cum_msgs:
        if DEBUG:
            print msg
            pp.pprint(open_msgs)
        if msg.type == 'note_on' and msg.velocity > 0:
            # Store until note off event. Note that there can be
            # several note events for the same note. Subsequent
            # note_off events will be associated with these note_on
            # events in FIFO fashion.
            open_msgs[msg.note].append((cum_time, msg))
        elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0):
            assert msg.note in open_msgs, \
                'Bad MIDI. Cannot have note off event before note on event'
            note_on_open_msgs = open_msgs[msg.note]
            note_on_cum_time, note_on_msg = note_on_open_msgs[0]
            open_msgs[msg.note] = note_on_open_msgs[1:]
            # Quantized note_on time
            quantized_note_on_cum_time = quantize_tick(
                note_on_cum_time, ticks_per_quarter, quantization)
            # The cumulative time of note_off is the quantized
            # cumulative time of note_on plus the orginal difference
            # of the unquantized cumulative times.
            quantized_note_off_cum_time = quantized_note_on_cum_time + (cum_time - note_on_cum_time)
            quantized_msgs.append((min(end_of_track_cum_time, quantized_note_on_cum_time), note_on_msg))
            quantized_msgs.append((min(end_of_track_cum_time, quantized_note_off_cum_time), msg))
        elif msg.type == 'end_of_track':
            quantized_msgs.append((cum_time, msg))

    # Now, sort the quantized messages by (cumulative time,
    # note_type), making sure that note_on events come before note_off
    # events when two event have the same cumulative time. Compute
    # differential times and construct the quantized track messages.
    quantized_msgs.sort(
        key=lambda (cum_time, msg): cum_time
        if (msg.type=='note_on' and msg.velocity > 0) else cum_time + 0.5)

    diff_times = [0] + list(
        np.diff([ msg[0] for msg in quantized_msgs ]))
    for diff_time, (cum_time, msg) in zip(diff_times, quantized_msgs):
        quantized_track.append(msg.copy(time=diff_time))
    if DEBUG:
        pp.pprint(quantized_msgs)
        pp.pprint(diff_times)
    return quantized_track
Example #46
0
tolerance = 0.8

notes_o = notes("default", win_s, hop_s, samplerate)

print("%8s" % "time","[ start","vel","last ]")

# create a midi file
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)

ticks_per_beat = mid.ticks_per_beat # default: 480
bpm = 120 # default midi tempo

tempo = bpm2tempo(bpm)
track.append(MetaMessage('set_tempo', tempo=tempo))
track.append(MetaMessage('time_signature', numerator=4, denominator=4))

def frames2tick(frames, samplerate=samplerate):
    sec = frames / float(samplerate)
    return int(second2tick(sec, ticks_per_beat, tempo))

last_time = 0

# total number of frames read
total_frames = 0
while True:
    samples, read = s()
    new_note = notes_o(samples)
    if (new_note[0] != 0):
        note_str = ' '.join(["%.2f" % i for i in new_note])
Example #47
0
from mido import MidiFile, MidiTrack, Message
import random

mid = MidiFile(type=0)

track = MidiTrack()

mid.tracks.append(track)

notes = range(40, 90)

for i in range(20):
    note = random.choice(notes)
    track.append(Message('note_on', note=note, velocity=100, time=i*100))
    track.append(Message('note_off', note=note, velocity=100, time=(i+1)*100))

mid.save('random.mid')

Example #48
0
for pred in prediction:
    for i in range(0,4):
        pred[i] = pred[i] * (max_val[i]-min_val[i]) + min_val[i]
        if pred[i] < min_val[i]:
            pred[i] = min_val[i]

        if pred[i] >= max_val[i]:
            pred[i] = max_val[i]
	
###########################################


###### SAVING TRACK FROM BYTES DATA #######
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)

for note in prediction:
    # 147 means note_on
    note = np.insert(note, 1, 144)
    bytes = np.round(note).astype(int)
    msg = Message.from_bytes(bytes[1:4])
    msg.time = int(note[4]/0.00125) # to rescale to midi's delta ticks. arbitrary value for now.
    msg.channel = bytes[0]
    print(msg)
    track.append(msg)

mid.save('new_song.mid')

Example #49
0
def array_to_MIDI(array,sig_length):

	# get relative times between events
	test_times = (np.diff(np.sort(np.concatenate((array[:,1],array[:,2])))* 512./44100)).astype(float)

	test_duration = (np.diff(np.sort(np.concatenate((array[:,1],array[:,2])))* 512./44100*960)).astype(int)
	#print array
	#print test_duration
	#print test_times
	#* 512./44100*960)
	# write MIDI file
	with MidiFile() as outfile:
		# Initialize
		track = MidiTrack()
		outfile.tracks.append(track)

		# add MIDI events
		track.append(Message('program_change', program=12))
		
		seg_skip_on = 1
		
		# take segments and make midi note events
		for segment in xrange(0,array.shape[0]):
			if segment == 0:
				track.append(Message('note_on', note=array[0,0], velocity=array[0,3], time=int(array[0,1]*512./44100*960)))
				track.append(Message('note_off', note=array[0,0], velocity=array[0,3], time=test_duration[0]))
			else:
				track.append(Message('note_on', note=array[segment,0], velocity=array[segment,3], time=test_duration[seg_skip_on]))
				seg_skip_off = seg_skip_on + 1
				track.append(Message('note_off', note=array[segment,0], velocity=array[segment,3], time=test_duration[seg_skip_off]))
				#print test_duration[seg_skip_off]
				seg_skip_on = seg_skip_off + 1
		track_end = int((sig_length/44100. - 512./44100 * array[-1,2])*960)
		track.append(Message('program_change', program=12, time=track_end))
		track.append(MetaMessage('end_of_track'))
				
		#outfile.save('output.mid') # output MIDI file
		
	return outfile
Example #50
0
#!/usr/bin/env python
"""
Create a new MIDI file with some random notes.

The file is saved to test.mid.
"""

import random
from mido import Message, MidiFile, MidiTrack

notes = [64, 64+7, 64+12]

with MidiFile() as outfile:
    track = MidiTrack()
    outfile.tracks.append(track)

    track.append(Message('program_change', program=12))

    delta = 16
    for i in range(4):
        note = random.choice(notes)
        track.append(Message('note_on', note=note, velocity=100, time=delta))
        track.append(Message('note_off', note=note, velocity=100, time=delta))

    outfile.save('test.mid')
Example #51
0
def array_to_midi(array,
                  name,
                  quantization=5,
                  pitch_offset=0,
                  midi_type=1,
                  ticks_per_quarter=240):
    '''Convert an array into a MIDI object.

    When an MIDI object is converted to an array, information is
    lost. That information needs to be provided to create a new MIDI
    object from the array. For this application, we don't care about
    this metadata, so we'll use some default values.

    Arguments:
    array -- An array A[time_step, note_number] = 1 if note on, 0 otherwise.
    quantization -- The note duration, represented as 1/2**quantization.
    pitch_offset -- Offset the pitch number relative to the array index.
    midi_type -- Type of MIDI format.
    ticks_per_quarter -- The number of MIDI timesteps per quarter note.'''
    
    mid = MidiFile()
    meta_track = MidiTrack()
    note_track = MidiTrack()
    mid.tracks.append(meta_track)
    mid.tracks.append(note_track)

    meta_track.append(MetaMessage('track_name', name=name, time=0))
    meta_track.append(MetaMessage('time_signature',
                                  numerator=4,
                                  denominator=4,
                                  clocks_per_click=24,
                                  notated_32nd_notes_per_beat=8,
                                  time=0))
    meta_track.append(MetaMessage('set_tempo', tempo=500000, time=0))
    meta_track.append(MetaMessage('end_of_track', time=0))

    ticks_per_quantum = ticks_per_quarter * 4 / 2**quantization

    note_track.append(MetaMessage('track_name', name=name, time=0))
    cumulative_events = []
    for t, time_slice in enumerate(array):
        for i, pitch_on in enumerate(time_slice):
            if pitch_on > 0:
                cumulative_events.append(dict(
                    type = 'note_on',
                    pitch = i + pitch_offset,
                    time = ticks_per_quantum * t
                ))
                cumulative_events.append(dict(
                    type = 'note_off',
                    pitch = i + pitch_offset,
                    time = ticks_per_quantum * (t+1)
                ))

    cumulative_events.sort(
        key=lambda msg: msg['time'] if msg['type']=='note_on' else msg['time'] + 0.5)
    last_time = 0
    for msg in cumulative_events:
        note_track.append(Message(type=msg['type'],
                                  channel=9,
                                  note=msg['pitch'],
                                  velocity=100,
                                  time=msg['time']-last_time))
        last_time = msg['time']
    note_track.append(MetaMessage('end_of_track', time=0))
    return mid