The objective of my project is to synthesize the sound. What I want to do is to read a wave file and convert it to the amplitude spectrum. Since I am interested in the Magnitude and corresponding Frequencies. I also need to Change the Magnitude of certain frequencies(which i get) so that i can generate different sounds wav file back and play it. However, even without altering the magnitude the reconstructed signal is full of noise.
In simple words , read file --- FFT--- vary magnitude --- play it.
below is the Code
import scipy.io.wavfile
import sounfile as sf
data , rate = sf.read("bird_chirp.wav")
FFt_data =np.fft.rfft(data)
magnitude = np.abs(FFt_data)
phase = np.angle(FFt_data)
N= len(data) # Define the length of the wav file
timestamp = np.linspace(0.0, N*T, N)
T= 1.0/rate
n = data.size
#get the corresponding Frequencies
freq = np.fft.rfftfreq(n, d=1./rate)
# save it as a Dataframe
df = {"freq":freq, "mag":magnitude}
df =pd.DataFrame(df)
#Normalize the magnitude
a=df["mag"]
norm_a = a/a.max(axis=0)
df["mag"] = norm_a
# here I would play around with magnitude , make it high or low
#code to change magnitude
#Get back the new data to write in wav
y=0
for magnitudes ,frequencies in df.iterrows():
y+= magnitudes["mag"]*(np.sin(frequencies["freq"] *2.0*np.pi*timestamp))
#save it
sf.write(file="test.wav", data=y,samplerate=rate)
The code plays sound full of noise.
Below is a simple program that (a) reads a wave file, (b) Fourier transforms the data, (c) modifies the amplitudes at specific frequencies, (d) reverses the Fourier transform to convert the data back to time domain, and (e) saves the result to another wave file that you can play with any of the usual audio playback programs.
For purposes of demonstrating what you can do with the signal in a simple way, we attenuate the amplitude at 1 kHz,we add a continuous tone at 440 Hz and we add a Gaussian shaped pulse at 880.
Note that the injected signals are scaled to the maximum of other signals in the Fourier transform. Alternatively we could have chosen an amplitude and scaled it by the length of the data.
An important concept here is that the Fourier transform conserves power. Therefore a signal in the Fourier transform is scaled by its duration in time.
Here is the code to implement what you seemed to be looking for in the question:
import scipy.io.wavfile
import soundfile as sf
import numpy as np
# Input the wave file
data , rate = sf.read("bird_chirp.wav")
# Fourier transform
FFT_data = np.fft.rfft(data)
# Get the list of frequencies
freq = np.fft.rfftfreq(len(data), d=1./rate)
# Find the bin closest to 1kHz and attenuate
idx = (np.abs(freq - 1.E3)).argmin()
FFT_data[idx] *= 1./2
# Find the bin closest to 440 Hz and set a continuous tone
idx = (np.abs(freq - 440)).argmin()
FFT_data[idx] = max( abs( FFT_data) )
# Add a Gaussian pulse, width in frequency is inverse of its duration
FFT_data += max( abs( FFT_data) )/2. * np.exp( -((freq-880)/5.)**2 )
# Convert back to time domain
newdata = np.fft.irfft(FFT_data)
# And save it to a new wave file
sf.write(file="test.wav", data=newdata, samplerate=rate)