Exemplo n.º 1
0
    def play(self):
        from midi.slice import EventStreamSlice
        from jazzparser.utils.midi import play_stream

        slc = EventStreamSlice(self.midi.midi_stream, self.start, self.end)
        strm = slc.to_event_stream()
        return play_stream(strm)
Exemplo n.º 2
0
def _play(mid, start, end):
    """ Play the selection """
    if start is None:
        start = 0
    # Trim the midi
    trimmed = EventStreamSlice(mid, start,
                               end).to_event_stream(repeat_playing=False)
    # Show info about the clip
    print "Start tick: %s" % start
    print "End tick: %s" % end
    print "First event tick: %s" % _ticks_to_ticks(mid, start)
    print "Last event tick: %s" % _ticks_to_ticks(mid, end, before=True)
    start_time = float(_get_time(mid, start)) / 1000.0
    print "Start time: %ss" % start_time
    print "Last event time: %ss" % (float(_get_time(mid, end, before=True)) /
                                    1000.0)
    print
    print "Playing MIDI. Hit ctrl+C to stop"
    # Record playing time
    timer = ExecutionTimer()
    try:
        play_stream(trimmed, block=True)
    except KeyboardInterrupt:
        length = timer.get_time()
        print "\nPlayed for %.2f seconds (stopped ~%.2fs)" % (
            length, start_time + length)
Exemplo n.º 3
0
    def get_slices(self):
        """
        Get a list of L{midi.slice.EventStreamSlice}s corresponding to the 
        chunks that this midi stream will be divided into.
        This includes all midi events, not just note-ons.
        
        """
        from midi.slice import EventStreamSlice

        tick_unit = int(self.stream.resolution * self.time_unit)
        if len(self.stream.trackpool) == 0:
            end_time = 0
        else:
            end_time = max(self.stream.trackpool).tick

        slices = [
            EventStreamSlice(self.stream, chunk_start,
                             chunk_start + tick_unit - 1)
            for chunk_start in range(self.tick_offset, end_time, tick_unit)
        ]
        return slices
Exemplo n.º 4
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)
Exemplo n.º 5
0
def main():
    usage = "%prog [options] <midi-input>"
    description = "Trims a MIDI file to the required start and end points. "\
        "By default, plays the trimmed MIDI (for testing) and can also write "\
        "it out to a file."
    parser = OptionParser(usage=usage, description=description)
    parser.add_option(
        "-s",
        "--start",
        dest="start",
        action="store",
        help="start point, in ticks as 'x', or in seconds as 'xs'")
    parser.add_option("-e",
                      "--end",
                      dest="end",
                      action="store",
                      help="end point (formatted as -s)")
    parser.add_option(
        "-o",
        "--output",
        dest="output",
        action="store",
        help=
        "MIDI file to output to. If given, output is stored instead of being played"
    )
    options, arguments = parser.parse_args()

    if len(arguments) == 0:
        print >> sys.stderr, "You must specify a MIDI file"
        sys.exit(1)
    mid = read_midifile(arguments[0])

    def _time_to_ticks(time, before=False):
        # Find the tick time of the first event after the given time
        #  or the last event before it
        mstime = int(time * 1000)
        if time is not None:
            previous = min(mid.trackpool)
            for ev in sorted(mid.trackpool):
                # Look for the first event after the time
                if ev.msdelay >= mstime:
                    if before:
                        # Return the previous event's tick
                        return previous.tick
                    else:
                        # Return this event's tick
                        return ev.tick
                previous = ev
        return max(mid.trackpool).tick

    def _ticks_to_ticks(ticks, before=False):
        # Find the tick time of the first event after the given time
        #  or the last event before it
        if ticks is not None:
            previous = min(mid.trackpool)
            for ev in sorted(mid.trackpool):
                # Look for the first event after the time
                if ev.tick >= ticks:
                    if before:
                        # Return the previous event's tick
                        return previous.tick
                    else:
                        # Return this event's tick
                        return ev.tick
                previous = ev
        return max(mid.trackpool).tick

    def _get_time(ticks, before=False):
        # Find the event time of the first event after the given tick time
        #  or the last event before it
        previous = min(mid.trackpool)
        if ticks is not None:
            for ev in sorted(mid.trackpool):
                # Look for the first event after the time in ticks
                if ev.tick >= ticks:
                    if before:
                        # Return the previous event's time
                        return previous.msdelay
                    else:
                        # Return this event's time
                        return ev.msdelay
                previous = ev
        return max(mid.trackpool).msdelay

    def _parse_time(val, before=False):
        if val.endswith("s"):
            # Value in seconds
            # Convert to ticks
            return _time_to_ticks(float(val[:-1]), before=before)
        else:
            return int(val)

    # Work out start and end points
    if options.start is not None:
        start = _parse_time(options.start, before=False)
    else:
        start = 0

    if options.end is not None:
        end = _parse_time(options.end, before=True)
    else:
        end = None

    if end is not None and start > end:
        print "Start time of %d ticks > end time of %d ticks" % (start, end)
        sys.exit(1)

    # Cut the stream to the desired start and end
    slc = EventStreamSlice(mid, start, end)
    trimmed_mid = slc.to_event_stream(repeat_playing=False)

    # Print out some info
    print "Start tick: %s" % start
    print "End tick: %s" % end
    print
    print "First event tick: %s" % _ticks_to_ticks(start)
    print "Last event tick: %s" % _ticks_to_ticks(end, before=True)
    print
    print "Start time: %ss" % (float(_get_time(start)) / 1000.0)
    print "Last event time: %ss" % (float(_get_time(end, before=True)) /
                                    1000.0)
    print
    print "%d events" % len(trimmed_mid.trackpool)

    # Record playing time
    timer = ExecutionTimer()

    if options.output is None:
        # Play the output by default
        try:
            play_stream(trimmed_mid, block=True)
        except KeyboardInterrupt:
            print "\nPlayed for %.2f seconds" % timer.get_time()
    else:
        # Output to a file
        outfile = os.path.abspath(options.output)
        write_midifile(trimmed_mid, outfile)
        print "Output written to %s" % outfile
def main():
    usage = "%prog [options] <midi-input>"
    description = (
        "Trims a MIDI file to the required start and end points. "
        "By default, plays the trimmed MIDI (for testing) and can also write "
        "it out to a file."
    )
    parser = OptionParser(usage=usage, description=description)
    parser.add_option(
        "-s", "--start", dest="start", action="store", help="start point, in ticks as 'x', or in seconds as 'xs'"
    )
    parser.add_option("-e", "--end", dest="end", action="store", help="end point (formatted as -s)")
    parser.add_option(
        "-o",
        "--output",
        dest="output",
        action="store",
        help="MIDI file to output to. If given, output is stored instead of being played",
    )
    options, arguments = parser.parse_args()

    if len(arguments) == 0:
        print >> sys.stderr, "You must specify a MIDI file"
        sys.exit(1)
    mid = read_midifile(arguments[0])

    def _time_to_ticks(time, before=False):
        # Find the tick time of the first event after the given time
        #  or the last event before it
        mstime = int(time * 1000)
        if time is not None:
            previous = min(mid.trackpool)
            for ev in sorted(mid.trackpool):
                # Look for the first event after the time
                if ev.msdelay >= mstime:
                    if before:
                        # Return the previous event's tick
                        return previous.tick
                    else:
                        # Return this event's tick
                        return ev.tick
                previous = ev
        return max(mid.trackpool).tick

    def _ticks_to_ticks(ticks, before=False):
        # Find the tick time of the first event after the given time
        #  or the last event before it
        if ticks is not None:
            previous = min(mid.trackpool)
            for ev in sorted(mid.trackpool):
                # Look for the first event after the time
                if ev.tick >= ticks:
                    if before:
                        # Return the previous event's tick
                        return previous.tick
                    else:
                        # Return this event's tick
                        return ev.tick
                previous = ev
        return max(mid.trackpool).tick

    def _get_time(ticks, before=False):
        # Find the event time of the first event after the given tick time
        #  or the last event before it
        previous = min(mid.trackpool)
        if ticks is not None:
            for ev in sorted(mid.trackpool):
                # Look for the first event after the time in ticks
                if ev.tick >= ticks:
                    if before:
                        # Return the previous event's time
                        return previous.msdelay
                    else:
                        # Return this event's time
                        return ev.msdelay
                previous = ev
        return max(mid.trackpool).msdelay

    def _parse_time(val, before=False):
        if val.endswith("s"):
            # Value in seconds
            # Convert to ticks
            return _time_to_ticks(float(val[:-1]), before=before)
        else:
            return int(val)

    # Work out start and end points
    if options.start is not None:
        start = _parse_time(options.start, before=False)
    else:
        start = 0

    if options.end is not None:
        end = _parse_time(options.end, before=True)
    else:
        end = None

    if end is not None and start > end:
        print "Start time of %d ticks > end time of %d ticks" % (start, end)
        sys.exit(1)

    # Cut the stream to the desired start and end
    slc = EventStreamSlice(mid, start, end)
    trimmed_mid = slc.to_event_stream(repeat_playing=False)

    # Print out some info
    print "Start tick: %s" % start
    print "End tick: %s" % end
    print
    print "First event tick: %s" % _ticks_to_ticks(start)
    print "Last event tick: %s" % _ticks_to_ticks(end, before=True)
    print
    print "Start time: %ss" % (float(_get_time(start)) / 1000.0)
    print "Last event time: %ss" % (float(_get_time(end, before=True)) / 1000.0)
    print
    print "%d events" % len(trimmed_mid.trackpool)

    # Record playing time
    timer = ExecutionTimer()

    if options.output is None:
        # Play the output by default
        try:
            play_stream(trimmed_mid, block=True)
        except KeyboardInterrupt:
            print "\nPlayed for %.2f seconds" % timer.get_time()
    else:
        # Output to a file
        outfile = os.path.abspath(options.output)
        write_midifile(trimmed_mid, outfile)
        print "Output written to %s" % outfile
Exemplo n.º 7
0
def main():
    usage = "%prog [options] <midi-input1> [<midi-input2> ...]"
    description = "Interactive routine for cutting MIDI files. May take "\
        "multiple MIDI files as input"
    parser = OptionParser(usage=usage, description=description)
    parser.add_option(
        "-o",
        "--output",
        dest="output_dir",
        action="store",
        help=
        "directory to send MIDI output to. If not given, they will be sent to a subdirectory 'cut' of that containing the first input"
    )
    parser.add_option(
        "--fragment",
        dest="fragment",
        action="store",
        type="float",
        help=
        "length in seconds of fragment to play when asked to play a beginning or ending. Default: 3secs",
        default=3.0)
    parser.add_option(
        "--overwrite",
        dest="overwrite",
        action="store_true",
        help=
        "by default, we skip processing any files where there's a file with the same name in the output directory. This forces us to overwrite them"
    )
    parser.add_option(
        "--ignore",
        dest="ignore",
        action="store",
        help=
        "file containing a list of filenames (not paths), one per line: any input files matching these names will be ignored and inputs marked as 'ignore' will be added to the list"
    )
    parser.add_option(
        "--segfile",
        dest="segfile",
        action="store",
        help=
        "output a list of the MIDI files that get written by this script (just the base filename) in the format of segmidi input lists. The list will contain a basic set of default segmentation parameters. Use play_bulk_chunks to validate these. If the file exists, it will be appended"
    )
    options, arguments = parser.parse_args()

    fragment = options.fragment

    if len(arguments) == 0:
        print >> sys.stderr, "You must specify at least one MIDI file"
        sys.exit(1)
    # Read in all the MIDI inputs
    filenames = arguments
    print "Processing %d inputs" % len(filenames)

    if options.ignore:
        if os.path.exists(options.ignore):
            # Existing list
            # Open the file to read in the current list and add to it
            ignore_file = open(options.ignore, 'r+a')
            ignore_list = [
                filename.strip("\n") for filename in ignore_file.readlines()
            ]
            print "Loaded ignore list from %s" % options.ignore
        else:
            # No existing list
            # Open the file so we can write new entries
            ignore_file = open(options.ignore, 'w')
            ignore_list = []
            print "Created new ignore list in %s" % options.ignore
    else:
        ignore_file = None
        ignore_list = []

    if options.segfile:
        # Open the file for writing segmidi parameters to
        segfile = open(options.segfile, 'a')
        segcsv = csv.writer(segfile)
    else:
        segfile = None

    try:
        # Set up the output directory
        if options.output_dir:
            output_dir = options.output_dir
        else:
            # Get the directory of the first input file
            output_dir = os.path.join(os.path.dirname(filenames[0]), "cut")
        check_directory(output_dir, is_dir=True)
        print "Outputing MIDI files to %s" % output_dir
        print

        for filename in filenames:
            basename = os.path.basename(filename)
            # Ignore any files in the ignore list
            if basename in ignore_list:
                print "Skipping input %s, as it's in the ignore list" % basename
                continue

            out_filename = os.path.join(output_dir, os.path.basename(filename))
            # Check whether the output file already exists
            if os.path.exists(out_filename):
                if options.overwrite:
                    # Just warn
                    print "WARNING: writing out this input will overwrite an existing file"
                else:
                    # Don't continue with this input
                    print "Skipping input %s, since output file already exists" % filename
                    continue

            start = 0
            end = None

            print "\n####################################"
            print "Processing input: %s" % filename
            # Read in the midi file
            try:
                mid = read_midifile(filename)
            except Exception, err:
                print "Error reading in midi file %s: %s" % (filename, err)
                continue
            print "Output will be written to: %s" % out_filename
            # Start by playing the whole thing
            _play(mid, start, end)

            try:
                while True:
                    # Print the header information
                    print "\n>>>>>>>>>>>>>>>>>>>>>>"
                    if end is None:
                        end_str = "open"
                    else:
                        end_str = "%d ticks" % end
                    print "Start: %d ticks. End: %s" % (start, end_str)
                    print ">>>>>>>>>>>>>>>>>>>>>>"
                    print "Set start time (s); set end time (e)"
                    print "Play all (p); play beginning ([); play end (], optional length)"
                    print "Write out and proceed (w); add to ignore list (i); skip to next (n); exit (x)"

                    # Get a command from the user
                    try:
                        command = raw_input(">> ")
                    except KeyboardInterrupt:
                        # I quite often send an interrupt by accident, meaning
                        #  to stop the playback, but just after it's stopped
                        #  itself
                        print "Ignored keyboard interrupt"
                        continue

                    command = command.strip()
                    if command.lower() == "p":
                        # Play within the selection again
                        _play(mid, start, end)
                    elif command.lower() == "n":
                        break
                    elif command.lower() == "i":
                        # Add the filename to the ignore list
                        if ignore_file:
                            ignore_file.write("%s\n" %
                                              os.path.basename(filename))
                        else:
                            print "No ignore file loaded: could not add this file to the list"
                        break
                    elif command.lower() == "x":
                        sys.exit(0)
                    elif command.lower().startswith("s"):
                        time = command[1:].strip()
                        if len(time) == 0:
                            print "Specify a start tick (T) or time (Ts)"
                            continue
                        start = _parse_time(mid, time)
                    elif command.lower().startswith("e"):
                        time = command[1:].strip()
                        if len(time) == 0:
                            print "Specify an end tick (T) or time (Ts)"
                            continue
                        end = _parse_time(mid, time, before=True)
                    elif command == "[":
                        # Play the opening few seconds
                        start_secs = _get_time(mid, start) / 1000.0
                        frag_end = _time_to_ticks(mid, fragment + start_secs)
                        _play(mid, start, frag_end)
                    elif command.startswith("]"):
                        length = command[1:].strip()
                        if len(length):
                            frag_length = float(length)
                        else:
                            frag_length = fragment
                        # Play the last few seconds
                        end_secs = _get_time(mid, end) / 1000.0
                        frag_start = _time_to_ticks(
                            mid, max(0.0, end_secs - frag_length), before=True)
                        _play(mid, frag_start, end)
                    elif command == "w":
                        # Write the file out
                        if start is None:
                            start = 0
                        # Trim the midi
                        trimmed = EventStreamSlice(
                            mid, start,
                            end).to_event_stream(repeat_playing=False)
                        # Write it out
                        write_midifile(trimmed, out_filename)
                        if segfile is not None:
                            # Also output a row to the segmidi index
                            SegmentedMidiBulkInput.writeln(segcsv, basename)
                        print "Output written to %s" % out_filename
                        # Continue to the next input
                        break
                    else:
                        print "Unknown command: %s" % command
                        continue
            except EOFError:
                # User hit ctrl+D: continue to next input
                print "Continuing to next input..."
                continue
        else: