class_docstr: A MidiAutoencoder that has additional z encoders.
  
  This is set up similar to the base MidiAutoencoder, except that there are
  many more places to learn encoding "z" variables to enable better
  reconstruction or better learnable representations.
docstr: Run the network to get a prediction and optionally get losses.
docstr_tok: ["Run","the","network","to","get","a","prediction","and","optionally","get","losses","."]
code: def call(self, features, training=True):
      """Run the network to get a prediction and optionally get losses."""
  
      # --- Set up
      features = self.preprocess(features)
  
      # --- Synthcoder Branch
      z_synth = self.z_synth_encode(features)
      synth_audio, synth_params = self.synthcoder_branch(
          features, training, z_synth
      )
      amps, hd, noise = self.extract_harm_controls(synth_params)
  
      # Add to features for z_note_encoder.
      features["amps_scaled"] = amps
      features["hd_scaled"] = hd
      features["noise_scaled"] = noise
  
      # --- MIDI Encoding
      z_pitch, z_vel = None, None
      if self.midi_encoder is not None:
          # Encode with network.
          f0_midi = features["f0_midi"]
          f0_loss_weights = tf.ones_like(f0_midi)
          z_pitch, q_pitch, _, q_vel = self.encode_to_midi(
              f0_midi, amps, hd, noise
          )
  
      else:
          # Skip encoder, use ground truth labels from MIDI.
          q_pitch, q_vel, f0_loss_weights = self.get_gt_midi(features)
  
      # --- MIDI Decoding
      if self.midi_decoder is None:
          f0_midi_pred = (
              q_pitch  # HACK(jesseengel): Dummy values for summaries.
          )
          midi_synth_params = synth_params
          z_global, z_notes = None, None
      else:
          # --- Z Global Encoding
          z_global = self.z_global_encode(features)
  
          # --- Z Note Encoding
          z_notes = self.z_note_encode(features, q_pitch)
  
          # Apply priors.
          if self.z_global_prior is not None:
              self._update_losses_dict(self.z_global_prior, z_global)
              z_global = self.z_global_prior(
                  z_global
              )  # Sample posterior.
  
          if self.z_note_prior is not None:
              self._update_losses_dict(self.z_note_prior, z_notes)
              z_notes = self.z_note_prior(z_notes)  # Sample posterior.
  
          # Pack the Z together.
          if z_notes is None:
              z_midi_decoder = z_global
          else:
              z_midi_decoder = tf.concat([z_global, z_notes], axis=-1)
  
          # --- Precondition
          if self.z_preconditioning_stack is not None:
              z_midi_decoder = self.z_preconditioning_stack(
                  z_midi_decoder
              )
  
          # --- MIDI Decoding
          pg_in = self.midi_decoder(q_pitch, q_vel, z_midi_decoder)
          f0_midi_pred = pg_in["f0_midi"]
          midi_synth_params = self.processor_group.get_controls(pg_in)
          amps_pred, hd_pred, noise_pred = self.extract_harm_controls(
              midi_synth_params
          )
  
          # --- MIDI Audio Losses
          midi_audio = self.processor_group.get_signal(
              midi_synth_params
          )
          if training:
              # --- Pitch Decoder Losses
              self.add_closeness_loss(
                  self.qpitch_f0rec_loss, f0_midi_pred, q_pitch
              )
  
              # --- Pitch Encoder Losses
              self.add_zpitch_losses(z_pitch, q_pitch, f0_midi_pred)
  
      # --- Finalize and return
      outputs = {
          "synth_params": synth_params,
          "synth_audio": synth_audio,
          "midi_synth_params": midi_synth_params,
          "midi_audio": midi_audio,
          "q_pitch": q_pitch,
          "q_vel": q_vel,
          "z_pitch": z_pitch,
          "z_vel": z_vel,
          "z_global": z_global,
          "z_notes": z_notes,
          "pianoroll": self.midi_to_pianoroll(q_pitch, q_vel),
          "f0_midi_pred": f0_midi_pred,
          "f0_hz_pred": ddsp.core.midi_to_hz(f0_midi_pred),
          "amps": amps,
          "hd": hd,
          "noise": noise,
          "amps_pred": amps_pred,
          "hd_pred": hd_pred,
          "noise_pred": noise_pred,
          "f0_loss_weights": f0_loss_weights,
          f"{self.db_key}_pred": features["db"],
      }
      # Remove unused z vectors (initialized as None)
      outputs = {k: v for k, v in outputs.items() if v is not None}
  
      outputs.update(
          {k: v for k, v in features.items() if k not in outputs}
      )
      outputs.update(synth_params)
  
      if training:
          loss_outs = self.reconstruction_losses(outputs)
          self._losses_dict.update(loss_outs)
  
      return outputs
  
imports: import ddsp
  from ddsp.training import nn
  from ddsp.training import preprocessing
  from ddsp.training.models.model import Model
  import tensorflow
label_desc: Use image node_id 5 for calling the ZMidiAutoencoder obj's underlying member method code with example usage: obj.call(features, training) and returns: outputs