classdef Efekty < handle

    properties
        File
        PathName
        Fs
        baseY
        yT
        player
        isEcho
        isFlanger
        isAM
        isDistortion
        echoDelay
        echoLevel
        flangerDelay
        flangerDepth
        flangerRate
        amFreq
        amModulation
        distortionLevel
        distortionThreshold
        yTAxes

    end

    methods
        function obj = Efekty(file, pathName)
                    obj.File = file;
                    obj.PathName = pathName;
                    % Načtení soouboru
                    [obj.baseY, obj.Fs] = audioread(fullfile(pathName, file));

                    %Převod signálu na mono
                    obj.baseY = mean(obj.baseY, 2);  
        end
        
        % Vypsání názvu souboru
        function r = getFileName(obj)
                    [~, name, ext] = fileparts(fullfile(obj.PathName, obj.File));
                    r = strjoin({name, ext});
        end

        % Vlastní funkce
        function obj = modulateYT(obj)

            newYT = obj.baseY;

            %%% Echo
            if (obj.isEcho)
                newYT = obj.echo(newYT, obj.Fs, obj.echoDelay, obj.echoLevel);
            end

            %%% Flanger
            if (obj.isFlanger)
                newYT = obj.flanger(newYT, obj.Fs, obj.flangerDelay, obj.flangerDepth, obj.flangerRate);
            end

            %%% AM MODULACE
            if (obj.isAM)
                newYT = obj.am(newYT, obj.Fs, obj.amFreq, obj.amModulation);
            end

             %%% Distortion
             if (obj.isDistortion)
                 newYT = obj.distortion(obj.distortionLevel, obj.distortionThreshold);
             end
            
            obj.setYT(newYT);
        end


        function obj = setIsEcho(obj, isEcho)
            obj.isEcho = isEcho;
        end
        
        function obj = setIsFlanger(obj, isFlanger)
            obj.isFlanger = isFlanger;
        end

         function obj = setIsAM(obj, isAM)
            obj.isAM = isAM;
         end

        function obj = setIsDistortion(obj, isDistortion)
            obj.isDistortion = isDistortion;
        end

        function obj = setEchoDelay(obj, echoDelay)
            obj.echoDelay = echoDelay;
        end

        function obj = setLevel(obj, echoLevel)
            obj.echoLevel = echoLevel;
        end

        function obj = setFlangerDelay(obj, flangerDelay)
           obj.flangerDelay = flangerDelay;
        end

        function obj = setDepth(obj, flangerDepth)
           obj.flangerDepth = flangerDepth;
        end

        function obj = setRate(obj, flangerRate)
           obj.flangerRate = flangerRate;
        end

        function obj = setAMFreq(obj, amFreq)
           obj.amFreq = amFreq;
        end

        function obj = setAMModulation(obj, amModulation)
           obj.amModulation = amModulation;
        end

        function obj = setDistortionLevel(obj, distortionLevel)
            obj.distortionLevel = distortionLevel;
        end

        function obj = setDistortionThreshold(obj, distortionThreshold)
            obj.distortionThreshold = distortionThreshold;
        end


        function obj = setYT(obj, yT)   
            obj.yT = yT;
            obj.plotYT();
            obj.player = audioplayer(obj.yT, obj.Fs);
        end
        
        % Efekt ECHO
        function r = echo(~, yT, Fs, delay, amp) 
            % Hodnota, která představuje zpoždění
            new_e = round(Fs * delay);          
            [~, numCols] = size(yT);

            % Původní signál s přidanými nulami
            no_echo = [yT; zeros(new_e,numCols)];

            % Zpožděný signál a nastavení jeho amplitudy
            echo_fx = [zeros(new_e,numCols); yT * amp];

            % Sečtení původního a zpožděného signálu
            newYT = no_echo + echo_fx;
            r = newYT; % Výsledný signál
        end       

        % Efekt FLANGER
        function r = flanger(~, yT, Fs, delay, depth, rate)
                % Parametry flanger efektu
                inputSignal = yT;
                sampleRate = Fs;
                delayTime = delay; % Doba zpoždění (v sekundách)
                modulationDepth = depth; % Hloubka modulace (v sekundách)
                modulationRate = rate; % Frekvence modulace (v Hz)
                
                % Vytvoření LFO signálu pro modulaci zpoždění
                time = (0:length(inputSignal)-1) / sampleRate;
                lfoSignal = sin(2*pi*modulationRate*time');
                
                % Vytvoření flanger efektu
                r = zeros(size(inputSignal));
                for i = 1:length(inputSignal)
                    delaySamples = round((delayTime + modulationDepth*lfoSignal(i)) * sampleRate);
                    if i > delaySamples
                        r(i) = inputSignal(i) + inputSignal(i - delaySamples);
                    else
                        r(i) = inputSignal(i);
                    end
                end
        end

        % Efekt MODULACE AM (efekt tremolo)
        function r = am(~, yT, Fs, freq, modulation)
         
              freqAM = freq; % Frekvence nosného signálu
              modulationAM = modulation; % Index modulace (0 - 1)
              
              % Vytvoření nosného signálu
              time = (0:length(yT)-1) / Fs;
              amSignal = cos(2*pi*freqAM*time');
              
              % Aplikace amplitudové modulace
              r = (1 + modulationAM*amSignal) .* yT;
        end

        % Efekt Distortion
        function r = distortion(obj, level, threshold)
            audioOut = zeros(size(obj.baseY)); % vytvoření výstupního pole
            for n = 1:length(obj.baseY)
               % Výpočet aktuálního vstupního signálu
               xn = obj.baseY(n);
            
               % Výpočet aktuálního zesíleného signálu
               xg = xn * level;
            
               % Aplikace clippingu na zesílený signál
               if abs(xg) > threshold
                   xg = sign(xg) * threshold;
               end
            
               % Výpočet výstupního signálu
               audioOut(n) = xg;               
            end
            r = audioOut;
        end

        % Vykreslení grafu
        function obj = plotYT(obj)
                plot(obj.yTAxes, (0:length(obj.yT)-1)/obj.Fs, obj.yT);
        end
        function obj = setYTAxes(obj, yTAxes)
            obj.yTAxes = yTAxes;
        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