class_docstr: Converts to/from multiple-instrument metric performances.
  
  Attributes:
    num_velocity_bins: Number of velocity bins.
    max_tensors_per_notesequence: The maximum number of outputs to return
        for each NoteSequence.
    hop_size_bars: How many bars each sequence should be.
    chunk_size_bars: Chunk size used for hierarchically decomposing sequence.
    steps_per_quarter: Number of time steps per quarter note.
    quarters_per_bar: Number of quarter notes per bar.
    min_num_instruments: Minimum number of instruments per sequence.
    max_num_instruments: Maximum number of instruments per sequence.
    min_total_events: Minimum total length of all performance tracks, in events.
    max_events_per_instrument: Maximum length of a single-instrument
        performance, in events.
    first_subsequence_only: If True, only use the very first hop and discard all
        sequences longer than the hop size.
    chord_encoding: An instantiated OneHotEncoding object to use for encoding
        chords on which to condition, or None if not conditioning on chords.
    drop_tracks_and_truncate: Randomly drop extra tracks and truncate the event
        sequence.
class_docstr_tok: ["Converts","to\/from","multiple-instrument","metric","performances",".","Attributes",":","num_velocity_bins",":","Number","of","velocity","bins",".","max_tensors_per_notesequence",":","The","maximum","number","of","outputs","to","return","for","each","NoteSequence",".","hop_size_bars",":","How","many","bars","each","sequence","should","be",".","chunk_size_bars",":","Chunk","size","used","for","hierarchically","decomposing","sequence",".","steps_per_quarter",":","Number","of","time","steps","per","quarter","note",".","quarters_per_bar",":","Number","of","quarter","notes","per","bar",".","min_num_instruments",":","Minimum","number","of","instruments","per","sequence",".","max_num_instruments",":","Maximum","number","of","instruments","per","sequence",".","min_total_events",":","Minimum","total","length","of","all","performance","tracks",",","in","events",".","max_events_per_instrument",":","Maximum","length","of","a","single-instrument","performance",",","in","events",".","first_subsequence_only",":","If","True",",","only","use","the","very","first","hop","and","discard","all","sequences","longer","than","the","hop","size",".","chord_encoding",":","An","instantiated","OneHotEncoding","object","to","use","for","encoding","chords","on","which","to","condition",",","or","None","if","not","conditioning","on","chords",".","drop_tracks_and_truncate",":","Randomly","drop","extra","tracks","and","truncate","the","event","sequence","."]
code: def _to_single_notesequence(self, samples, controls):
      qpm = note_seq.DEFAULT_QUARTERS_PER_MINUTE
      seconds_per_step = 60.0 / (self._steps_per_quarter * qpm)
      chunk_size_steps = self._steps_per_bar * self._chunk_size_bars
  
      seq = note_seq.NoteSequence()
      seq.tempos.add().qpm = qpm
      seq.ticks_per_quarter = note_seq.STANDARD_PPQ
  
      tracks = [[] for _ in range(self._max_num_instruments)]
      all_timed_chords = []
  
      for chunk_index, encoded_chunk in enumerate(samples):
          chunk_step_offset = chunk_index * chunk_size_steps
  
          # Decode all tracks in this chunk into performance representation.
          # We don't immediately convert to NoteSequence as we first want to group
          # by track and concatenate.
          for instrument, encoded_track in enumerate(encoded_chunk):
              track_tokens = np.argmax(encoded_track, axis=-1)
  
              # Trim to end token.
              if self.end_token in track_tokens:
                  idx = track_tokens.tolist().index(self.end_token)
                  track_tokens = track_tokens[:idx]
  
              # Handle program token. If there are extra program tokens, just use the
              # first one.
              program_tokens = [
                  token
                  for token in track_tokens
                  if token >= self._performance_encoding.num_classes
              ]
              track_token_indices = [
                  idx
                  for idx, t in enumerate(track_tokens)
                  if t < self._performance_encoding.num_classes
              ]
              track_tokens = [
                  track_tokens[idx] for idx in track_token_indices
              ]
              if not program_tokens:
                  program = 0
                  is_drum = False
              else:
                  program = (
                      program_tokens[0]
                      - self._performance_encoding.num_classes
                  )
                  if program == note_seq.MAX_MIDI_PROGRAM + 1:
                      # This is the drum program.
                      program = 0
                      is_drum = True
                  else:
                      is_drum = False
  
              # Decode the tokens into a performance track.
              track = performance_lib.MetricPerformance(
                  quantized_sequence=None,
                  steps_per_quarter=self._steps_per_quarter,
                  start_step=0,
                  num_velocity_bins=self._num_velocity_bins,
                  program=program,
                  is_drum=is_drum,
              )
              for token in track_tokens:
                  track.append(
                      self._performance_encoding.decode_event(token)
                  )
  
              if controls is not None:
                  # Get the corresponding chord and time for each event in the track.
                  # This is a little tricky since we removed extraneous program tokens
                  # when constructing the track.
                  track_chord_tokens = np.argmax(
                      controls[chunk_index][instrument], axis=-1
                  )
                  track_chord_tokens = [
                      track_chord_tokens[idx]
                      for idx in track_token_indices
                  ]
                  chords = [
                      self._chord_encoding.decode_event(token)
                      for token in track_chord_tokens
                  ]
                  chord_times = [
                      (chunk_step_offset + step) * seconds_per_step
                      for step in track.steps
                      if step < chunk_size_steps
                  ]
                  all_timed_chords += zip(chord_times, chords)
  
              # Make sure the track has the proper length in time steps.
              track.set_length(chunk_size_steps)
  
              # Aggregate by instrument.
              tracks[instrument].append(track)
  
      # Concatenate all of the track chunks for each instrument.
      for instrument, track_chunks in enumerate(tracks):
          if track_chunks:
              track = track_chunks[0]
              for t in track_chunks[1:]:
                  for e in t:
                      track.append(e)
  
          track_seq = track.to_sequence(instrument=instrument, qpm=qpm)
          seq.notes.extend(track_seq.notes)
  
      # Set total time.
      if seq.notes:
          seq.total_time = max(note.end_time for note in seq.notes)
  
      if self._chord_encoding:
          # Sort chord times from all tracks and add to the sequence.
          all_chord_times, all_chords = zip(*sorted(all_timed_chords))
          chords_lib.add_chords_to_sequence(
              seq, all_chords, all_chord_times
          )
  
      return seq
  
imports: import abc
  import random
  from magenta.models.music_vae import data
  from magenta.pipelines import performance_pipeline
  import note_seq
  from note_seq import chords_lib
  from note_seq import performance_lib
  import numpy
  import tensorflow.compat.v1
label_desc: Use image node_id 5 for calling the MultiInstrumentPerformanceConverter obj's underlying member method code with example usage: obj._to_single_notesequence(samples, controls) and returns: seq