コード例 #1
0
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)
コード例 #2
0
def to_mido_track(
    track: Track,
    channel: Optional[int] = None,
    use_note_off_message: bool = False,
) -> MidiTrack:
    """Return a Track object as a mido MidiTrack object.

    Parameters
    ----------
    track : :class:`muspy.Track` object
        Track object to convert.
    use_note_off_message : bool, optional
        Whether to use note-off messages. If False, note-on messages
        with zero velocity are used instead. The advantage to using
        note-on messages at zero velocity is that it can avoid sending
        additional status bytes when Running Status is employed.
        Defaults to False.
    channel : int, optional
        Channel number. Defaults to 10 for drums and 0 for other
        instruments.

    Returns
    -------
    :class:`mido.MidiTrack` object
        Converted mido MidiTrack object.

    """
    if channel is None:
        channel = 9 if track.is_drum else 0

    # Create a new MIDI track
    midi_track = MidiTrack()

    # Track name messages
    if track.name is not None:
        midi_track.append(MetaMessage("track_name", name=track.name))

    # Program change messages
    midi_track.append(
        Message("program_change", program=track.program, channel=channel))

    # Note on and note off messages
    for note in track.notes:
        midi_track.extend(
            to_mido_note_on_note_off(
                note,
                channel=channel,
                use_note_off_message=use_note_off_message,
            ))

    # End of track message
    midi_track.append(MetaMessage("end_of_track"))

    # Convert to delta time
    to_delta_time(midi_track)

    return midi_track
コード例 #3
0
ファイル: spear2midi.py プロジェクト: areormberg/spear2midi
def main():
    #open spear file
    with open('Untitled.txt') as f:
        spear = f.readlines()
    
    root_frequency = 440
    pb_range = 2

    #init midi file
    mid = MidiFile()
    tracks = MidiTrack()
    
    #init out port
    midiout = rtmidi.MidiOut()
    available_ports = midiout.get_ports()
    if available_ports:
        midiout.open_port(0)
    else:
        midiout.open_virtual_port("Virtual port")
    
    #read data from spear file
    
    partials = []
    
    for a,b in pairwise(spear[4:]):
        a_split = a.split(' ')
        b_split = b.split(' ')
        partials.append(
            Partial(a_split[0].replace(',','.'), 
                float(a_split[1].replace(',','.')), 
                float(a_split[2].replace(',','.')), 
                float(a_split[3].replace(',','.')), 
                b_split[0::3], 
                b_split[1::3], 
                b_split[2::3], 
                root_frequency, 
                pb_range,
                midiout
            )
        )
    
    tracks.extend(partials[-1].note_list)

    mid.tracks.append(tracks)

    mid.save('output.mid')
コード例 #4
0
ファイル: midi.py プロジェクト: oguzkirman/muspy
def to_mido_track(track: Track,
                  use_note_on_as_note_off: bool = True) -> MidiTrack:
    """Return a Track object as a mido MidiTrack object.

    Parameters
    ----------
    track : :class:`muspy.Track` object
        Track object to convert.
    use_note_on_as_note_off : bool
        Whether to use a note on message with zero velocity instead of a
        note off message.

    Returns
    -------
    :class:`mido.MidiTrack` object
        Converted mido MidiTrack object.

    """
    # Create a new MIDI track
    midi_track = MidiTrack()

    # Track name messages
    if track.name is not None:
        midi_track.append(MetaMessage("track_name", name=track.name))

    # Program change messages
    channel = 9 if track.is_drum else 0
    midi_track.append(
        Message(
            "program_change",
            program=track.program,
            channel=channel,
        ))

    # Note on and note off messages
    for note in track.notes:
        midi_track.extend(
            to_mido_note_on_note_off(note, channel, use_note_on_as_note_off))

    # End of track message
    midi_track.append(MetaMessage("end_of_track"))

    # Convert to delta time
    to_delta_time(midi_track)

    return midi_track
コード例 #5
0
def split_midi(mid_file,
               target_dir,
               default_tempo=500000,
               target_segment_len=1):
    '''Split midi file into many chunks'''
    song_name = split(mid_file)[-1][:-4]
    mid = MidiFile(mid_file)

    # identify the meta messages
    metas = []
    tempo = default_tempo
    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)
    prefix = 0
    time_elapsed = 0
    for msg in mid:
        # Skip non-note related messages
        if msg.is_meta:
            continue
        time_elapsed += msg.time
        if msg.type is not 'end_of_track':
            msg.time = int(
                mido.second2tick(msg.time, mid.ticks_per_beat, tempo))
            track.append(msg)
        if msg.type is 'end_of_track' or time_elapsed >= target_segment_len:
            track.append(MetaMessage('end_of_track'))
            target.save(join(target_dir, song_name + '_{}.mid'.format(prefix)))
            target = MidiFile()
            track = MidiTrack()
            track.extend(metas)
            target.tracks.append(track)
            time_elapsed = 0
            prefix += 1
コード例 #6
0
    def merge_midi(self, input_dir, output, tempo_override=None):
        '''Merge midi files into one'''
        midis = []
        for midi in listdir(input_dir):
            midis.append(join(input_dir, midi))

        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])
        metas = []
        tempo = self.__default_tempo
        if tempo_override:
            tempo = tempo_override
        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.ticks_per_beat = mid.ticks_per_beat
        target.save(output)
        for msg in target:
            print(msg)
コード例 #7
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 = list(
        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('Message:', msg)
            print('Open messages:')
            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'

            if msg.note not in open_msgs:
                print(
                    'Bad MIDI. Cannot have note off event before note on event'
                )
                return

            note_on_open_msgs = open_msgs[msg.note]

            if len(note_on_open_msgs) == 0:
                print('Bad MIDI, Note has no end time.')
                return

            # assert len(note_on_open_msgs) > 0, 'Bad MIDI, Note has no end time.'

            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))

            if DEBUG:
                print('Appended', quantized_msgs[-2:])
        elif msg.type == 'end_of_track':
            quantized_msgs.append((cum_time, msg))

        if DEBUG:
            print('\n')

    # 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_msg2: cum_time_msg2[0] if
                        (cum_time_msg2[1].type == 'note_on' and cum_time_msg2[
                            1].velocity > 0) else cum_time_msg2[0] + 0.5)

    diff_times = [quantized_msgs[0][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:
        print('Quantized messages:')
        pp.pprint(quantized_msgs)
        pp.pprint(diff_times)
    return quantized_track
コード例 #8
0
ファイル: midi_util.py プロジェクト: kastnerkyle/neural-beats
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
コード例 #9
0
#!/usr/bin/env python
"""
Create a new MIDI file with some random notes.

The file is saved to example.mid.
"""
import random
from mido import Message, MidiFile, MidiTrack, MetaMessage

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

outfile = MidiFile()

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

track.extend([
    MetaMessage('track_name', name='Melody'),
    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('example.mid')
コード例 #10
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.'''

    # 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 = list(
        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])

    quantized_msgs = []
    index = 0

    # Iterate through all the MIDI messages searching for 'note on' events.
    for cum_time, msg in cum_msgs:
        if msg.type == 'note_on' and msg.velocity > 0:
            # For each 'note on' event, find the next corresponding 'note off'
            # event for the same note value.
            for other_cum_time, other_msg in cum_msgs[index:]:
                if ((other_msg.type == 'note_off' or
                     (other_msg.type == 'note_on' and other_msg.velocity == 0))
                        and msg.note == other_msg.note):

                    # Quantized 'note on' time.
                    quantized_note_on_cum_time = quantize_tick(
                        cum_time, ticks_per_quarter, quantization)

                    # The cumulative time of a 'note off' event is the quantized
                    # cumulative time of the associated 'note on' plus the
                    # original difference of the unquantized cumulative times.
                    quantized_note_off_cum_time = quantized_note_on_cum_time + \
                        (other_cum_time - cum_time)
                    quantized_msgs.append(
                        (min(end_of_track_cum_time,
                             quantized_note_on_cum_time), msg))
                    quantized_msgs.append(
                        (min(end_of_track_cum_time,
                             quantized_note_off_cum_time), other_msg))

                    # print('Appended', quantized_msgs[-2:])

                    break
        elif msg.type == 'end_of_track':
            quantized_msgs.append((cum_time, msg))

        index += 1

    # 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.
    def sort_msg(args):
        cum_time, msg = args
        return cum_time if (msg.type == 'note_on'
                            and msg.velocity > 0) else (cum_time + 0.5)

    quantized_msgs.sort(key=sort_msg)

    diff_times = [quantized_msgs[0][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))

    return quantized_track
コード例 #11
0
    def split_midi(self, mid_file, destinationDir=""):
        '''Split midi file into many chunks'''
        if destinationDir is "":
            destinationDir = self.__destinationDir

        print(destinationDir)
        song_name = split(mid_file)[-1][:-4]
        print(song_name)
        mid = MidiFile(mid_file)
        self.__chunks[mid_file] = []

        # identify the meta messages
        metas = []
        tempo = self.__default_tempo
        for msg in mid:
            if msg.type == 'set_tempo':
                tempo = msg.tempo
            if msg.is_meta:
                metas.append(msg)

        target = MidiFile()
        track = MidiTrack()
        for i in range(len(metas)):
            metas[i].time = int(mido.second2tick(metas[i].time, 960, tempo))
        track.extend(metas)
        target.tracks.append(track)
        for msg in mid:
            # Skip non-note related messages
            if msg.is_meta:
                continue
            msg.time = int(mido.second2tick(msg.time, 960, tempo))

            track.append(msg)

        target.save("test.mid")

        mid = MidiFile("test.mid")
        self.__chunks["test.mid"] = []

        # identify the meta messages
        metas = []
        tempo = self.__default_tempo
        tpb = mid.ticks_per_beat
        for msg in mid:
            if msg.type == 'set_tempo':
                tempo = msg.tempo
            if msg.is_meta:
                metas.append(msg)

        for i in range(len(metas)):
            metas[i].time = 0

        target = MidiFile()
        track = MidiTrack()
        track.extend(metas)
        target.tracks.append(track)

        prefix = 0
        time_elapsed = 0
        ct = 0
        for msg in mid:
            # Skip non-note related messages
            if msg.is_meta:
                continue
            time_elapsed += msg.time

            t = msg.time
            if msg.type is not 'end_of_track':
                msg.time = int(
                    mido.second2tick(msg.time, mid.ticks_per_beat, tempo))
                track.append(msg)
                if msg.type in ['note_on', 'note_off']:
                    ct += 1

            if msg.type is 'end_of_track' or time_elapsed >= self.__target_segment_len:
                track.append(MetaMessage('end_of_track'))
                target.ticks_per_beat = mid.ticks_per_beat

                if ct > 0:
                    for i in range(int(t / self.__target_segment_len)):
                        dest = join(destinationDir,
                                    song_name + '_{}.mid'.format(prefix))
                        target.save(dest)
                        prefix += 1
                        self.__chunks[mid_file].append(dest)

                target = MidiFile()
                track = MidiTrack()
                track.extend(metas)
                target.tracks.append(track)
                time_elapsed = 0
                ct = 0

        return tempo, tpb