Generate echo to an audio

I have to write a function called echo_gen that adds an echo effect to an audio recording. The function is to be called like this:
output = echo_gen(input, fs, delay, amp);
where input is a column vector with values between -1 and 1 representing a time series of digitized sound data. The input argument fs is the sampling rate. The sampling rate specifies how many samples we have in the data each second. For example, an audio CD uses 44,100 samples per second. The input argument delay represent the delay of the echo in seconds. That is, the echo should start after delay seconds have passed from the start of the audio signal. Finally, amp specifies the amplification of the echo which normally should be a value less than 1, since the echo is typically not as loud as the original signal.
The output of the function is a column vector containing the original sound with the echo superimposed. The output vector will be longer than the input vector if the delay is not zero (round to the nearest number of points needed to get the delay, as opposed to floor or ceil). A sound recording has values between -1 and 1, so if the echo causes some values to be outside of this range, you will need to normalize the entire vector, so that all values adhere to this requirement.
I got blocked on the following code:
function output = echo_gen(input, fs, delay, amp);
samples_echo = round(fs*delay);
input_sound = zeros(length(input)+fs,1);
input = (input_sound(1:length(input)))';
echo = zeros(length(input)+samples_echo,1);
echo_sound = echo(delay+(1:length(input*amp)));
output = input + echo_sound;
max_output = max(abs(output));
if max_output > 1;
for i = i:length (output);
output2 (i) = output2(i)/max_output;
end
output = output2
else
output = output
end

4 Comments

I have updated to the following:
function output = echo_gen(input, fs, delay, amp);
samples = (fs*delay);
samples_echo = round(samples);
echo = zeros(size(input));
echo(1:samples_echo) = input (1:samples_echo);
for ii = samples + 1:length(input);
echo(ii) = input (ii) + amp*input(ii-samples_echo);
end
output1 = echo
max_output = max(abs(output1));
if max_output > 1;
for i = 1:length (output1);
output1 (i) = output1(i)/max_output;
end
output = output1
else
output = echo
end
well explained, thanks@pepperlisbon
function out = blur(img,w)
% convert to double for doing calculations
imgD = double(img);
[row, col] = size(img);
out = zeros(row, col);
for ii = 1:row
for jj = 1:col
% Get the indices for a submatrix
r1 = ii-w;
r2 = ii+w;
c1 = jj-w;
c2 = jj+w;
% Test that indices are valid
% If not, set to min/max that is valid
if r1 < 1
r1 = 1;
end
if r2 > row
r2 = row;
end
if c1 < 1
c1 = 1;
end
if c2 > col
c2 = col;
end
% Get the submatrix and assign the mean to the output pixel
m = imgD(r1:r2, c1:c2);
out(ii,jj) = mean(m(:));
end
end
% convert back to uint8
out = uint8(out);
end
@omkar, wrong problem

Sign in to comment.

Answers (10)

dhouimir salem
dhouimir salem on 1 Jan 2020
Edited: Walter Roberson on 1 Jan 2020
valid code :
function output = echo_gen(in,fs,delay,gain)
samples = round(fs*delay) ;
ds = floor(samples);
signal = zeros(length(in)+ds,1);
signal(1:length(in))=in;
echo_signal =zeros(length(in)+ds,1);
echo_signal(ds+(1:length(in*gain)))=in*gain;
output= signal + echo_signal;
p= max(abs(output));
if p>1
output=output ./ p;
else
output = output;
end
end
another valid code :
function output = echo_gen(s, Fs, delay, amp)
% Find the time between points using Fs
dt = 1/Fs;
% Calculate the number of points for the given delay
N = round(delay/dt);
% Pad the original signal with zeros to make room for the echo
s1 = [s; zeros(N, 1)];
% Create an echo signal that starts with 0's
s2 = [zeros(N, 1); s.*amp];
% Add the echo to the original signal
output = s1 + s2;
% the abs of all values must be < 1. Rescale if necessary
if max(abs(output)) > 1
output = output./max(abs(output));
end
% Note: This only works with column vectors - can you make the
% function more robust so that it works with column or row vectors?
end
enjoy

10 Comments

I had to make guesses about the line breaks in your code in order to format it properly. Please check to be sure that I put the breaks into the proper place.
Why is there a need to floor samples here can someone explain please thanks
If you are referring to
samples = round(fs*delay) ;
ds = floor(samples);
Then you would be right that the floor() is not needed: after the round() then samples would already have integer values and that would not be changed by floor() .
samples = round(fs*delay) ;
ds = samples;
would be equivalent.
Thanks a lot, it really works.
Thank you very much. It really helped me.
just wanted to ask that in the 7th line of the 1st code ,
echo_signal(ds+(1:length(in*gain)))=in*gain;
the above line can be written as echo_signal(ds+(1:length(in)))=in*gain; right?
Yes, you could use length(in) instead of length(gain) there in practice.
Because * is algebraic matrix multiplication, there are cases where length(in) is not the same as length(in*gain) . Most of those cases would produce an error before that point. The only case that comes to mind that makes a difference would be if in is 1 x 2, and gain is 2 x 1: in that case in*gain is 1 x 1. But it is not clear what a non-scalar gain would be intended to mean in this case. (I guess if you used a gain that was a square matrix with the same number of rows and columns as the signal has channels, then you could use that matrix to define mixing between channels.)
thank you sir
Good coding. Even if you don't use the "abs", the code will work.
No, you need the abs(). When you have echo, negative values can reinforce each other just like positive values can reinforce each other.
Remember, the human ear does not directly hear whether a speaker is fully extended or fully pulled back: the human ear perceives the changes.
load handel
sound(-y,Fs)
is going to sound exactly like sound(y,Fs) .
So if the processesing can produce values > 1 that have to be scaled back due to reinforcement, then it follows that if the exact negative of the signal had been given, the values would be < -1 instead. It would therefore be a mistake to only test for > 1 instead of abs() > 1.

Sign in to comment.

Arafat Roney
Arafat Roney on 11 May 2020
Edited: Arafat Roney on 11 May 2020
function output = echo_gen(input, fs, delay, amp)
ds = round((delay)*fs); %%CALCULATING DELAY SAMPLE NUMBERS
if ds==0 %%THIS APPENDS TO THE INPUT TO EQUAL THE SIZE WITH OUTPUT
append=[]; %%APPENDS EMPTY MATRIX WHILE 'ds' IS ZERO
else
append=zeros(ds,1); %%APPENDS ZERO VECTOR FOR THE DELAY
end
ain = [append;input]; %%APPENDED INPUT
dmwa = amp*ain; %%AMPLIFIED SIGNAL
outd = [input; append]; %%APPENDED OUTPUT
out = (dmwa+outd); %%OUTPUT WITHOUT SCALLING
%%% SCALLING (IF NEEDED)
mx = max(out);
mn = min(out);
if max(abs(out))>1
if(abs(mx)>abs(mn))
output = out/abs(mx);
else
output = out/abs(mn);
end
else
output=out; %%OUTPUT WITH SCALLING(IF NEEDED)
end
end

3 Comments

hey thanks it works now
Hello, thanks for the help! Can you explain better the 'SCALLING' code part?
Thanks!
Suppose that you have a sine wave at full volume and suppose that you have a 2% echo. Then your signal value 1.0 would increase to 1.02 with the echo. But the maximum value that can be recorded is 1.0.

Sign in to comment.

function echo_sound = echo_gen(input, fs, delay, amp)
new_sr = round(fs*delay);
no_echo = [input; zeros(new_sr,1)];
echo_effect = [zeros(new_sr,1); input*amp];
echo_sound = no_echo + echo_effect;
norm_factor = max(abs(echo_sound));
if norm_factor > 1
echo_sound = echo_sound./norm_factor;
end
I wrote the following code, and I am getting errors. Can you help me with it?
function output = echo_gen(input, fs, delay, amp)
[a b] = size(input);
input1 = input*amp;
c = round(fs*delay);
d = length(input1);
x = zeros(a+c,1);
x(1:a) = input;
y = zeros(a+c,1);
y(c:d+c-1) = input1;
output = x+y;
maxi = max(abs(output));
if(maxi > 1)
output = output./maxi;
else
output = output;
end
end
function output=echo_gen(input,fs,delay,amp)
%here calculating the delay points after which echo will be added
c=round(delay*fs);
s1=[input;zeros(c,1)];
s2=[zeros(c,1);input.*amp];
output=s1+s2;
if max(abs(output)) > 1
output = output./max(abs(output)); %scaling the invalid values
end
end
end
Kazi Hafizur Rahman
Kazi Hafizur Rahman on 19 Aug 2020
Edited: Kazi Hafizur Rahman on 19 Aug 2020
this one is a little detailed but works like a charm
function output=echo_gen(input,fs,delay,amp)
N=round(fs*delay);%Number of additional points needed for delay
sz=length(input);
output=zeros(N+sz,1);%if delay is not equal to zero output size will be N greater
for i=1:length(output)
if N<sz%in this case superposition will occur
if i<=N
output(i)=input(i);%first N points will only contain original sound
elseif i<=sz
output(i)=input(i)+amp*input(i-N);%points ranging from N+1 to sz will contain original Sound +amplified sound of a previous time
else
output(i)=amp*input(i-N);%Last N points will only contain amplified data points
end
else
if i<=sz%no superposition in this case
output(i)=input(i);%first sz points will get only original signal data
%points ranging from sz+1 to N will contain nothing
elseif i>N
output(i)=amp*input(i-N);%points after N will contain amplified signal only
end
end
end
maxi=max(abs(output));
if maxi>1
output=output/maxi;%scaling if values fall outside the range [-1,1]
end
end
Ok, it works. In my opinion, the round should be the floor, because the echo signal never reaches the last point in real life.
function out = echo_gen(in, fs, del, amp);
if del==0
a=0;
else
a=round(fs*del);
end
z=zeros(a,1);
out=[in;z]+[z;in*amp];
m=max(abs(out))
if m>1
out=out/m;
end
function output = echo_gen (y,Fs,delay,amp)
additionalsamples = round (Fs*delay);
delay_vector = zeros(additionalsamples,1);
inputD = [y ; delay_vector];
newy = zeros((length(y)+additionalsamples),1);
amplified = y.*amp;
M = size(y);
newy(end-M+1:end) = amplified(1:end);
outF = newy;
out = (outF + inputD);
Max = max(out);
Min = min(out);
if max(abs(out))>1
if(abs(Max)>abs(Min))
output = out/abs(Max);
else
output = out/abs(Min);
end
else
output=out;
end
end
function output = echo_gen(input,fs,delay,amp)
rawecho = zeros(length(input)+round(fs*delay),1);%creat a vector to storge "pure" echo
v = zeros(round(fs*delay),1);
rawoutput = [input;v];%creat a vector to storge the mixtrue of "pure" echo and input
for ii = 1:length(input)
rawecho(round(fs*delay) + ii) = amp*input(ii);
end
v2 = rawecho + rawoutput;%get the mixtrue of "pure" echo and input
if isempty(v2(v2<-1|v2>1))%check whether to scale obtained output
output = v2;
else
v3 = abs(v2);%scale the output maintaining the relative amplitude of the elements
Maxnum = max(v3);
output = v2/Maxnum;
end
昱安 朱
昱安 朱 on 18 Mar 2023
Edited: DGM on 18 Mar 2023
function output = echo_gen(input, fs, delay, amp)
%input : signal,fs : sample rate,dalay : time of dalay,amp : amplitude
num_delay=round(fs*delay); %延後幾個開始放
echo0=zeros(num_delay,1);
echo_dalay=input*amp;
echo_final=[echo0;echo_dalay]; %最後echo=echo_dalay前面加上delay的數字
org_input=[input;echo0]; %在原來的聲音加上0,匹配成echo的長度
output=echo_final+org_input; %output=原來的聲音加上回音
if max(abs(output))>1
output=output/max(abs(output)); %讓echo在1~-1
end

Asked:

on 13 Jul 2019

Edited:

DGM
on 18 Mar 2023

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!