Created
June 16, 2017 21:46
-
-
Save cversek/1e355d961ba41535ff8296920586d9a3 to your computer and use it in GitHub Desktop.
Testing a pitch shifting Algo. from http://zulko.github.io/blog/2014/03/29/soundstretching-and-pitch-shifting-in-python/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It sort of works, but the sounds are crusty and the envelopes are wonky!