class_docstr: Helper object for computing f0 encoder metrics.
class_docstr_tok: ["Helper","object","for","computing","f0","encoder","metrics","."]
docstr: Update metrics based on a batch of audio.
  
  Args:
    batch: Dictionary of input features.
    f0_hz_predict: Batch of encoded f0, same as input f0 if no f0 encoder.
docstr_tok: ["Update","metrics","based","on","a","batch","of","audio",".","Args",":","batch",":","Dictionary","of","input","features",".","f0_hz_predict",":","Batch","of","encoded","f0",",","same","as","input","f0","if","no","f0","encoder","."]
code: def update_state(self, batch, f0_hz_predict):
      """Update metrics based on a batch of audio.
  
      Args:
        batch: Dictionary of input features.
        f0_hz_predict: Batch of encoded f0, same as input f0 if no f0 encoder.
      """
      batch_size = int(f0_hz_predict.shape[0])
      # Match number of timesteps.
      if f0_hz_predict.shape[1] != batch["f0_hz"].shape[1]:
          # f0_hz_predict = ddsp.core.resample(f0_hz_predict,
          #                                    batch['f0_hz'].shape[1]).numpy()
          batch["f0_hz"] = ddsp.core.resample(
              batch["f0_hz"], f0_hz_predict.shape[1]
          ).numpy()
          batch["f0_confidence"] = ddsp.core.resample(
              batch["f0_confidence"], f0_hz_predict.shape[1]
          ).numpy()
  
      # Compute metrics per sample. No batch operations possible.
      for i in range(batch_size):
          f0_hz_gt = batch["f0_hz"][i]
          f0_conf_gt = batch["f0_confidence"][i]
  
          if not is_outlier(f0_conf_gt):
              # Gound truth f0 was reliable, proceed with metrics
              # Compute distance between original f0_hz labels and f0 encoder values.
              # Resample if f0 encoder has different number of time steps.
              # TODO(hanoih): compare f0_hz against frame_rate * len_sec
              f0_hz = f0_hz_predict[i]
              f0_dist = f0_dist_conf_thresh(f0_hz_gt, f0_hz, f0_conf_gt)
              self.metrics["f0_dist"].update_state(f0_dist)
  
              f0_hz_gt = np.squeeze(f0_hz_gt)
              f0_hz = np.squeeze(f0_hz)
              voiced_gt = mir_eval.melody.freq_to_voicing(f0_hz_gt)[1]
              cents_gt = mir_eval.melody.hz2cents(f0_hz_gt)
              cents_est = mir_eval.melody.hz2cents(f0_hz)
              rca = mir_eval.melody.raw_chroma_accuracy(
                  voiced_gt,
                  cents_gt,
                  voiced_gt,
                  cents_est,
                  cent_tolerance=self._rpa_tolerance,
              )
              rpa = mir_eval.melody.raw_pitch_accuracy(
                  voiced_gt,
                  cents_gt,
                  voiced_gt,
                  cents_est,
                  cent_tolerance=self._rpa_tolerance,
              )
              self.metrics["raw_chroma_accuracy"].update_state(rca)
              self.metrics["raw_pitch_accuracy"].update_state(rpa)
              log_str = (
                  f"{self._name} | sample {i} | f0_dist(midi): {f0_dist:.3f} "
                  f"raw_chroma_accuracy: {rca:.3f} "
                  f"raw_pitch_accuracy: {rpa:.3f}"
              )
              logging.info(log_str)
  
imports: import dataclasses
  from absl import logging
  import ddsp
  import librosa
  import mir_eval
  import note_seq
  from note_seq import sequences_lib
  import numpy
  import tensorflow.compat.v2
label_desc: Use image node_id 3 for calling the F0Metrics obj's underlying member method code with example usage: obj.update_state(batch, f0_hz_predict) without return types