code: def _time_stretcher(self, stretch_factor):
          
          start = self._i2
          end = min(self._i2 + self._N, len(self._sy) - (self._N + self._H))
  
          if start >= end:
              raise StopIteration
  
          # The not so clean code below basically implements a phase vocoder
          out = numpy.zeros(self._N, dtype=numpy.complex)
  
          while self._i2 < end:
              if self._i1 + self._N + self._H > len(self.y):
                  raise StopIteration
  
              a, b = self._i1, self._i1 + self._N
              S1 = numpy.fft.fft(self._win * self.y[a: b])
              S2 = numpy.fft.fft(self._win * self.y[a + self._H: b + self._H])
  
              self._phi += (numpy.angle(S2) - numpy.angle(S1))
              self._phi = self._phi - 2.0 * numpy.pi * numpy.round(self._phi / (2.0 * numpy.pi))
  
              out.real, out.imag = numpy.cos(self._phi), numpy.sin(self._phi)
  
              self._sy[self._i2: self._i2 + self._N] += self._win * numpy.fft.ifft(numpy.abs(S2) * out).real
  
              self._i1 += int(self._H * self.stretch_factor)
              self._i2 += self._H
  
          chunk = self._sy[start:end]
  
          if stretch_factor == 1.0:
              chunk = self.y[start:end]
  
          return chunk
docs: Real time time-scale without pitch modification.
  
              :param int i: index of the beginning of the chunk to stretch
              :param float stretch_factor: audio scale factor (if > 1 speed up the sound else slow it down)
  
              .. warning:: This method needs to store the phase computed from the previous chunk. Thus, it can only be called chunk by chunk.