classdef EQ < handle
 
properties
        File
        PathName
        baseY
        Fs
        yT
        player
        GainBass
        GainMiddle
        GainTreble
        yTUIAxes
        
end
    methods

        % Načtení zvukového souboru
        function obj = EQ(file, pathName, GainBass, GainMiddle, GainTreble)
                    obj.File = file;
                    obj.PathName = pathName;
                   [obj.baseY, obj.Fs] = audioread(fullfile(pathName, file));

                   %Převod signálu na mono
                   obj.baseY = mean(obj.baseY, 2); 

                   %Nastavení hodnot z GUI
                   obj.GainBass = GainBass;
                   obj.GainMiddle = GainMiddle;
                   obj.GainTreble = GainTreble;
                  
        end
        
        function r = getFileName(obj)
                    [~, name, ext] = fileparts(fullfile(obj.PathName, obj.File));
                    r = strjoin({name, ext});
        end

        function obj = setYT(obj, yT)   
            obj.yT = yT;
            obj.plotYT();
            obj.player = audioplayer(obj.yT, obj.Fs);
        end

        function obj = setGainBass(obj, GainBass)   
            obj.GainBass = GainBass;
            obj.modulateYT_YY();
        end
        
        function obj = setGainMiddle(obj, GainMiddle)   
            obj.GainMiddle = GainMiddle;
            obj.modulateYT_YY();
        end

        function obj = setGainTreble(obj, GainTreble)   
            obj.GainTreble = GainTreble;
            obj.modulateYT_YY();
        end

        %%%Vykreslení grafu
        function obj = plotYT(obj)
           
           % Vypočítání kmitočtového spektra signálu
                N = length(obj.yT); % délka signálu
                f = (0:N-1)*(obj.Fs/N); % vypočtení kmitočtů pro každý vzorek signálu
                Y = fft(obj.yT)/N; % Fourierova transformace
                
                % Výpočet amplitud a frekvencí
                amplitude = 2*abs(Y(1:N/2+1));
                frequency = f(1:N/2+1);
                
                % Zobrazení signálu v grafu
                plot(obj.yTUIAxes,frequency, amplitude);
                obj.yTUIAxes.XScale = 'log'; % Osa x bude logaritmická
                obj.yTUIAxes.XTick = [100 500 2500 4500 16000]; % Nastavení hodnot na ose x
                obj.yTUIAxes.XLim = [50 20000]; % Nastavení rozsahu osy x 
        end
        
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       
        function obj = modulateYT_YY(obj) 
       
           newYT = obj.equalizationLow(obj.baseY,str2double(obj.GainBass),(500)); % Přiřazení hodnoty zesílení v dB a mezní frekvence
           newYT = obj.equalizationPeak(newYT, str2double(obj.GainMiddle), (2500), 2000); % Přiřazení zesílení, střední frekvence a šířky pásma 
           newYT = obj.equalizationHigh(newYT, str2double(obj.GainTreble), (4500)); % Přiřazení hodnoty zesílení v dB a mezní frekvence

           obj.setYT(newYT);

        end
 
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
               
                 %%%Low shelf filtr pro úpravu basového pásma
                 function r = equalizationLow(obj, y, gain, limits)
                   
                    fs = obj.Fs; % Vzorkovací frekvence (vstupní hodnota načteného signálu)
                    fc = limits; % Středová frekvence basového pásma (pevně nastavená), po vydělení 2 dostáváme limits jako krajní mez
                    G = gain; % Zesílení basového pásma v dB (zisk / útlum)
                 
                    % Převod frekvence z lineární škály na logaritmickou
                    w0 = 2*pi*fc/fs;
                    A = 10^(G/20);
                 
                    % Výpočet koeficientů filtru pro konstantní sklon. Určují charakteristiku filtru 
                    alpha = sin(w0) / (2*sqrt(A));
                    b0 = A*((A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha); 
                    b1 = 2*A*((A-1) - (A+1)*cos(w0));
                    b2 = A*((A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha);
                    a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha;
                    a1 = -2*((A-1) + (A+1)*cos(w0));
                    a2 = (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha;
                 
                    % Normalizace koeficientů
                    b0 = b0/a0;
                    b1 = b1/a0;
                    b2 = b2/a0;
                    a1 = a1/a0;
                    a2 = a2/a0;
                 
                    % Implementace filtru
                    yh = [0, 0];
                    for n = 1:length(y)
                        yh_new = y(n) - a1*yh(1) - a2*yh(2);
                        fr(n) = b0*yh_new + b1*yh(1) + b2*yh(2);
                        yh = [yh_new, yh(1)];
                    end               
                    r = fr;                   
                 end
          
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          
                 %%%Peak filtr pro úpravu středních pásem
                 function y = equalizationPeak (obj, y, G, limit, bandwith)
                        Fc = 2 * limit /obj.Fs; % Středová frekvence pásma
                        Fb = 2 * bandwith /obj.Fs; % Šířka pásma
                        V0 = 10^(G/20); 
                        H0 = V0 - 1;

                        % Výpočet koeficientů c a d
                        if G >= 0
                            c = (tan(pi * Fb / 2) - 1) / (tan(pi * Fb / 2) + 1); 
                        else
                            c = (tan(pi * Fb / 2) - V0) / (tan(pi * Fb / 2) + V0); 
                        end
                        d = -cos(pi * Fc); 

                        yh = [0, 0];
                        for n = 1:length(y)
                            yh_new = y(n) - d * (1 - c) * yh(1) + c * yh(2);
                            ap_y = -c * yh_new + d * (1 - c) * yh(1) + yh(2); % Aproximace filtru
                            yh = [yh_new, yh(1)];
                            y(n) = 0.5 * H0 * (y(n) - ap_y) + y(n);
                        end
                 end
          
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                 %%%High shelf filtr pro úpravu výškového pásma
                 function r = equalizationHigh(obj, y, gain, limits)
                     fs = obj.Fs; % Vzorkovací frekvence (vstupní hodnota načteného signálu)
                     fc = limits; % Středová frekvence výškového pásma (pevně nastavená), po vydělení 2 dostáváme limits jako krajní mez
                     G = gain; % Zesílení výškového pásma v dB
                     
                     % Převod frekvence z lineární škály na logaritmickou
                     w0 = 2*pi*fc/fs;
                     A = 10^(G/20);
                     
                     % Výpočet koeficientů filtru pro konstantní sklon
                     alpha = sin(w0) / (2*sqrt(A));
                     b0 = A*((A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha);
                     b1 = -2*A*((A-1) + (A+1)*cos(w0));
                     b2 = A*((A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha);
                     a0 = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha;
                     a1 = 2*((A-1) - (A+1)*cos(w0));
                     a2 = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha;
                     
                     % Normalizace koeficientů
                     b0 = b0/a0;
                     b1 = b1/a0;
                     b2 = b2/a0;
                     a1 = a1/a0;
                     a2 = a2/a0;
                     
                     % Implementace filtru
                     yh = [0, 0];
                     for n = 1:length(y)
                         yh_new = y(n) - a1*yh(1) - a2*yh(2);
                         fr(n) = b0*yh_new + b1*yh(1) + b2*yh(2);
                         yh = [yh_new, yh(1)];
                     end

                     r = fr;
                 end
           
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
         
        function obj = setYTUIAxes(obj, yTUIAxes)
           obj.yTUIAxes = yTUIAxes;
        end
        
        %%%%%%%%%%%PŘEHRÁVAČ%%%%%%%%%%%
        function obj = playAudio(obj)                       
            play(obj.player);
            disp(['Player,running ', obj.player.Running]);
        end
        
        function obj = pauseAudio(obj)
            pause(obj.player);
            disp(['Player,running ', obj.player.TimerPeriod]);
        end
        
        function obj = stopAudio(obj)
            stop(obj.player);
            disp(['Player,running ', obj.player.Running]);
        end  
    end
end