예제 #1
0
def test_tap_activation():
    a = Ring(16)
    t = a.create_tap()
    t.deactivate()
    assert t.name in a.inactive_taps
    assert t.name not in a.active_taps
    a.append(np.arange(15))
    a.append([99])
    t.activate()
    assert t.name in a.active_taps
    assert t.name not in a.inactive_taps
    s = t.get_samples(1)
    assert s[0] == 99
class Stretcher(object):
    """ Given a tap pointer in a Ring buffer, generate the stretched audio
    """
    def __init__(self, tap):
        """
        tap (RingPosition): the starting point where our stretch begins
        """
        self.__in_tap = tap
        self.__buffer = Ring(2**16)
        self.__fading_out = False

    def step(self, windowsize, *args, **kwargs):
        results = self.stretch(windowsize, *args, **kwargs)

        return results

    def stretch(self, windowsize, stretch_amount=4):
        """
        Run paulstretch once from the current location of the tap point
        """
        sw = get_strech(windowsize)
        audio_in = self.__in_tap.get_samples(sw.size)

        # Magnitude spectrum of windowed samples
        mX = np.abs(fft.rfft(audio_in * sw.window))
        # Randomise the phases for each bin between 0 and 2pi
        pX = np.random.uniform(0, 2 * np.pi, len(mX)) * 1j
        # use e^x to Convert our array of random values from 0 to 2pi to an
        # array of cartesian style real+imag vales distributed around the unit
        # circle. Then multiply with magnitude spectrum to rotate the magnitude
        # spectrum around the circle.
        freq = mX * np.exp(pX)
        # Get the audio samples with randomized phase. When we randomized the
        # phase, we changed the waveform so it no longer starts and ends at
        # zero. We will need to apply another window -- however do not know the
        # size of the next window, so instead of applying the full window to
        # our audio samples, we will close the window from the previous step,
        # and open the window on our current samples.
        audio_phased = fft.irfft(freq)
        # counter the tremelo for both halves of the audio snippet
        audio_phased *= sw.double_hinv_buf
        # Open the window to the newly generated audio sample
        audio_phased *= sw.open_window

        # Next we will do the overlap/add with the tail of our local buffer.
        # First, retrive the the samples, apply the closing window
        previous = self.__buffer.recent(sw.half) * sw.close_window

        # overlap add this the newly generated audio with the closing tail of
        # the previous signal
        audio_phased[:sw.half] += previous
        # replace the tail end of the output buffer with the new signal
        self.__buffer.rewind(sw.half)
        self.__buffer.append(audio_phased)
        # The last <sw.half> samples are not valid (the window has not yet
        # been closed). These will be closed the next time we call step.

        # Advance our input tap
        self.__in_tap.advance(sw.hopsize(stretch_amount))

        # append the audio output to our output buffer
        self.__buffer.append(audio_phased)

        return audio_phased[:sw.half]

    def fade_out(self):
        """Begin fading the stretch with each .step() .step should deactivate
    
        Caution: fade_out is currently implemeted in StretchGroup. See:
        https://github.com/CharlesHolbrow/realtime-fft-experiment/issues/4
        """
        self.__fading_out = True

    def activate(self):
        self.__fading_out = False
        self.tap.activate()

    def deactivate(self):
        self.clear()
        self.tap.deactivate()

    @property
    def fading_out(self):
        return self.__fading_out

    @fading_out.setter
    def fading_out(self, val):
        self.__fading_out = bool(val)

    @property
    def tap(self):
        return self.__in_tap

    def clear(self):
        self.__buffer.raw.fill(0.)
예제 #3
0
def test():
    a = Ring(4)
    a.append([1, 2])
    assert np.all(a.raw == [1, 2, 0, 0])
    a.append([3, 4])
    assert np.all(a.raw == [1, 2, 3, 4])
    a.append([5])
    assert np.all(a.raw == [5, 2, 3, 4])
    a.append([6, 7])
    a.append([8, 9])
    assert np.all(a.raw == [9, 6, 7, 8])
    a.append([10, 11])
    assert np.all(a.raw == [9, 10, 11, 8])

    # test getitem
    a = Ring(4)
    a.append([0, 1, 2, 3])
    assert a[0] == 3
    assert a[-1] == 2
    a.append([4])
    assert (np.all(a.raw == [4, 1, 2, 3]))
    assert (a[0] == 4)
    assert (a[-1] == 3)
    assert (np.all(a.recent(0) == []))
    assert (np.all(a.recent(1) == [4]))
    a.append([5])
    assert (np.all(a.recent(2) == [4, 5]))
    # test wrap around
    assert (np.all(a.recent(3) == [3, 4, 5]))

    # test RingPosition
    a = Ring(8)
    p = a.create_tap()

    assert p.valid_buffer_length == 1
    a.append(np.arange(4))
    assert p.valid_buffer_length == 5
    p.advance(1)
    assert p.valid_buffer_length == 4
    assert p.index == 0

    assert np.all(p.get_samples(4) == [0, 1, 2, 3])
    p.advance(2)
    assert np.all(p.get_samples(2) == [2, 3])
    a.append([4, 5, 6, 7, 8])

    p.advance(4)

    assert np.all(p.get_samples(2) == [6, 7])
    # test wraping
    assert np.all(p.get_samples(3) == [6, 7, 8])
    p.advance(2)
    assert (p.valid)
    assert (a.raw[p.index] == 8)

    # Ensure that we throw when breaking a ring pointer
    a = Ring(8)
    a.append(np.arange(8))
    p = a.create_tap()
    assert (p.get_samples(1)[0] == 7)
    # pointing to the last item in the sample
    a.append(np.arange(7))
    try:
        a.append([99])
    except RingPointerWarning as e:
        pass
    assert p.valid is False

    a = Ring(8)
    p = a.create_tap()
    try:
        p.advance(2)
    except RingPointerWarning as e:
        pass
    assert p.valid is False
    return a, p

    # test rewinding pointer
    a = Ring(5)
    a.append(np.arange(2))
    assert a.pointer == 2
    a.rewind(1)
    assert a.p == 1
    a.rewind(3)
    assert a.p == 3