def spectrum(x, samprate):
"""
compute amplitude spectrum
Usage:
freq, ampspec = spectrum(sig, samprate)
"""
y = scipy.fft(x, nextpow2(len(x)))
#y = scipy.fft(x)
y_tmp = np.abs(y)
y_ampspec = y_tmp[:len(y)//2+1]
y_ampspec[1:(len(y)//2)] *= 2.0
freq = scipy.linspace(start=0, stop=samprate/2, num=len(y)/2+1)
return(freq, y_ampspec / len(x))
def plot_spectrum(x, samprate, xlim=None, ylim=None):
f, ampspec = spectrum(x, samprate)
plt.plot(f, ampspec)
plt.xlabel("Frequency (Hz)")
plt.ylabel("Amplitude Spectrum")
plt.xlim(xlim)
plt.ylim(ylim)
plt.grid()
plt.show()
def plot_magnitude(x, samprate, xlim=(20, 20000), ylim=(-100, 0)):
f, spec = spectrum(x, samprate)
mag = 10 * np.log10(spec ** 2)
mag = mag - max(mag)
plt.semilogx(f, mag)
plt.xlabel("Frequency (Hz)")
plt.ylabel("Power Spectrum (dB)")
plt.xlim(xlim)
plt.ylim(ylim)
plt.grid()
plt.show()
def spectral_centroid(x, samprate):
freq, spec = spectrum(x, samprate)
# remove DC and nyquist
powspec = spec[1 : -1] ** 2
f = freq[1 : -1]
# compute spectral centroid (of log-frequency and power spectrum)
if sum(powspec) != 0.0:
speccent = 2**(sum(np.log2(f) * powspec) / sum(powspec))
else:
speccent = None
return(speccent)
def spectral_centroid_linlin(x, samprate):
freq, spec = spectrum(x, samprate)
# remove DC and nyquist
ampspec = spec[1 : -1]
f = freq[1 : -1]
# compute spectral centroid (of linear-frequency and amplitude spectrum)
if sum(ampspec) != 0.0:
speccent = sum(f * ampspec) / sum(ampspec)
else:
speccent = None
return(speccent)
def spectral_centroid_moving(x, samprate, window_size=8192, hop_size=1024):
"""
Calculate spectral centroid of a signal as in moving average.
Usage:
x, samprate = soundfile.read("audio.wav")
sc, t = spectral_centroid_moving(x, samprate,
window_size=8192, hop_size=1024)
matplotlib.pyplot.plot(t/samprate, sc)
"""
num_frames = (len(x) + window_size-1) // hop_size
xx = np.concatenate((x, np.zeros(2 * window_size)))
spec_cents = np.zeros(num_frames)
for n in range(num_frames):
xxx = xx[hop_size*n : hop_size*n+window_size-1]
spec_cents[n] = spectral_centroid(xxx, samprate)
t = np.arange(num_frames) * hop_size
return(spec_cents, t)
def hilbert(x):
"""
Hilbert Transform
"""
# add zero at the end if signal length is odd
if (len(x) % 2 == 1):
flag = True
x = np.concatenate((x, 0))
else:
flag = False
# compute analytical signal
xx = scipy.fft(x)
hh = [1] + [2]*(len(xx)//2-1) + [1] + [0]*(len(xx)//2-1)
yy = xx * hh
y = scipy.ifft(yy).real
# trim trailing zero to match the original signal length
if (flag == True):
return(y[:-1])
else:
return(y)
def envelope(x):
"""
Signal Envelope using Hilbert Transform
"""
return(np.abs(hilbert(x)))
def reverb_time_sabine(width, depth, height, alpha):
"""
estimate reverberation time using Sabine's equation
"""
S = (width * height + width * depth + depth * height) * 2.0
V = width * depth * height
return((0.161 * V) / (alpha * S))
def reverb_envelope(ir):
"""
Schroeder's reverberation envelope
"""
return(np.flipud(np.cumsum(np.flipud(ir ** 2))))
def reverb_time(ir, samprate, T=[-5,-35,-60]):
"""
estimate reverberation time from impulse response
"""
# compute reverberation envelope in dB
t = np.linspace(0, len(ir) / samprate, len(ir))
revenv = reverb_envelope(ir)
irdb = 10 * scipy.log10(revenv)
irdb = irdb - max(irdb)
# linear fit between -5dB and -35dB and find the time of being -60dB
ind = [sum(irdb >= T[0]), sum(irdb >= T[1])]
p = np.polyfit(irdb[ind[0]:ind[1]], t[ind[0]:ind[1]], 1)
rt = T[2] * p[0]
# return reverb time
return(rt)
def ambisonics_AtoB(A, B, C, D):
"""
ambisonics A to B format conversion
"""
W = ( A + B + C + D) / 2
X = (-A + B + C - D) / 2 # front-back
Y = ( A + B - C - D) / 2 # left-right
Z = (-A + B - C + D) / 2 # up-down
return(W, X, Y, Z)
##### SIGNAL PROCESSING #######################################################
def normalize(x):
"""
Signal normalize to [-1, +1]
"""
return(x / np.max(np.abs(x)))
def fadein(x, ms, samprate):
"""
apply raised-cosine fade-in at the beginning of a signal
"""
winsize = round(ms / 1000 * samprate)
y = x
if winsize != 0:
t = np.arange(winsize) / winsize
w = (np.cos((t+1) * math.pi) + 1) / 2
y[:winsize] *= w
return(y)
def fadeout(x, ms, samprate):
"""
apply raised-cosine fade-out at the end of a signal
"""
winsize = round(ms / 1000 * samprate)
y = x
if winsize != 0:
t = np.arange(winsize) / winsize
w = (np.cos(t * math.pi) + 1) / 2
y[-winsize:] *= w
return(y)
def freeze(x):
"""
Freezing audio by randomizing phase component.
Usage:
filename = 'in.wav'
x, samprate = soundfile.read(filename)
sinfo = soundfile.info(filename)
x2 = freeze(x)
soundfile.write("out.wav", x2, sinfo.samplerate, sinfo.subtype)
"""
# FFT
y = scipy.fft(x)
mag = scipy.absolute(y)
phase = scipy.angle(y)
# phase randomization
p2 = phase[1:len(phase)//2]
np.random.seed(0)
perm = np.random.permutation(len(p2))
p2p = p2[perm]
phaseR = scipy.r_[phase[0], p2p, phase[len(phase)//2], -p2p[::-1]]
# IFFT
y2 = mag * scipy.exp(1j * phaseR)
x2 = scipy.real(scipy.ifft(y2))
return(x2)