MATLAB - Concatenating 2 wav audio files - matlab

I have 2 WAV audio files, which I load into MATLAB as follows:
[y1,Fs]=audioread('bat-time_x.wav');
y1_sample_rate = 2000;
[y2,Fs]=audioread('believe_me.wav');
y3 = [y1(1:y1_sample_rate:numel(y1)) y2]
sound(y3,Fs);
How can I concatenate these to play one after the other?

You want to audioread both files and check their sample rate. If they are the same, you can concatenate the files.
[y1,Fs1]=audioread('bat-time_x.wav');
[y2,Fs2]=audioread('believe_me.wav');
if Fs1 ~= Fs2
error('Need to resample');
end
y3 = [y1; y2];
sound(y3,Fs1);
To resample y2 to Fs1 use resample.
y2 = resample(y2,Fs1,Fs2);

Related

Remove noise from mp3 file, MATLAB

I have a mp3 file in the link below, where there is a man human voice and some humming noise in the background. I want the humming noise removed. Is there anyone who can tell me how to do it in MATLAB?
https://www.dropbox.com/s/h95y1oelbzvcgkc/allthatbass.mp3?dl=0
%% Read in the file
clearvars;
close all;
[f,fs] = audioread('allthatbass.mp3');
%% Play original file
pOrig = audioplayer(f,fs);
N = size(f,1);
%% Plot the spectrum
df = fs / N;
w = (-(N/2):(N/2)-1)*df;
y = fft(f(:,1), N) / N; % For normalizing, but not needed for our analysis
y2 = fftshift(y);
figure;
plot(w,abs(y2));
%% Design a bandpass filter that filters out between 700 to 12000 Hz
n = 7;
beginFreq = 700 / (fs/2);
endFreq = 12000 / (fs/2);
[b,a] = butter(n, [beginFreq, endFreq], 'bandpass');
%% Filter the signal
fOut = filter(b, a, f);
%% Construct audioplayer object and play
p = audioplayer(fOut, fs);
p.play;
I expect the humming noise removed, but the output sound like the original sound.
enter link description here
I have downloaded the original file you linked in your question and added the following line at the end:
audiowrite('filtered.wav', fOut, fs);
The resulting file 'filtered.wav' sounds very different to my ears (I used a headset to listen). If you open 'filtered.wav' for example in Audacity and take a look at the spectrum then it looks indeed different from the original (as expected, the frequencies below 700 Hz and above 12 kHz are removed).
Let's try to verify this in matlab. The following script reads both files and plots the dB value of both ffts. The lower plot represents the filtered signal and it is clearly visible that the bass frequencies are removed. The cut above 12 kHz is visible as well but it seems that these frequencies have already been attenuated in the original signal and the bandpass filter reinforces that.
%% Read in both files
clearvars;
close all;
[f,fs] = audioread('allthatbass.mp3');
[fflt, fsflt] = audioread('filtered.wav');
N = size(f,1);
%% Compute the ffts
df = fs / N;
n = N / 2; % plot only the second half of the spectrum
w = (0:(n)-1)*df;
y = fft(f(:,1), N) / N;
y2 = fftshift(y);
yflt = fft(fflt(:,1), N) / N;
y2flt = fftshift(yflt);
%% Plot the spectrum of both files (use the dB value, i.e. 10 * log(abs(x)) )
figure;
ax1 = subplot(2,1,1);
plot(w,10*log(abs(y2(n:end-1,1))));
ax2 = subplot(2,1,2);
plot(w, 10*log(abs(y2flt(n:end-1,1))));
linkaxes([ax1, ax2], 'y'); % link the axes (this makes it easier to visually compare the plots)
Try using a low pass filter in MATLAB. They're relatively easy to implement. You can find the documentation, along with examples, here.

Customize output of MATLAB's spectrogram function

I would like to know whether it is possible to customize the plot generated by MATLAB's spectrogram function in such a way that its x-axis does not represent the time but another physical signal y2captured simultaneously with the input signal y1 (used for computing the spectrogram). Therefore, it can be assumed that y1 and y2 have the same timestamps as x-axis as in the following example.
N = 1024;
n = 0:N-1;
w0 = 2*pi;
y1 = sin(w0*n);
y2 = n;
spectrogram(y1,'yaxis');
To control the scale of the axes arbitrarily, you could manually plot the spectrogram using imagesc. Here's how:
N = 1024;
n = 0:N-1;
w0 = 2*pi/10;
y1 = sin(w0*n);
y2 = n;
% compute spectrogram
[s,w,t]=spectrogram(y1,'yaxis');
% find values in y2 corresponding to spectrogram time-grid
t2 = interp1((1:N), y2, t);
% use imagesc to plot spectrogram
figure;
imagesc(t2,w/pi,10*log10(abs(s.^2)/length(w)/pi))
set(gca,'YDir','normal');
colorbar;
ylabel('Normalized Frequency (\times \pi rad/sample)');
% caxis([-160, 20]) % manually tweak the color range for best detail
Note that I have made two minor changes to your code:
Changed w0 from 2*pi to 2*pi/10, because the former results in y1 being all zeros.
Changed y2 to be something else than 1:N, which is spectrogram default.
I should also point out that the built-in spectrogram plot does let you control the axes scale in a variety of ways, including specifying the sample rate.

Changing frequency of a signal in Matlab

I have a difficulty in solving one Matlab problem. I want to read a wav file, Re-arrange the data so that the frequency is quadrupled and play the file. Here is my first attempt, am I doing the correct thing? Any help would be appreciated.
hfile = 'one.wav';
wavwrite(y, Fs, hfile)
clear y Fs
[y, Fs, nbits, readinfo] = wavread(hfile);
sound(y, Fs); % Play the sound & wait until it finishes
duration = numel(y) / Fs; % Calculate the duration
pause(duration + 2) % Wait that much + 2 seconds
FsQ=Fs*4;
sound(y,FsQ,nbits)

how to transform frequency domain into time domain

I had created a 3 three different frequency signal and filter out the signal i don't want. But when i using ifft in matlab, it shows a wrong graph.How to transform my frequency domain spectrum back into my 3 second time domain graph? Below my code is as below:
clc
clear all
Fs = 8192;
T = 1/Fs;
%create tones with different frequency
t=0:T:1;
t2=1:T:2;
t3=2:T:3;
y1 = sin(2*pi*220*t);
y2 = sin(2*pi*300*t2);
y3 = sin(2*pi*440*t3);
at=y1+y2+y3;
figure;
plot(t,y1,t2,y2,t3,y3),title('Tones with noise');
[b,a]=butter(2,[2*290/Fs,2*350/Fs],'stop');
e=filter(b,a,at);
et=(ifft(abs(e)));
figure,
plot(et)
As it is now, et is in the frequency domain, because of the fft. You don't need to fft. just plot(e) and you'll get the time domain filtered waveform. Yo can check the filter performance in the freq. domain by fft though, just
plot(abs(fftshift(fft(fftshift(e)))));
xlim([4000 5000])
Edit:
Your code as it is written on the question has the following bug: at has exactly 1 second of info in it (or 8192 elements). If you plot(at) you'll see the sum of frequencies alright, but they all happen in the same time. This is how to fix it:
clear all
Fs = 8192; % or multiply by 3 if needed
T = 1/Fs;
%create tones with different frequency
t=0:T:3;
y1 = sin(2*pi*220*t).*(t<1);
y2 = sin(2*pi*300*t).*(t<2 & t>=1);
y3 = sin(2*pi*440*t).*(t>=2);
at=y1+y2+y3;
[b,a]=butter(2,[2*290/Fs,2*350/Fs],'stop');
e=filter(b,a,at);
figure,
plot(t,e)
dt=t(2)-t(1);
N=length(at);
df=1/(N*dt); % the frequency resolution (df=1/max_T)
if mod(N,2)==0
f_vector= df*((1:N)-1-N/2); % frequency vector for EVEN length vectors: f =[-f_max,-f_max+df,...,0,...,f_max-df]
else
f_vector= df*((1:N)-0.5-N/2); % frequency vector for ODD length vectors f =[-f_max,-f_max+fw,...,0,...,f_max]
end
freq_vec=f_vector;
fft_vec=fftshift(fft(e));
plot(freq_vec,abs(fft_vec))
xlim([0 1000])

Plotting from different matlab files

I have four matlab codes and each of them generates a plot how can be able to combine all the plots into one plot to show the transition of each?
If you want to plot multiple lines on the same figure you can use hold on For example:
plot(x1,y1,'ok');
hold on
plot(x2,y2,'or');
If you are saying that they all form one single line then try concatenate your input vectors like this:
%Mock input
x1 = 0:9;
x2 = 10:19;
x3 - 20:29;
x4 = 30:39;
y1 = 2*x1 -20;
y2 = 2*x2 -20;
y3 = 2*x3 -20;
y4 = 2*x4 -20;
%Example of plotting concatenated vectors
plot( [x1;x2;x3;x4], [y1;y2;y3;y4]);
If you want all four to be on the same figure (say figure 1) then you can do this:
%% In PlotCode1.m
figure(1)
hold on
...%your plotting code
%% In PlotCode2.m
figure(1)
hold on
...%your plotting code
And if you run each of your PlotCode.m files without closing or clearing figure 1 then all the lines will show up on the same figure.
Alternately, you can turn each of your different plotting files into functions that take in the figure number as an input. For instance:
% In PlotCode1.m
function PlotCode1(num)
figure(num)
hold on
%Your plotting code
% In PlotCode2.m
function PlotCode2(num)
figure(num)
hold on
%Your plotting code
And now you can call each of these functions in one script:
fignum = 2;
PlotCode1(fignum)
PlotCode2(fignum)
And now everything will plot on figure 2.