Created a Pitch Envelope

App updated to work with pitch envelope. Works with Harmonic Offset. Added Equalizer GUI elements.

Still does not work with LFO and does not work with Equalizer.
This commit is contained in:
Darell Chua Yun Da 2021-12-07 07:25:21 +08:00
parent ef5b43b354
commit 0984b75d36
6 changed files with 125 additions and 3 deletions

Binary file not shown.

View File

@ -0,0 +1,57 @@
%Written by Darell and Anne
function output = DarellAnnePitchEnvelope(input, Fs, attack,decay,sustain,release) %percentages for attack, decay, sustain, release
len = length(input);
T = (len-1)/Fs;
attacktime = attack * T * Fs;
decaytime = attacktime + decay * T * Fs;
sustaintime = (T - (release * T)) * Fs;
output = zeros([1,len]);
tcounter = 1;
%attack phase
curr = attacktime;
while tcounter <= curr
ncount = round(curr*log(tcounter)/log(curr)+1);
output(tcounter) = input(ncount);
tcounter = tcounter+1;
end
%decay phase
prevcur = curr;
tcounter = prevcur;
curr = decaytime;
while tcounter <= curr
ncount = round(sustain*curr*(1-log(tcounter)/log(prevcur)) + prevcur);
tcounter = round(tcounter);
output(tcounter)
output(tcounter) = input(ncount);
tcounter = tcounter+1;
end
%sustain phase
prevncount = ncount;
prevcur = curr;
tcounter = prevcur;
curr = sustaintime;
while tcounter <= curr
ncount = round(sustain*(tcounter - prevcur) + prevncount);
tcounter = round(tcounter);
output(tcounter) = input(ncount);
tcounter = tcounter+1;
end
%release phase
prevncount = ncount;
prevcur = curr;
tcounter = prevcur;
curr = Fs;
while tcounter <= Fs
ncount = round(curr*(1-log(tcounter)/log(prevcur)) + prevncount);
tcounter = round(tcounter);
output(tcounter) = input(ncount);
tcounter = tcounter+1;
end
end

8
src/FilterSelect.m Normal file
View File

@ -0,0 +1,8 @@
function output = FilterSelect(input,Fs,LOW,MED,HIGH,number)
if(number == "Option 1")
output = DarellbandpassFilter(input,Fs,LOW,MED,HIGH);
else
output = input;
end
end

View File

@ -13,7 +13,7 @@ x = x + generate_sine(amplitude, (frequency+5), phase, fs, duration, duty);
%play over 5 counts, should hear both frequencies, 5 beats per second between the 2 frequencies %play over 5 counts, should hear both frequencies, 5 beats per second between the 2 frequencies
playtime = 5; playtime = 5;
play_continuous(x, fs, playtime) %play_continuous(x, fs, playtime)
LOW = 0; LOW = 0;
HIGH = frequency + 1; HIGH = frequency + 1;
@ -22,7 +22,14 @@ x = DarellbandpassFilter(x,fs,LOW,MED,HIGH);
%play over 5 counts, should only hear 200hz %play over 5 counts, should only hear 200hz
playtime = 5; playtime = 5;
play_continuous(x, fs, playtime) %play_continuous(x, fs, playtime)
attack = 0.2;
decay = 0.1;
sustain = 0.8;
release = 0.4;
x = DarellAnnePitchEnvelope(x, Fs, attack,decay,sustain,release);
attack = 0.2; attack = 0.2;
decay = 0.2; decay = 0.2;

View File

@ -0,0 +1,50 @@
% Petha_Hsu_PitchOffset: input a wave and pitch offset (in percentage)
% This function takes a input sound signal and increases the pitch by the
% offset percentage. The output is not 100% accurate. It is only an
% estimation as the information we the function works with is very limited.
% If 100% output is expected, more information like the frequency and type
% of wave would be required. And the estimation only works for
% f_offset > 0.5. Below 0.5, the output is problematic. Again, the output
% is just a good estimation.
% CONTRIBUTORS:
% Pethaperumal Natarajan: I figured a way to increase the pitch of input
% signal by using fourier transform and shifting the frequency using a for
% loop. Then I used inverse transform to get a sound signal back in the time
% domain.
% Wesley Hsu: I helped solve the problem of being unable to lower frequency
% for the loop using the floor function. This allowed rounding to maintain
% the lower signals that were needed when the code returned the signal back
% into the time domain.
function y = Petha_Hsu_PitchOffset(x, f_offset)
len = length(x);
X = fft(x);
X = fftshift(X); %Fourier transform the input wave
Y = zeros(1, len);
midpoint = len/2;
for i = 1:len
%Shifting the Fourier transform in frequency domain to adjust the
%frequency of signal.
%Floor function is used as signals must be integers and not
%doubles.
if floor((i - midpoint) / f_offset + midpoint) < 1 || floor((i - midpoint) / f_offset + midpoint) > len
continue;
end
Y(i) = X(floor((i - midpoint) / f_offset + midpoint));
end
%Plotted graphs to troubleshoot the problem.
%Fs = 44800;
%f = Fs *(-len/2 : len/2 -1) / len;
%tiledlayout(1,3); nexttile;
%plot(f, abs(X)); title("input"); nexttile;
%plot(f, abs(Y)); title("output"); nexttile;
Y = fftshift(Y);
y = ifft(Y);
y = real(y);
end

View File

@ -1,6 +1,6 @@
function output = PitchEnvelopeSelect(input, Fs, attack,decay,sustain,release,number) function output = PitchEnvelopeSelect(input, Fs, attack,decay,sustain,release,number)
if(number == "Option 1") if(number == "Option 1")
output = DarellAmplitudeEnvelope(input, Fs, attack,decay,sustain,release); output = DarellAnnePitchEnvelope(input, Fs, attack,decay,sustain,release);
else else
output = input; output = input;
end end