code: def generate(self):
      sample_n = 0
  
      # in samples
      cycle_length = self.sample_rate / float(self.freq)
      midpoint = cycle_length * self.duty_cycle
      ascend_length = midpoint
      descend_length = cycle_length - ascend_length
  
      while True:
          cycle_position = sample_n % cycle_length
          if cycle_position < midpoint:
              yield (2 * cycle_position / ascend_length) - 1.0
          else:
              yield 1.0 - (
                  2 * (cycle_position - midpoint) / descend_length
              )
          sample_n += 1
  
imports: import math
  import array
  import itertools
  import random
  from .audio_segment import AudioSegment
  from .utils import db_to_float, get_frame_width, get_array_type, get_min_max_value
label_desc: Use image node_id 2 for calling the Sawtooth obj's underlying member method code with example usage: obj.generate() without return types