class_docstr: Definition of sine generator
  SineGen(samp_rate, harmonic_num = 0,
          sine_amp = 0.1, noise_std = 0.003,
          voiced_threshold = 0,
          flag_for_pulse=False)
  
  sample_rate: sampling rate in Hz
  harmonic_num: number of harmonic overtones (default 0)
  sine_amp: amplitude of sine-wavefrom (default 0.1)
  noise_std: std of Gaussian noise (default 0.003)
  voiced_thoreshold: F0 threshold for U/V classification (default 0)
  flag_for_pulse: this SinGen is used inside PulseGen (default False)
  
  Note: when flag_for_pulse is True, the first time step of a voiced
      segment is always sin(np.pi) or cos(0)
docstr: f0_values: (batchsize, length, dim)
  where dim indicates fundamental tone and overtones
docstr_tok: ["f0_values",":","(","batchsize",",","length",",","dim",")","where","dim","indicates","fundamental","tone","and","overtones"]
code: def _f02sine(self, f0_values):
      """f0_values: (batchsize, length, dim)
      where dim indicates fundamental tone and overtones
      """
      # convert to F0 in rad. The interger part n can be ignored
      # because 2 * np.pi * n doesn't affect phase
      rad_values = (f0_values / self.sampling_rate) % 1
  
      # initial phase noise (no noise for fundamental component)
      rand_ini = torch.rand(
          f0_values.shape[0],
          f0_values.shape[2],
          device=f0_values.device,
      )
      rand_ini[:, 0] = 0
      rad_values[:, 0, :] = rad_values[:, 0, :] + rand_ini
  
      # instantanouse phase sine[t] = sin(2*pi \sum_i=1 ^{t} rad)
      if not self.flag_for_pulse:
          # for normal case
  
          # To prevent torch.cumsum numerical overflow,
          # it is necessary to add -1 whenever \sum_k=1^n rad_value_k > 1.
          # Buffer tmp_over_one_idx indicates the time step to add -1.
          # This will not change F0 of sine because (x-1) * 2*pi = x *2*pi
          tmp_over_one = torch.cumsum(rad_values, 1) % 1
          tmp_over_one_idx = (
              tmp_over_one[:, 1:, :] - tmp_over_one[:, :-1, :]
          ) < 0
          cumsum_shift = torch.zeros_like(rad_values)
          cumsum_shift[:, 1:, :] = tmp_over_one_idx * -1.0
  
          sines = torch.sin(
              torch.cumsum(rad_values + cumsum_shift, dim=1) * 2 * np.pi
          )
      else:
          # If necessary, make sure that the first time step of every
          # voiced segments is sin(pi) or cos(0)
          # This is used for pulse-train generation
  
          # identify the last time step in unvoiced segments
          uv = self._f02uv(f0_values)
          uv_1 = torch.roll(uv, shifts=-1, dims=1)
          uv_1[:, -1, :] = 1
          u_loc = (uv < 1) * (uv_1 > 0)
  
          # get the instantanouse phase
          tmp_cumsum = torch.cumsum(rad_values, dim=1)
          # different batch needs to be processed differently
          for idx in range(f0_values.shape[0]):
              temp_sum = tmp_cumsum[idx, u_loc[idx, :, 0], :]
              temp_sum[1:, :] = temp_sum[1:, :] - temp_sum[0:-1, :]
              # stores the accumulation of i.phase within
              # each voiced segments
              tmp_cumsum[idx, :, :] = 0
              tmp_cumsum[idx, u_loc[idx, :, 0], :] = temp_sum
  
          # rad_values - tmp_cumsum: remove the accumulation of i.phase
          # within the previous voiced segment.
          i_phase = torch.cumsum(rad_values - tmp_cumsum, dim=1)
  
          # get the sines
          sines = torch.cos(i_phase * 2 * np.pi)
      return sines
  
imports: import numpy
  import torch
label_desc: Use image node_id 3 for calling the SineGen obj's underlying member method code with example usage: obj._f02sine(f0_values) and returns: sines