'Converts the Performance to NoteSequence proto.
Args:
velocity: MIDI velocity to give each note. Between 1 and 127 (inclusive).
If the performance contains velocity events, those will be used
instead.
instrument: MIDI instrument to give each note.
program: MIDI program to give each note.
max_note_duration: Maximum note duration in seconds to allow. Notes longer
than this will be truncated. If None, notes can be any length.
Raises:
ValueError: if an unknown event is encountered.
Returns:
A NoteSequence proto.'

def to_sequence(self, velocity=100, instrument=0, program=0, max_note_duration=None):

    seconds_per_step = (1.0 / self._steps_per_second)
    sequence_start_time = (self.start_step * seconds_per_step)
    sequence = music_pb2.NoteSequence()
    sequence.ticks_per_quarter = STANDARD_PPQ
    step = 0
    if self._num_velocity_bins:
        velocity_bin_size = int(math.ceil((((MAX_MIDI_VELOCITY - MIN_MIDI_VELOCITY) + 1) / self._num_velocity_bins)))
    pitch_start_steps_and_velocities = collections.defaultdict(list)
    for (i, event) in enumerate(self):
        if (event.event_type == PerformanceEvent.NOTE_ON):
            pitch_start_steps_and_velocities[event.event_value].append((step, velocity))
        elif (event.event_type == PerformanceEvent.NOTE_OFF):
            if (not pitch_start_steps_and_velocities[event.event_value]):
                tf.logging.debug(('Ignoring    NOTE_OFF    at    position    %d    with    no    previous    NOTE_ON' % i))
            else:
                (pitch_start_step, pitch_velocity) = pitch_start_steps_and_velocities[event.event_value][0]
                pitch_start_steps_and_velocities[event.event_value] = pitch_start_steps_and_velocities[event.event_value][1:]
                if (step == pitch_start_step):
                    tf.logging.debug(('Ignoring    note    with    zero    duration    at    step    %d' % step))
                    continue
                note = sequence.notes.add()
                note.start_time = ((pitch_start_step * seconds_per_step) + sequence_start_time)
                note.end_time = ((step * seconds_per_step) + sequence_start_time)
                if (max_note_duration and ((note.end_time - note.start_time) > max_note_duration)):
                    note.end_time = (note.start_time + max_note_duration)
                note.pitch = event.event_value
                note.velocity = pitch_velocity
                note.instrument = instrument
                note.program = program
                if (note.end_time > sequence.total_time):
                    sequence.total_time = note.end_time
        elif (event.event_type == PerformanceEvent.TIME_SHIFT):
            step += event.event_value
        elif (event.event_type == PerformanceEvent.VELOCITY):
            assert self._num_velocity_bins
            velocity = (MIN_MIDI_VELOCITY + ((event.event_value - 1) * velocity_bin_size))
        else:
            raise ValueError(('Unknown    event    type:    %s' % event.event_type))
    for pitch in pitch_start_steps_and_velocities:
        for (pitch_start_step, pitch_velocity) in pitch_start_steps_and_velocities[pitch]:
            if (step == pitch_start_step):
                tf.logging.debug(('Ignoring    note    with    zero    duration    at    step    %d' % step))
                continue
            note = sequence.notes.add()
            note.start_time = ((pitch_start_step * seconds_per_step) + sequence_start_time)
            note.end_time = ((step * seconds_per_step) + sequence_start_time)
            if (max_note_duration and ((note.end_time - note.start_time) > max_note_duration)):
                note.end_time = (note.start_time + max_note_duration)
            note.pitch = pitch
            note.velocity = pitch_velocity
            note.instrument = instrument
            note.program = program
            if (note.end_time > sequence.total_time):
                sequence.total_time = note.end_time
    return sequence
