two signals with different frequencies to play at the same time without audio clipping

2 views (last 30 days)
Hi
I want to play two sounds at the same time (d1 and d01), and they have different frequencies. My issue is that when I run the code the audio clips and it is because of d01(when I remove it the code works fine). I considered combining them but im not sure how to do that.
C=220*2^(3/12);
Cc=220*2^(4/12);
G=220*2^(10/12);
T=1/8000;
num=[1:1:(2*8000)+1];
d1=sin(2*pi*C*T*num).*(heaviside(T*num)-heaviside(T.*num-0.5));
d01=sin(2*pi*Cc*T*num).*(heaviside(T*num)-heaviside(T.*num-0.5));
d2=sin(2*pi*C*T*num).*(heaviside(T*num-0.75)-heaviside(T.*num-1.25));
d3=sin(2*pi*G*T*num).*(heaviside(T*num-1.5)-heaviside(T.*num-2));
notes=d1+d01+d2+d3;
vector=zeros(1,2*8000+1);
for i=1:2*8000+1
vector(i)=notes(i);
end
audiowrite('test.wav',vector,8000);
Warning: Data clipped when writing file.
r=audioread('test.wav');
sound(r,8000,8);

Accepted Answer

William Rose
William Rose on 4 Nov 2022
I see that you are starting from A440, divividing by 2 to go down an octave, then using the circle of fifths with equal temperament to go up to middle C, C#, G.
audiowrite likes signals to be in the range -1 to +1. I added a line to your code to display the min and max of notes. As you will see, min=-2, max=+2. Therefore you could just divide the whole signal by 2 and it would be OK. I wrote a more general rescaling funciton that will re-map notes to the rage [-1,+1], for any min and max. I also added a line to display the min and max of rescaled notes.
C=220*2^(3/12);
Cc=220*2^(4/12);
G=220*2^(10/12);
T=1/8000;
num=[1:1:(2*8000)+1];
d1=sin(2*pi*C*T*num).*(heaviside(T*num)-heaviside(T.*num-0.5));
d01=sin(2*pi*Cc*T*num).*(heaviside(T*num)-heaviside(T.*num-0.5));
d2=sin(2*pi*C*T*num).*(heaviside(T*num-0.75)-heaviside(T.*num-1.25));
d3=sin(2*pi*G*T*num).*(heaviside(T*num-1.5)-heaviside(T.*num-2));
notes=d1+d01+d2+d3;
fprintf('notes: min=%.2f, max=%.2f\n',min(notes),max(notes))
notesRe=(notes-min(notes))*2/(max(notes)-min(notes))-1; %rescaled notes
fprintf('rescaled notes: min=%.2f, max=%.2f\n',min(notesRe),max(notesRe))
vector=zeros(1,2*8000+1);
for i=1:2*8000+1
vector(i)=notesRe(i);
end
audiowrite('test.wav',vector,8000);
r=audioread('test.wav');
sound(r,8000,8);
It seems to work. No more warning message.
  4 Comments
William Rose
William Rose on 4 Nov 2022
Here is a script that generates a C major arpeggio and triad:
fC=220*2^(3/12); %middle C frequency (Hz)
fEe=fC*2^(4/12); %E frequency (Hz), equal temperament
fGe=fC*2^(7/12); %G frequency (Hz), equal temperament
fs=8000; %sampling rate (Hz)
dT=1/fs; %sampling interval (s)
t10=dT:dT:1; %1.0 second long time vector
si1=zeros(1,fs*0.1); %0.1 seconds of silence
t6=dT:dT:0.6; %0.6 second long time vector
%generate arpeggio + triad waveform
r1=[sin(2*pi*fC*t6),si1,sin(2*pi*fEe*t6),si1,sin(2*pi*fGe*t6),si1,...
(sin(2*pi*fC*t10)+sin(2*pi*fEe*t10)+sin(2*pi*fGe*t10))/3];
r1=rescale(r1,-1,1); %probably not necessary in this case
sound(r1,fs) %play arpeggio + triad
The individual notes sound reasonable, but when combined in a chord, they sound different than doing it on the piano.
I also tried it using the just temperament frequencies for E and G, not shown above. The resulting sounds were the same, to my ear. I wondered if the computer-generated just and equal temperament chords would sound different, because the just temperament frequencies are exact fractional multiples of the base frequency, and the equal temperament values are not. Therefore the C, E, G waveforms stay in phase for just temperament, but they get out of phase for equal temperament. The computer-generated just and equal temperament triads sound the same to me: they both sound different from a real piano.

Sign in to comment.

More Answers (0)

Categories

Find more on Audio I/O and Waveform Generation in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

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

Start Hunting!