Ejemplo n.º 1
0
    def from_stream(stream,
                    time_unit=4,
                    tick_offset=0,
                    name=None,
                    only_notes=True,
                    truncate=None,
                    gold=None,
                    sequence_index=None):
        """
        Creates a L{SegmentedMidiInput} from a midi event stream.
        
        @type only_notes: bool
        @param only_notes: if True, only includes note-on/note-off events in 
            the segments. If False, the stream will be sliced so that each 
            segment repeats things like program change events at the beginning.
            Including only notes, however, makes the preprocessing very much 
            faster
        
        """
        # Divide the stream up into slices of the right size
        # Number of ticks in each slice
        tick_unit = int(stream.resolution * time_unit)
        if len(stream.trackpool) == 0:
            end_time = 0
        else:
            end_time = max(stream.trackpool).tick

        if only_notes:
            from midi import EventStream, NoteOnEvent, NoteOffEvent, EndOfTrackEvent
            # Only include notes in the stream
            # This is much simpler and faster than the alternative
            events = [ev for ev in list(sorted(stream.trackpool)) if \
                        type(ev) in [NoteOnEvent, NoteOffEvent]]
            events = iter(events)
            try:
                current_event = events.next()
                # Get up to the start point in the stream
                while current_event.tick < tick_offset:
                    current_event = events.next()
            except StopIteration:
                # Got to the end of the stream before we even started
                inputs = []
            else:
                inputs = []
                for chunk_start in range(tick_offset, end_time, tick_unit):
                    chunk_end = chunk_start + tick_unit
                    slc = EventStream()
                    slc.add_track()
                    slc.format = stream.format
                    slc.resolution = stream.resolution
                    slc.segment_start = chunk_start

                    # Add all the note events in this time period
                    try:
                        while current_event.tick < chunk_end:
                            slc.add_event(current_event)
                            current_event = events.next()
                        # Add the end of track event
                        eot = EndOfTrackEvent()
                        eot.tick = chunk_end
                        slc.add_event(eot)
                    except StopIteration:
                        # Reached the end of the stream
                        inputs.append(slc)
                        break

                    inputs.append(slc)
        else:
            # Use slices to do all the necessary repetition of ongoing events
            from midi.slice import EventStreamSlice
            start_times = range(tick_offset, end_time, tick_unit)
            # First slice starts at the offset value
            slices = [
                EventStreamSlice(stream, chunk_start, chunk_start + tick_unit)
                for chunk_start in start_times
            ]
            inputs = [slc.to_event_stream(repeat_playing=False, cancel_playing=False) \
                                for slc in slices]
            # Associate the start time with each segment
            for slc, start_time in zip(inputs, start_times):
                slc.segment_start = start_time

        # Remove empty segments from the start and end
        current = 0
        # There's always one event - the end of track
        while len(inputs[current].trackpool) < 2:
            current += 1
        inputs = inputs[current:]
        # And the end
        current = len(inputs) - 1
        while len(inputs[current].trackpool) < 2:
            current -= 1
        inputs = inputs[:current + 1]

        if truncate is not None:
            inputs = inputs[:truncate]

        return SegmentedMidiInput(inputs,
                                  time_unit=time_unit,
                                  tick_offset=tick_offset,
                                  name=name,
                                  stream=stream,
                                  gold=gold,
                                  sequence_index=sequence_index)
Ejemplo n.º 2
0
def simplify(stream,
             remove_drums=False,
             remove_pc=False,
             remove_all_text=False,
             one_track=False,
             remove_tempo=False,
             remove_control=False,
             one_channel=False,
             remove_misc_control=False,
             real_note_offs=False,
             remove_duplicates=False):
    """
    Filters a midi L{midi.EventStream} to simplify it. This is useful 
    as a preprocessing step before taking midi input to an algorithm, 
    for example, to make it clearer what the algorithm is using.
    
    Use kwargs to determine what filters will be applied. Without any 
    kwargs, the stream will just be left as it was.
    
    Returns a filtered copy of the stream.
    
    @type remove_drums: bool
    @param remove_drums: filter out all channel 10 events
    @type remove_pc: bool
    @param remove_pc: filter out all program change events
    @type remove_all_text: bool
    @param remove_all_text: filter out any text events. This includes 
        copyright, text, track name, lyrics.
    @type one_track: bool
    @param one_track: reduce everything to just one track
    @type remove_tempo: bool
    @param remove_tempo: filter out all tempo events
    @type remove_control: bool
    @param remove_control: filter out all control change events
    @type one_channel: bool
    @param one_channel: use only one channel: set the channel of 
        every event to 0
    @type remove_misc_control: bool
    @param remove_misc_control: filters a miscellany of device 
        control events: aftertouch, channel aftertouch, pitch wheel, 
        sysex, port
    @type real_note_offs: bool
    @param real_note_offs: replace 0-velocity note-ons with actual 
        note-offs. Some midi files use one, some the other
    
    """
    from midi import EventStream, TextEvent, ProgramChangeEvent, \
        CopyrightEvent, TrackNameEvent, \
        SetTempoEvent, ControlChangeEvent, AfterTouchEvent, \
        ChannelAfterTouchEvent, PitchWheelEvent, SysExEvent, \
        LyricsEvent, PortEvent, CuePointEvent, MarkerEvent, EndOfTrackEvent
    import copy

    # Empty stream to which we'll add the events we don't filter
    new_stream = EventStream()
    new_stream.resolution = stream.resolution
    new_stream.format = stream.format

    # Work out when the first note starts in the input stream
    input_start = first_note_tick(stream)

    # Filter track by track
    for track in stream:
        track_events = []
        for ev in sorted(track):
            # Don't add EOTs - they get added automatically
            if type(ev) == EndOfTrackEvent:
                continue
            ev = copy.deepcopy(ev)
            # Each filter may modify the event or continue to filter it altogether

            if remove_drums:
                # Filter out any channel 10 events, which is typically
                #  reserved for drums
                if ev.channel == 9 and \
                        type(ev) in (NoteOnEvent, NoteOffEvent):
                    continue
            if remove_pc:
                # Filter out any program change events
                if type(ev) == ProgramChangeEvent:
                    continue
            if remove_all_text:
                # Filter out any types of text event
                if type(ev) in (TextEvent, CopyrightEvent, TrackNameEvent,
                                LyricsEvent, CuePointEvent, MarkerEvent):
                    continue
            if remove_tempo:
                # Filter out any tempo events
                if type(ev) == SetTempoEvent:
                    continue
            if remove_control:
                # Filter out any control change events
                if type(ev) == ControlChangeEvent:
                    continue
            if remove_misc_control:
                # Filter out various types of control events
                if type(ev) in (AfterTouchEvent, ChannelAfterTouchEvent,
                                ChannelAfterTouchEvent, PitchWheelEvent,
                                SysExEvent, PortEvent):
                    continue
            if real_note_offs:
                # Replace 0-velocity note-ons with note-offs
                if type(ev) == NoteOnEvent and ev.velocity == 0:
                    new_ev = NoteOffEvent()
                    new_ev.pitch = ev.pitch
                    new_ev.channel = ev.channel
                    new_ev.tick = ev.tick
                    ev = new_ev
            if one_channel:
                ev.channel = 0

            track_events.append(ev)

        # If there are events left in the track, add them all as a new track
        if len(track_events) > 1:
            if not one_track or len(new_stream.tracklist) == 0:
                new_stream.add_track()
            for ev in track_events:
                new_stream.add_event(ev)
            track_events = []

    for track in stream:
        track.sort()

    # Work out when the first note happens now
    result_start = first_note_tick(new_stream)
    # Move all events after and including this sooner so the music
    #  starts at the same point it did before
    shift = result_start - input_start
    before_start = max(input_start - 1, 0)
    if shift > 0:
        for ev in new_stream.trackpool:
            if ev.tick >= result_start:
                ev.tick -= shift
            elif ev.tick < result_start and ev.tick >= input_start:
                # This event happened in a region that no longer contains notes
                # Move it back to before what's now the first note
                ev.tick = before_start

    new_stream.trackpool.sort()

    if remove_duplicates:
        # Get rid of now duplicate events
        remove_duplicate_notes(new_stream, replay=True)

    return new_stream
    def from_stream(
        stream, time_unit=4, tick_offset=0, name=None, only_notes=True, truncate=None, gold=None, sequence_index=None
    ):
        """
        Creates a L{SegmentedMidiInput} from a midi event stream.
        
        @type only_notes: bool
        @param only_notes: if True, only includes note-on/note-off events in 
            the segments. If False, the stream will be sliced so that each 
            segment repeats things like program change events at the beginning.
            Including only notes, however, makes the preprocessing very much 
            faster
        
        """
        # Divide the stream up into slices of the right size
        # Number of ticks in each slice
        tick_unit = int(stream.resolution * time_unit)
        if len(stream.trackpool) == 0:
            end_time = 0
        else:
            end_time = max(stream.trackpool).tick

        if only_notes:
            from midi import EventStream, NoteOnEvent, NoteOffEvent, EndOfTrackEvent

            # Only include notes in the stream
            # This is much simpler and faster than the alternative
            events = [ev for ev in list(sorted(stream.trackpool)) if type(ev) in [NoteOnEvent, NoteOffEvent]]
            events = iter(events)
            try:
                current_event = events.next()
                # Get up to the start point in the stream
                while current_event.tick < tick_offset:
                    current_event = events.next()
            except StopIteration:
                # Got to the end of the stream before we even started
                inputs = []
            else:
                inputs = []
                for chunk_start in range(tick_offset, end_time, tick_unit):
                    chunk_end = chunk_start + tick_unit
                    slc = EventStream()
                    slc.add_track()
                    slc.format = stream.format
                    slc.resolution = stream.resolution
                    slc.segment_start = chunk_start

                    # Add all the note events in this time period
                    try:
                        while current_event.tick < chunk_end:
                            slc.add_event(current_event)
                            current_event = events.next()
                        # Add the end of track event
                        eot = EndOfTrackEvent()
                        eot.tick = chunk_end
                        slc.add_event(eot)
                    except StopIteration:
                        # Reached the end of the stream
                        inputs.append(slc)
                        break

                    inputs.append(slc)
        else:
            # Use slices to do all the necessary repetition of ongoing events
            from midi.slice import EventStreamSlice

            start_times = range(tick_offset, end_time, tick_unit)
            # First slice starts at the offset value
            slices = [EventStreamSlice(stream, chunk_start, chunk_start + tick_unit) for chunk_start in start_times]
            inputs = [slc.to_event_stream(repeat_playing=False, cancel_playing=False) for slc in slices]
            # Associate the start time with each segment
            for slc, start_time in zip(inputs, start_times):
                slc.segment_start = start_time

        # Remove empty segments from the start and end
        current = 0
        # There's always one event - the end of track
        while len(inputs[current].trackpool) < 2:
            current += 1
        inputs = inputs[current:]
        # And the end
        current = len(inputs) - 1
        while len(inputs[current].trackpool) < 2:
            current -= 1
        inputs = inputs[: current + 1]

        if truncate is not None:
            inputs = inputs[:truncate]

        return SegmentedMidiInput(
            inputs,
            time_unit=time_unit,
            tick_offset=tick_offset,
            name=name,
            stream=stream,
            gold=gold,
            sequence_index=sequence_index,
        )
Ejemplo n.º 4
0
def simplify(stream, remove_drums=False, remove_pc=False, 
        remove_all_text=False, one_track=False, remove_tempo=False,
        remove_control=False, one_channel=False, 
        remove_misc_control=False, real_note_offs=False, remove_duplicates=False):
    """
    Filters a midi L{midi.EventStream} to simplify it. This is useful 
    as a preprocessing step before taking midi input to an algorithm, 
    for example, to make it clearer what the algorithm is using.
    
    Use kwargs to determine what filters will be applied. Without any 
    kwargs, the stream will just be left as it was.
    
    Returns a filtered copy of the stream.
    
    @type remove_drums: bool
    @param remove_drums: filter out all channel 10 events
    @type remove_pc: bool
    @param remove_pc: filter out all program change events
    @type remove_all_text: bool
    @param remove_all_text: filter out any text events. This includes 
        copyright, text, track name, lyrics.
    @type one_track: bool
    @param one_track: reduce everything to just one track
    @type remove_tempo: bool
    @param remove_tempo: filter out all tempo events
    @type remove_control: bool
    @param remove_control: filter out all control change events
    @type one_channel: bool
    @param one_channel: use only one channel: set the channel of 
        every event to 0
    @type remove_misc_control: bool
    @param remove_misc_control: filters a miscellany of device 
        control events: aftertouch, channel aftertouch, pitch wheel, 
        sysex, port
    @type real_note_offs: bool
    @param real_note_offs: replace 0-velocity note-ons with actual 
        note-offs. Some midi files use one, some the other
    
    """
    from midi import EventStream, TextEvent, ProgramChangeEvent, \
        CopyrightEvent, TrackNameEvent, \
        SetTempoEvent, ControlChangeEvent, AfterTouchEvent, \
        ChannelAfterTouchEvent, PitchWheelEvent, SysExEvent, \
        LyricsEvent, PortEvent, CuePointEvent, MarkerEvent, EndOfTrackEvent
    import copy
    
    # Empty stream to which we'll add the events we don't filter
    new_stream = EventStream()
    new_stream.resolution = stream.resolution
    new_stream.format = stream.format
    
    # Work out when the first note starts in the input stream
    input_start = first_note_tick(stream)
    
    # Filter track by track
    for track in stream:
        track_events = []
        for ev in sorted(track):
            # Don't add EOTs - they get added automatically
            if type(ev) == EndOfTrackEvent:
                continue
            ev = copy.deepcopy(ev)
            # Each filter may modify the event or continue to filter it altogether
            
            if remove_drums:
                # Filter out any channel 10 events, which is typically 
                #  reserved for drums
                if ev.channel == 9 and \
                        type(ev) in (NoteOnEvent, NoteOffEvent):
                    continue
            if remove_pc:
                # Filter out any program change events
                if type(ev) == ProgramChangeEvent:
                    continue
            if remove_all_text:
                # Filter out any types of text event
                if type(ev) in (TextEvent, CopyrightEvent, TrackNameEvent,
                        LyricsEvent, CuePointEvent, MarkerEvent):
                    continue
            if remove_tempo:
                # Filter out any tempo events
                if type(ev) == SetTempoEvent:
                    continue
            if remove_control:
                # Filter out any control change events
                if type(ev) == ControlChangeEvent:
                    continue
            if remove_misc_control:
                # Filter out various types of control events
                if type(ev) in (AfterTouchEvent, ChannelAfterTouchEvent, 
                        ChannelAfterTouchEvent, PitchWheelEvent, 
                        SysExEvent, PortEvent):
                    continue
            if real_note_offs:
                # Replace 0-velocity note-ons with note-offs
                if type(ev) == NoteOnEvent and ev.velocity == 0:
                    new_ev = NoteOffEvent()
                    new_ev.pitch = ev.pitch
                    new_ev.channel = ev.channel
                    new_ev.tick = ev.tick
                    ev = new_ev
            if one_channel:
                ev.channel = 0
            
            track_events.append(ev)
        
        # If there are events left in the track, add them all as a new track
        if len(track_events) > 1:
            if not one_track or len(new_stream.tracklist) == 0:
                new_stream.add_track()
            for ev in track_events:
                new_stream.add_event(ev)
            track_events = []
    
    for track in stream:
        track.sort()
    
    # Work out when the first note happens now
    result_start = first_note_tick(new_stream)
    # Move all events after and including this sooner so the music 
    #  starts at the same point it did before
    shift = result_start - input_start
    before_start = max(input_start-1, 0)
    if shift > 0:
        for ev in new_stream.trackpool:
            if ev.tick >= result_start:
                ev.tick -= shift
            elif ev.tick < result_start and ev.tick >= input_start:
                # This event happened in a region that no longer contains notes
                # Move it back to before what's now the first note
                ev.tick = before_start
    
    new_stream.trackpool.sort()
    
    if remove_duplicates:
        # Get rid of now duplicate events
        remove_duplicate_notes(new_stream, replay=True)
    
    return new_stream