1
votes

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.

1
I'd recommend making your code a little clearer if you want people to be able to help with it - as in, use variables with names that are self-explanatory. Also, it's not really clear what you're asking, either - maybe expand on what you're trying to do, what's not working, and what you've tried so far? I'd recommend looking at the guides on this site for how to ask a question that people will want to help answer.Random Davis
@RandomDavis I hope I have given a bit of more clear explanation now?JRD
Definitely. You might just want to clarify your question a little more - are you asking why there's noise in the output, and how you can get rid of it? If so, you should have that question be in the title and the body of the post, and not be an implied question.Random Davis
no! There is no modification of the magnitude.JRD

1 Answers

0
votes

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)