content: """
  Each generator will return float samples from -1.0 to 1.0, which can be 
  converted to actual audio with 8, 16, 24, or 32 bit depth using the
  SiganlGenerator.to_audio_segment() method (on any of it's subclasses).
  
  See Wikipedia's "waveform" page for info on some of the generators included 
  here: http://en.wikipedia.org/wiki/Waveform
  """
  
  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
  )
  
  
  
  class SignalGenerator(object):
      def __init__(self, sample_rate=44100, bit_depth=16):
          self.sample_rate = sample_rate
          self.bit_depth = bit_depth
  
      def to_audio_segment(self, duration=1000.0, volume=0.0):
          """
          Duration in milliseconds
              (default: 1 second)
          Volume in DB relative to maximum amplitude
              (default 0.0 dBFS, which is the maximum value)
          """
          minval, maxval = get_min_max_value(self.bit_depth)
          sample_width = get_frame_width(self.bit_depth)
          array_type = get_array_type(self.bit_depth)
  
          gain = db_to_float(volume)
          sample_count = int(self.sample_rate * (duration / 1000.0))
  
          sample_data = (int(val * maxval * gain) for val in self.generate())
          sample_data = itertools.islice(sample_data, 0, sample_count)
  
          data = array.array(array_type, sample_data)
          
          try:
              data = data.tobytes()
          except:
              data = data.tostring()
  
          return AudioSegment(data=data, metadata={
              "channels": 1,
              "sample_width": sample_width,
              "frame_rate": self.sample_rate,
              "frame_width": sample_width,
          })
  
      def generate(self):
          raise NotImplementedError("SignalGenerator subclasses must implement the generate() method, and *should not* call the superclass implementation.")
  
  
  
  class Sine(SignalGenerator):
      def __init__(self, freq, **kwargs):
          super(Sine, self).__init__(**kwargs)
          self.freq = freq
  
      def generate(self):
          sine_of = (self.freq * 2 * math.pi) / self.sample_rate
          sample_n = 0
          while True:
              yield math.sin(sine_of * sample_n)
              sample_n += 1
  
  
  
  class Pulse(SignalGenerator):
      def __init__(self, freq, duty_cycle=0.5, **kwargs):
          super(Pulse, self).__init__(**kwargs)
          self.freq = freq
          self.duty_cycle = duty_cycle
  
      def generate(self):
          sample_n = 0
  
          # in samples
          cycle_length = self.sample_rate / float(self.freq)
          pulse_length = cycle_length * self.duty_cycle
  
          while True:
              if (sample_n % cycle_length) < pulse_length:
                  yield 1.0
              else:
                  yield -1.0
              sample_n += 1
  
  
  
  class Square(Pulse):
      def __init__(self, freq, **kwargs):
          kwargs['duty_cycle'] = 0.5
          super(Square, self).__init__(freq, **kwargs)
  
  
  
  class Sawtooth(SignalGenerator):
      def __init__(self, freq, duty_cycle=1.0, **kwargs):
          super(Sawtooth, self).__init__(**kwargs)
          self.freq = freq
          self.duty_cycle = duty_cycle
  
      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
  
  
  
  class Triangle(Sawtooth):
      def __init__(self, freq, **kwargs):
          kwargs['duty_cycle'] = 0.5
          super(Triangle, self).__init__(freq, **kwargs)
  
  
  class WhiteNoise(SignalGenerator):
      def generate(self):
          while True:
              yield (random.random() * 2) - 1.0
  