%% Carl Edser - 430488700 - DESC9115 Lab Report 2

% University of Sydney - Masters in Design Science (Audio and Acoustics)

% Lecturer - Bill Martens
% Tutor - Luis Alejandro Miranda Jofre 


% This function allows the user to apply a limiter to an input audio
% signal. Adjustment of this limiters parameters can be accessed from the
% call_limiter.m file provided in the folder. Guidance for the creation of
% this function was obtained from both the DAFX text (Chapter 5.2.1) 

%% LIMITER FUNCTION

function dataout = limiter(datain, Fs, att, rel, compfac, compthresh, limthresh)

%   datain      = input signal
%   Fs          = sampling frequency in Hz
%   att         = attack time of the limiter
%   rel         = release time of the limiter
%   compfac     = compression factor
%   compthresh  = compression threshold
%   limthresh   = limiter threshold
%   dataout     = output where limiter has been applied to the input signal

% Conversion from decibels (dB)

compthresh = 10^(compthresh/20);
limthresh = 10^(limthresh/20);


% Calculate the amplitude at which the limiter is activated

limit_react = (limthresh - compthresh) * compfac + compthresh;


% Attack and release times converted into samples

att = 1-exp(-2.2* Fs/att);
rel = 1-exp(-2.2* Fs/rel);

if size (datain, 2) > size (datain,1)
    datain = datain';
end;


% Initialize peak detector vector and gain factor vector

xd = zeros (length(datain),1);
f = zeros (length(datain),1);


% Analyses the sound vector and compares the signal values with the
% threshold values. Set gain factor vector and multiply

for n = 2:length(datain);
 
    a = abs (datain(n,1)) - xd (n - 1);
    if a < 0
        a = 0;
    end;
    xd(n) = xd(n - 1) * (1-rel)+ att * a;
    
    if compthresh < xd(n) && xd(n) < limthresh;
        f(n) = 10^(-limiter * (log10(xd(n))-log10(compthresh)));
    
    elseif xd(n) >= limthresh;
        f(n) = 10^(-1*(log10(xd(n))-log10(limit_react)));
        
        else
            f(n) = 1;
    end;
end;


% Multiply with the gain factor vector

dataout (:,1) = datain(:,1).* f;


% Maximize

dataout(:,1) = dataout(:,1)/max(abs(dataout(:,1)));


% Potential error messages from invalid input values in script

if nargin < 7
    error ('Not enough input arguments. Check function parameters')
end;

if 0.00001 > att || att > 2
    error ('att value must be between 0.00001 and 2 (ten microseconds / two seconds');
end;

if 0.005 > rel || rel > 5
    error ('rel value must be between 0.005 and 5 (five milliseconds / five seconds');
end;

if 0 > compfac || compfac > 1
    error ('compression factor must be set between 0 and 1');
end;

if 20 < compthresh || compthresh < -100
    error ('Compression threshold must be set between -100 and 20');
end;

if 20 < limthresh || limthresh < -100 || limthresh < compthresh
    error ('To use as limiter, limthresh must be set the same as compthresh');
end;


% Plotting of the input signal against processed output signal

subplot(2,1,1);
plot (datain, 'b'), title('Original Waveform'), xlabel('Samples'), ylabel('Amplitude');
subplot(2,1,2);
plot(dataout, 'r'), title('Limiter Applied to Input'), xlabel('Samples'), ylabel('Amplitude');