Example #1
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)
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)
Example #3
0
    def parse(self, derivations=False, summaries=False, inspect=False):
        """
        Run the parser on the input, using the specified tagger. Runs 
        the CKY parsing algorithm to do chart parsing. For details of 
        chart parsing, see Chart class.
        
        If the parser was given a maximum number of iterations, the 
        routine will return as usual after this number is completed, 
        even if no parses have been found.
        
        @type derivations: bool
        @param derivations: store derivation traces, which 
            can subsequently be used to trace all the derivations that 
            led to any given sign in the chart. Overridden by the module 
            option if it's given
        @type summaries: int/bool
        @param summaries: output chart summary information to stderr during 
            parsing to track progress. Set to 2 to output some info, 
            but not the full chart.
        @type inspect: bool
        @param inspect: launch a graphical chart inspector during the 
            parse to display interactive chart information.
            
        @return: a list of signs that span the full input.
        """
        if 'derivations' in self.options and self.options[
                'derivations'] is not None:
            derivations = self.options['derivations']

        # Time excecution if we're showing any summaries
        time = bool(summaries)
        # Find out from the tagger how long the input it read in was
        input_length = self.tagger.input_length
        # Create and initialise a chart for parsing
        # Don't initialise the chart with signs - we'll add signs gradually instead
        chart = self._create_chart([[]] * input_length,
                                   derivations=derivations)

        # Launch a chart inspector if requested
        if self.options['inspect'] or inspect:
            # Get a string form of the input to display
            input_strs = self.tagger.get_string_input()
            chart.launch_inspector(input=input_strs)
        # Start dumping the chart if requested
        if self.options['dump_chart']:
            # Make the first dump of the empty chart
            from .chart import dump_chart
            dump_chart(chart, self.options['dump_chart'])
        # Stop after a given number of iterations
        if self.options['max_iter'] == 0:
            max_iter = None
        else:
            max_iter = self.options['max_iter']

        if self.options['min_iter'] == -1:
            # Special case: never stop until we've got all the categories
            min_iter = None
        else:
            min_iter = self.options['min_iter']

        required_parses = self.options['parses']

        timeout = 60 * self.options['timeout']
        check_timeout = timeout > 0
        # Make sure the timed out flag is unset to start with
        self.timed_out = False

        # This is where progress output will go
        # Note that it's not the same as logger, which is the main system logger
        prog_logger = self.logger

        if check_timeout:
            prog_logger.info("Due to timeout after %d mins" %
                             self.options['timeout'])

        ##################################################
        ### Here is the parser itself.
        # Keep track of how long since we started for timing out
        timeout_timer = ExecutionTimer(clock=True)

        signs_taken = [0] * input_length

        offset = 0
        last_lexicals = [0] * (input_length)
        try:
            # Keep adding signs until none left, or we get a full parse,
            #  or we complete the maximum iterations allowed
            # Keep going if min_iter is None (special value meaning don't stop
            #  when we get a parse
            while (min_iter is None or (offset < min_iter) \
                                        or len(chart.parses) < required_parses):
                if max_iter is not None and offset >= max_iter:
                    # Exceded maximum number of iterations: give up
                    prog_logger.info("Reached maximum number of iterations: "\
                                        "continuing to backoff/fail")
                    break
                prog_logger.info(">>> Parsing iteration: %d" % (offset + 1))
                # Get new signs from the tagger
                added = self._add_signs(offset=offset)
                # Note whether we added anything new
                if added:
                    # Apply unary rules to these new signs
                    added_spans = set([(start, end)
                                       for (start, end, sign) in added])
                    for (start, end) in added_spans:
                        chart.apply_unary_rules(start, end)
                else:
                    # No new signs added by the tagger: no point in continuing
                    prog_logger.info("No new signs added: ending parse")
                    break

                ##### Main parser loop: produce all possible results
                # Set end point to each node
                for end in range(1, input_length + 1):
                    if time:
                        # Start a timer
                        timer = ExecutionTimer()
                    chart.apply_unary_rules(end - 1, end)

                    # Set start point to each node before the end, in reverse order
                    for start in range(end - 2, -1, -1):
                        for middle in range(start + 1, end):
                            chart.apply_binary_rules(start, middle, end)

                            # Check whether the timeout has expired and don't process
                            #  any more if it has
                            if check_timeout:
                                # Check whether the timeout has passed
                                if int(timeout_timer.get_time()) > timeout:
                                    # Move on to post-parse stuff
                                    raise ParserTimeout

                        # Check for new unary rule applications
                        chart.apply_unary_rules(start, end)

                    if summaries:
                        prog_logger.info(
                            "Completed parsing up to node %d / %d (%.2f secs)"
                            % (end, input_length, timer.get_time()))
                        if summaries != 2:
                            prog_logger.info(chart.summary)
                    if self.options['dump_chart']:
                        # Dump an update of the chart to the file
                        dump_chart(chart, self.options['dump_chart'])

                if summaries:
                    prog_logger.info("Completed parsing to end of sequence")
                    if summaries != 2:
                        prog_logger.info(chart.summary)

                offset += 1
        except ParserTimeout:
            # The given timeout elapsed: just continue with no parses
            prog_logger.info("Parse timeout (%d mins) expired: continuing "\
                            "to backoff/fail" % self.options['timeout'])
            # Set the timed_out flag so we can check later whether we timed out
            self.timed_out = True
        except KeyboardInterrupt:
            # We pass the interrupt on to a higher level, but first kill
            #  the inspector window, so it doesn't hang around and mess up
            self.chart.kill_inspector()
            raise

        parses = chart.parses
        if len(parses) == 0 and self.backoff is not None:
            prog_logger.info("Using backoff model")
            backoff_results = self.run_backoff()
            if len(backoff_results) > 0:
                for res in backoff_results:
                    # Put the semantics result into a sign, with a dummy
                    #  syntactic category
                    sign = self.grammar.formalism.Syntax.Sign(
                        self.grammar.formalism.Syntax.DummyCategory(), res)
                    # If the semantics has a probability, put this on the sign
                    if hasattr(res, "probability"):
                        sign.probability = res.probability
                    parses.append(sign)
        elif len(parses):
            prog_logger.info("Parse finished with %d results" % len(parses))
        else:
            prog_logger.info("Parse finished with no results")

        # Close the inspector window if one was opened
        if not self.options['inspect_persist']:
            self.chart.kill_inspector()

        return parses
Example #4
0
 def parse(self, derivations=False, summaries=False, inspect=False):
     # Find out from the tagger how long the input it read in was
     input_length = self.tagger.input_length
     # Create and initialise a chart for parsing
     # Don't initialise the chart with signs - we'll add signs gradually instead
     chart = self._create_chart(
                             [[]]*input_length,
                             derivations=derivations)
     
     # Stop after a given number of iterations
     if self.options['max_iter'] == 0:
         max_iter = None
     else:
         max_iter = self.options['max_iter']
     timeout = 60*self.options['timeout']
     check_timeout = timeout>0
     
     # This is where progress output will go
     # Note that it's not the same as logger, which is the main system logger
     prog_logger = self.logger
     
     if check_timeout:
         prog_logger.info("Due to timeout after %d mins" % self.options['timeout'])
     
     ##################################################
     ### The dummy parse loop
     # Keep track of how long since we started for timing out
     timeout_timer = ExecutionTimer()
     
     signs_added = True
     offset = 0
     try:
         # Keep adding signs until none left
         while len(chart.get_signs(0, input_length)) == 0 and signs_added:
             if max_iter is not None and offset >= max_iter:
                 # Exceded maximum number of iterations: give up
                 prog_logger.info("Reached maximum number of iterations: "\
                                     "continuing to backoff/fail")
                 break
             prog_logger.info(">>> Parsing iteration: %d" % (offset+1))
             
             # Get new signs from the tagger
             added = self._add_signs(offset=offset)
             # Note whether we added anything new
             signs_added = bool(added)
 
             # Check whether the timeout has expired
             if check_timeout:
                 if int(timeout_timer.get_time()) > timeout:
                     raise ParserTimeout
             # Don't do any parsing: just go round again to get more signs
             offset += 1
     except ParserTimeout:
         # The given timeout elapsed: just continue with no parses
         logger.debug("Parse loop timeout (%d mins) expired" % self.options['timeout'])
         prog_logger.info("Parse timeout (%d mins) expired: continuing "\
                         "to backoff/fail" % self.options['timeout'])
     
     parses = []
     # If a backoff model was given, always use it now
     if self.backoff is not None:
         backoff_results = self.run_backoff()
         if len(backoff_results) > 0:
             for res in backoff_results:
                 # Put the semantics result into a sign, with a dummy 
                 #  syntactic category
                 sign = self.grammar.formalism.Syntax.Sign(
                             self.grammar.formalism.Syntax.DummyCategory(),
                             res)
                 # If the semantics has a probability, put this on the sign
                 if hasattr(res, "probability"):
                     sign.probability = res.probability
                 parses.append(sign)
     
     return parses
Example #5
0
 def parse(self, derivations=False, summaries=False, inspect=False):
     """
     Run the parser on the input, using the specified tagger. Runs 
     the CKY parsing algorithm to do chart parsing. For details of 
     chart parsing, see Chart class.
     
     If the parser was given a maximum number of iterations, the 
     routine will return as usual after this number is completed, 
     even if no parses have been found.
     
     @type derivations: bool
     @param derivations: store derivation traces, which 
         can subsequently be used to trace all the derivations that 
         led to any given sign in the chart. Overridden by the module 
         option if it's given
     @type summaries: int/bool
     @param summaries: output chart summary information to stderr during 
         parsing to track progress. Set to 2 to output some info, 
         but not the full chart.
     @type inspect: bool
     @param inspect: launch a graphical chart inspector during the 
         parse to display interactive chart information.
         
     @return: a list of signs that span the full input.
     """
     if 'derivations' in self.options and self.options['derivations'] is not None:
         derivations = self.options['derivations']
         
     # Time excecution if we're showing any summaries
     time = bool(summaries)
     # Find out from the tagger how long the input it read in was
     input_length = self.tagger.input_length
     # Create and initialise a chart for parsing
     # Don't initialise the chart with signs - we'll add signs gradually instead
     chart = self._create_chart(
                             [[]]*input_length,
                             derivations=derivations)
     
     # Launch a chart inspector if requested
     if self.options['inspect'] or inspect:
         # Get a string form of the input to display
         input_strs = self.tagger.get_string_input()
         chart.launch_inspector(input=input_strs)
     # Start dumping the chart if requested
     if self.options['dump_chart']:
         # Make the first dump of the empty chart
         from .chart import dump_chart
         dump_chart(chart, self.options['dump_chart'])
     # Stop after a given number of iterations
     if self.options['max_iter'] == 0:
         max_iter = None
     else:
         max_iter = self.options['max_iter']
         
     if self.options['min_iter'] == -1:
         # Special case: never stop until we've got all the categories
         min_iter = None
     else:
         min_iter = self.options['min_iter']
         
     required_parses = self.options['parses']
     
     timeout = 60*self.options['timeout']
     check_timeout = timeout>0
     # Make sure the timed out flag is unset to start with
     self.timed_out = False
     
     # This is where progress output will go
     # Note that it's not the same as logger, which is the main system logger
     prog_logger = self.logger
     
     if check_timeout:
         prog_logger.info("Due to timeout after %d mins" % self.options['timeout'])
     
     ##################################################
     ### Here is the parser itself.
     # Keep track of how long since we started for timing out
     timeout_timer = ExecutionTimer(clock=True)
     
     signs_taken = [0]*input_length
         
     offset = 0
     last_lexicals = [0]*(input_length)
     try:
         # Keep adding signs until none left, or we get a full parse, 
         #  or we complete the maximum iterations allowed
         # Keep going if min_iter is None (special value meaning don't stop 
         #  when we get a parse
         while (min_iter is None or (offset < min_iter) \
                                     or len(chart.parses) < required_parses):
             if max_iter is not None and offset >= max_iter:
                 # Exceded maximum number of iterations: give up
                 prog_logger.info("Reached maximum number of iterations: "\
                                     "continuing to backoff/fail")
                 break
             prog_logger.info(">>> Parsing iteration: %d" % (offset+1))
             # Get new signs from the tagger
             added = self._add_signs(offset=offset)
             # Note whether we added anything new
             if added:
                 # Apply unary rules to these new signs
                 added_spans = set([(start,end) for (start,end,sign) in added])
                 for (start,end) in added_spans:
                     chart.apply_unary_rules(start,end)
             else:
                 # No new signs added by the tagger: no point in continuing 
                 prog_logger.info("No new signs added: ending parse")
                 break
              
             ##### Main parser loop: produce all possible results
             # Set end point to each node
             for end in range(1,input_length+1):
                 if time:
                     # Start a timer
                     timer = ExecutionTimer()
                 chart.apply_unary_rules(end-1, end)
                 
                 # Set start point to each node before the end, in reverse order
                 for start in range(end-2,-1,-1):
                     for middle in range(start+1,end):
                         chart.apply_binary_rules(start, middle, end)
                         
                         # Check whether the timeout has expired and don't process 
                         #  any more if it has
                         if check_timeout:
                             # Check whether the timeout has passed
                             if int(timeout_timer.get_time()) > timeout:
                                 # Move on to post-parse stuff
                                 raise ParserTimeout
                     
                     # Check for new unary rule applications
                     chart.apply_unary_rules(start, end)
             
                 if summaries:
                     prog_logger.info("Completed parsing up to node %d / %d (%.2f secs)" % (end,input_length, timer.get_time()))
                     if summaries != 2:
                         prog_logger.info(chart.summary)
                 if self.options['dump_chart']:
                     # Dump an update of the chart to the file
                     dump_chart(chart, self.options['dump_chart'])
                 
             if summaries:
                 prog_logger.info("Completed parsing to end of sequence")
                 if summaries != 2:
                     prog_logger.info(chart.summary)
             
             offset += 1
     except ParserTimeout:
         # The given timeout elapsed: just continue with no parses
         prog_logger.info("Parse timeout (%d mins) expired: continuing "\
                         "to backoff/fail" % self.options['timeout'])
         # Set the timed_out flag so we can check later whether we timed out
         self.timed_out = True
     except KeyboardInterrupt:
         # We pass the interrupt on to a higher level, but first kill 
         #  the inspector window, so it doesn't hang around and mess up
         self.chart.kill_inspector()
         raise
     
     parses = chart.parses
     if len(parses) == 0 and self.backoff is not None:
         prog_logger.info("Using backoff model")
         backoff_results = self.run_backoff()
         if len(backoff_results) > 0:
             for res in backoff_results:
                 # Put the semantics result into a sign, with a dummy 
                 #  syntactic category
                 sign = self.grammar.formalism.Syntax.Sign(
                             self.grammar.formalism.Syntax.DummyCategory(),
                             res)
                 # If the semantics has a probability, put this on the sign
                 if hasattr(res, "probability"):
                     sign.probability = res.probability
                 parses.append(sign)
     elif len(parses):
         prog_logger.info("Parse finished with %d results" % len(parses))
     else:
         prog_logger.info("Parse finished with no results")
     
     # Close the inspector window if one was opened
     if not self.options['inspect_persist']:
         self.chart.kill_inspector()
     
     return parses
Example #6
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
Example #7
0
    def parse(self, derivations=False, summaries=False, inspect=False):
        # Find out from the tagger how long the input it read in was
        input_length = self.tagger.input_length
        # Create and initialise a chart for parsing
        # Don't initialise the chart with signs - we'll add signs gradually instead
        chart = self._create_chart([[]] * input_length,
                                   derivations=derivations)

        # Stop after a given number of iterations
        if self.options['max_iter'] == 0:
            max_iter = None
        else:
            max_iter = self.options['max_iter']
        timeout = 60 * self.options['timeout']
        check_timeout = timeout > 0

        # This is where progress output will go
        # Note that it's not the same as logger, which is the main system logger
        prog_logger = self.logger

        if check_timeout:
            prog_logger.info("Due to timeout after %d mins" %
                             self.options['timeout'])

        ##################################################
        ### The dummy parse loop
        # Keep track of how long since we started for timing out
        timeout_timer = ExecutionTimer()

        signs_added = True
        offset = 0
        try:
            # Keep adding signs until none left
            while len(chart.get_signs(0, input_length)) == 0 and signs_added:
                if max_iter is not None and offset >= max_iter:
                    # Exceded maximum number of iterations: give up
                    prog_logger.info("Reached maximum number of iterations: "\
                                        "continuing to backoff/fail")
                    break
                prog_logger.info(">>> Parsing iteration: %d" % (offset + 1))

                # Get new signs from the tagger
                added = self._add_signs(offset=offset)
                # Note whether we added anything new
                signs_added = bool(added)

                # Check whether the timeout has expired
                if check_timeout:
                    if int(timeout_timer.get_time()) > timeout:
                        raise ParserTimeout
                # Don't do any parsing: just go round again to get more signs
                offset += 1
        except ParserTimeout:
            # The given timeout elapsed: just continue with no parses
            logger.debug("Parse loop timeout (%d mins) expired" %
                         self.options['timeout'])
            prog_logger.info("Parse timeout (%d mins) expired: continuing "\
                            "to backoff/fail" % self.options['timeout'])

        parses = []
        # If a backoff model was given, always use it now
        if self.backoff is not None:
            backoff_results = self.run_backoff()
            if len(backoff_results) > 0:
                for res in backoff_results:
                    # Put the semantics result into a sign, with a dummy
                    #  syntactic category
                    sign = self.grammar.formalism.Syntax.Sign(
                        self.grammar.formalism.Syntax.DummyCategory(), res)
                    # If the semantics has a probability, put this on the sign
                    if hasattr(res, "probability"):
                        sign.probability = res.probability
                    parses.append(sign)

        return parses
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
Example #9
0
def do_parse(grammar, tagger_cls, parser_cls, input, topts, popts, backoff, 
        npopts, options, identifier, multiprocessing=False, 
        logfile=None, partition=None):
    """
    Function called for each input to do tagging and parsing and return the 
    results. It's a separate function so that we can hand it over to worker 
    processes to do multiprocessing.
    
    @type logfile: str
    @param logfile: filename to send logging output to. If None, will log 
        to stderr
    
    """
    # If the input's a string, preprocess it
    if isinstance(input, str):
        input = input.rstrip("\n")
        if len(input) == 0:
            return
        input = ChordInput.from_string(input)
    
    print "Processing input: %s (%s)" % (input, identifier)
        
    if logfile is None:
        # Sending logging output to stderr
        logger = create_plain_stderr_logger()
    else:
        logger = create_logger(filename=logfile)
        print "Logging parser progress to %s" % logfile
    
    # Prepare an initial response
    # We'll fill in some values of this later
    response = {
        'tagger' : None,
        'parser' : None,
        'input' : input,
        'error' : None,
        'messages' : [],
        'time' : None,
        'identifier' : identifier,
        'results' : None,
        'timed_out' : False,
    }
    tagger = None
    parser = None
    messages = []
    
    if options.short_progress:
        # Only output the short form of the progress reports
        progress = 2
    elif options.long_progress:
        progress = 1
    else:
        progress = 0
    
    # Start a timer now to time the parse
    timer = ExecutionTimer(clock=True)
    
    # Catch any errors and continue to the next input, instead of giving up
    try:
        ######### Do that parsing thang
        logger.info("Tagging sequence (%d timesteps)" % len(input))
        
        # Prepare a suitable tagger component
        tagger = tagger_cls(grammar, input, options=topts.copy(), logger=logger)
        if not multiprocessing:
            response['tagger'] = tagger
        
        # Create a parser using this tagger
        parser = parser_cls(grammar, tagger, options=popts.copy(), 
                                backoff=backoff, 
                                backoff_options=npopts.copy(),
                                logger=logger)
        if not multiprocessing:
            response['parser'] = parser
        try:
            # Parse to produce a list of results
            results = parser.parse(derivations=options.derivations, summaries=progress)
        except (KeyboardInterrupt, Exception), err:
            if multiprocessing:
                # Don't go interactive if we're in a subprocess
                # Instead, just return with an error
                response.update({
                    'error' : exception_tuple(str_tb=True),
                })
                return response
            else:
                # Drop into the shell
                if type(err) == KeyboardInterrupt:
                    print "Dropping out on keyboard interrupt"
                    print "Entering shell: use 'chart' command to see current state of parse"
                elif options.error_shell:
                    print >> sys.stderr, "Error parsing %s" % str(input)
                    print >> sys.stderr, "The error was:"
                    traceback.print_exc(file=sys.stderr)
                # If we keyboard interrupted, always go into the shell, so 
                #  the user can see how far we got
                if options.error_shell or type(err) == KeyboardInterrupt:
                    # Instead of exiting, enter the interactive shell
                    print 
                    from jazzparser.shell import interactive_shell
                    env = {}
                    env.update(globals())
                    env.update(locals())
                    interactive_shell(parser.chart.parses,options,tagger,parser,
                                grammar.formalism,env,input_data=input)
                    return
                else:
                    raise
    except (KeyboardInterrupt, Exception), err:
        if multiprocessing:
            response.update({
                'error' : exception_tuple(str_tb=True),
            })
            return response
        else:
            if type(err) == KeyboardInterrupt:
                print "Exiting on keyboard interrupt"
                sys.exit(1)
            else:
                response.update({
                    'error' : exception_tuple(str_tb=True),
                    'messages' : messages,
                    'time' : timer.get_time(),
                })
                return response