Skip to content

Instantly share code, notes, and snippets.

@cversek
Created June 16, 2017 21:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cversek/1e355d961ba41535ff8296920586d9a3 to your computer and use it in GitHub Desktop.
Save cversek/1e355d961ba41535ff8296920586d9a3 to your computer and use it in GitHub Desktop.
import numpy as np
def speedx(sound_array, factor):
""" Multiplies the sound's speed by some `factor` """
indices = np.round( np.arange(0, len(sound_array), factor) )
indices = indices[indices < len(sound_array)].astype(int)
return sound_array[ indices.astype(int) ]
def stretch(sound_array, f, window_size, h):
""" Stretches the sound by a factor `f` """
phase = np.zeros(window_size)
hanning_window = np.hanning(window_size)
result = np.zeros( len(sound_array) /f + window_size)
for i in np.arange(0, len(sound_array)-(window_size+h), h*f):
# two potentially overlapping subarrays
a1 = sound_array[i: i + window_size]
a2 = sound_array[i + h: i + window_size + h]
# resynchronize the second array on the first
s1 = np.fft.fft(hanning_window * a1)
s2 = np.fft.fft(hanning_window * a2)
phase = (phase + np.angle(s2/s1)) % 2*np.pi
a2_rephased = np.fft.ifft(np.abs(s2)*np.exp(1j*phase))
# add to result
i2 = int(i/f)
result[i2 : i2 + window_size] += hanning_window*a2_rephased.real
result = ((2**(16-4)) * result/result.max()) # normalize (16bit)
return result.astype('int16')
def pitchshift(snd_array, n, window_size=2**13, h=2**11):
""" Changes the pitch of a sound by ``n`` semitones. """
factor = 2**(1.0 * n / 12.0)
stretched = stretch(snd_array, 1.0/factor, window_size, h)
return speedx(stretched[window_size:], factor)
if __name__ == "__main__":
from matplotlib import pyplot as plt
SAMPLE_RATE = 44000
FREQ = 440.0
DURATION = 1
X = np.arange(DURATION*SAMPLE_RATE)
S = np.sin(2*np.pi*FREQ*X/SAMPLE_RATE)
fig = plt.figure()
ax = fig.add_subplot(111)
Ss = [S]
for n in range(1,13):
Sn = pitchshift(S,n)
Ss.append(Sn)
ax.plot(Sn)
Ss = np.hstack(Ss)
# Generate wave file
from scipy.io import wavfile
from scipy.interpolate import interp1d
wavfile.write("out.wav", SAMPLE_RATE, Ss.astype("float32"))
#show the graphs but allow program to continue
plt.show(block = False)
#wait for the user
input("press enter to exit")
plt.close('all')
@cversek
Copy link
Author

cversek commented Jun 16, 2017

It sort of works, but the sounds are crusty and the envelopes are wonky!
wonky_shifter

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment