I have a sound file, which I'll call sndfile.wav.
So far I have determined the number of samples, sampling rating, and the length in seconds.
[f,Fs] = wavread('mike.wav');
N = length(f);
slength = N/Fs;
Given that f is the vector containing the samples from the sound file, Fs is the sampling rate, N is the number of samples, and slength is the length of the sound file in seconds, how can I plot the sound signal with respect to time in seconds.
Make a time vector and then plot it versus f.
t = linspace(0, N/Fs, N)
plot(t, f)
moorepants answer is good for plotting the signal. If you want to do more to the signal after viewing take a look at the "Simple Audio Editor" available at file exchange. http://www.mathworks.com/matlabcentral/fileexchange/19873-simple-audio-editor
It can read an audio file directly and display it. You can also play the signal and do cut,copy and paste with the audio signal.
Related
I'm working on Matlab, I want to perform FFT on a wav file I previously recorded on Matlab as well.
fs = 44100; % Hz
t = 0:1/fs:1; % seconds
f = 600; % Hz
y = sin(2.*pi.*f.*t);
audiowrite('600freq.wav',y,fs)
This is the way I'm recording in the wav file.
Now to the reading and FFT part:
[y,Fs] = audioread('600freq.wav');
sound(y)
plot(fft(y))
This is the plot of the FFT I get:
Maybe I'm missing something about the FFT, but I expected two vertical lollipops.
Another thing I noticed that's wrong, is when I play the sound after reading it form the file it's longer and the pitch is significantly lower.
My guess is a sampling rate problem, but I really have no idea of what to do about it.
Thanks for any help in advance.
That's because you're not plotting the magnitude. What you are plotting are the coefficients, but these are complex valued. Because of that, the horizontal axis is the real component and the vertical axis is the imaginary component. Also, when you use sound by itself, the default sampling frequency is 8 kHz (8192 Hz to be exact) which explains why your sound is of a lower pitch. You need to use the sampling frequency as a second argument into sound, and that's given to you by the second output of audioread.
So, try placing abs after the fft call and also use Fs into sound:
[y,Fs] = audioread('600freq.wav');
sound(y, Fs);
plot(abs(fft(y)))
Also, the above code doesn't plot the horizontal axis properly. If you want to do that, make sure you fftshift your spectra after you take the Fourier transform, then label your axis properly. If you want to determine what each horizontal value is in terms of frequency, this awesome post by Paul R does the trick: How do I obtain the frequencies of each value in an FFT?
Basically, each horizontal value in your FFT is such that:
F = i * Fs / N
i is the bin number, Fs is the sampling frequency and N is the number of points you're using for the FFT. F is the interpreted frequency of the component you're looking at.
By default, fft assumes that N is the total number of points in your array. For the one-sided FFT, i goes from 0, 1, 2, up to floor((N-1)/2) due to the Nyquist sampling theorem.
Because what you're actually doing in the code you tried to write is displaying both sides of the spectrum, that's why it's nice to centre the spectrum so that the DC frequency is located in the middle and the left side is the negative spectra and the right side is the positive spectra.
We can incorporate that into your code here:
[y,Fs] = audioread('600freq.wav');
sound(y, Fs);
F = fftshift(abs(fft(y)));
f = linspace(-Fs/2, Fs/2, numel(y)+1);
f(end) = [];
plot(f, F);
The horizontal axis now reflects the correct frequency of each component as well as the vertical axis reflecting the magnitude of each component.
By running your audio generation code which generates a sine tone at 600 Hz, and then the above code to plot the spectra, I get this:
Note that I inserted a tool tip right at the positive side of the spectra... and it's about 600 Hz!
Here is the context of the problem: I have a DTMF signal in wav format, I have to identify the number sequence it has encoded. I must do so using fast fourier transform in Matlab, implying that I read the wav file using wavread and to identify each number that is seperated by 40ms silence or more.
Here is my code so far:
[signal, fs] = wavread( 'C:\Temp\file.wav' ); % here, fs = 8000Hz
N = 512;
T = 1/fs;
L = length( signal )
samples = fs / 1000 * 40
windows = floor(L / samples)
t = (1:L)/fs;
figure(1), plot(t, signal);
Here is what the figure 1 looks like, that is the signal read from the wav:
How can I effectively split the signal into pieces so that I can then do an FFT on each of the 10 pieces seperately to decode the corresponding numbers?
I would recommend the following approach:
Find the envelope of the signal in the time domain (see Hilbert transform).
Smooth the envelope a bit.
Take the diff and find peaks to get the onsets of the tones.
Use the onsets to pick frames and find the spectrum using fft.
Find the index of the max in each of the spectrums and convert them to a frequency.
The tricky part in this is to get a robust onset detector in point 3. The peaks in the difference you pick, has to be of a certain size in order to qualify as on onset. If your tones are of varying strength this might pose a problem, but from your image of the time signal it doesn't seem like a problem.
Regards
This worked for me:
windowSize = 256;
nbWindows = floor(L / windowSize);
for i=1:nbWindows
coeffs = fft(signal((i-1)*windowSize+1:i*windowSize));
plot(abs(coeffs(1:N)));
waitforbuttonpress
end;
This way it is possible to shift the window until the end of the input signal
I have some matlab code which produces frequency (in hertz) of a sound over 5 seconds. The code as it stands outputs 100 samples per second, and I want to play the 5 second block to see what this sounds like, but I'm having issues with sampling rate and sound / soundsc commands.
My frequency oscillates (data here ) and I'd be very grateful if someone could help me convert this data into some kind of real-time approximation of what it should sound like.
Something like this may be helpful
Fs=2000; %sample rate, Hz
t=0:1/Fs:5; %time vector
F=298+sin(2*pi*t); %put your own F here
S=sin(2*pi*F.*t); %here is the sound vector
%visual check
figure(1);
plot(t,S)
figure(2);
plot(t,F)
%listen
wavplay(S,Fs)
This is like FM modulation, but different. If you have an Fold vector with a different sample rate, you can convert it with the command
F=interp1(told,Fold,t); %told and Fold are F at a different sample rate
%check it
plot(told,Fold,t,F)
First, your sampling rate should be at least twice the maximum frequency according the Nyquist–Shannon sampling theorem.
Next, you need to generate a sinusoid:
Signal = sin(2*pi*Phi);
where Phi is the phase corresponding to the desired frequency pattern, which is simply an integral of the frequency (which you can do numerically or analytically).
Here is the context of the problem: I have a DTMF signal in wav format, I have to identify the number sequence it has encoded. I must do so using fast fourier transform in Matlab, implying that I read the wav file using wavread and to identify each number that is seperated by 40ms silence or more.
Here is my code so far:
[signal, fs] = wavread( 'C:\Temp\file.wav' ); % here, fs = 8000Hz
N = 512;
T = 1/fs;
L = length( signal )
samples = fs / 1000 * 40
windows = floor(L / samples)
t = (1:L)/fs;
figure(1), plot(t, signal);
Here is what the figure 1 looks like, that is the signal read from the wav:
How can I effectively split the signal into pieces so that I can then do an FFT on each of the 10 pieces seperately to decode the corresponding numbers?
I would recommend the following approach:
Find the envelope of the signal in the time domain (see Hilbert transform).
Smooth the envelope a bit.
Take the diff and find peaks to get the onsets of the tones.
Use the onsets to pick frames and find the spectrum using fft.
Find the index of the max in each of the spectrums and convert them to a frequency.
The tricky part in this is to get a robust onset detector in point 3. The peaks in the difference you pick, has to be of a certain size in order to qualify as on onset. If your tones are of varying strength this might pose a problem, but from your image of the time signal it doesn't seem like a problem.
Regards
This worked for me:
windowSize = 256;
nbWindows = floor(L / windowSize);
for i=1:nbWindows
coeffs = fft(signal((i-1)*windowSize+1:i*windowSize));
plot(abs(coeffs(1:N)));
waitforbuttonpress
end;
This way it is possible to shift the window until the end of the input signal
Question is as stated in the title.
After i decimate an audio signal that take every nth point out it in turns speeds up the audio clip at a factor of n. I want the decimated and original clips to have the same length in time.
Heres my code, analyzing and decimated piano .wav
[piano,fs]=wavread('piano.wav'); % loads piano
play=piano(:,1); % Renames the file as "play"
t = linspace(0,time,length(play)); % Time vector
x = play;
y = decimate(x,2);
stem(x(1:30)), axis([0 30 -2 2]) % Original signal
title('Original Signal')
figure
stem(y(1:30)) % Decimated signal
title('Decimated Signal')
%changes the sampling rate
fs1 = fs/2;
fs2 = fs/3;
fs3 = fs/4;
fs4 = fs*2;
fs5 = fs*3;
fs6 = fs*4;
wavwrite(y,fs,'PianoDecimation');
possible solutions: Double each of the remaining points since the new decimated clip is 2x shorter then the original.
I just want to be able to have a side by side comparison of the 2 clips.
here is the audio file: http://www.4shared.com/audio/11xvNmkd/piano.html
Although #sage's answer has a lot of good information, I think the answer to the question is as simple as changing your last line to:
wavplay(y,fs/2,'PianoDecimation')
You have removed half the samples in the file, so in order to play it back over the same time period as the original, you need to set the playback frequency to half as many samples per second.
Are you using wavplay, audioplayer, or something else to play the decimated signals? Are you explicitly specifying the sample frequencies?
The functions take the sample frequency as one of the parameters (the second parameter). You are decreasing the sample frequency as you decimate, so you need to update that parameter accordingly.
Also, when you are plotting the data, you should:
plot N times as many points on the original data (when decimating by N)
provide a corresponding x axis input - I recommend t = (1/Fs:1/Fs:maxT) where maxT is the maximum time you want to plot, which will address #1 if you use the updated Fs, which will result in larger time steps (and make sure to transpose t if it does not match your signal)
I have added an example that plays chirp and decimated chirp (this chirp is part of the standard MATLAB install). I amplified the decimated version. The tic and toc show that the elapsed time is equivalent (within variations in processor loading, etc.) - note that this also works for decim = 3, etc:
load chirp
inWav = y;
inFs = Fs;
decim = 2;
outWav = decimate(inWav,decim);
outFs = inFs/decim;
tic, wavplay(inWav,inFs),toc
pause(0.2)
tic,wavplay(outWav*decim^2,outFs),toc
The function 'decimate' really messes up the chirp sound (the sample rate of which is not very high frequency to begin with), but perhaps you are trying to show something like this...