classdef (StrictDefaults)BassEnhancer < audioPlugin & matlab.System
    % BassEnhancer  Enhance low frequencies of an audio signal.
    %
    % This object is used in the "Psychoacoustic Bass enhancement for
    % Band-Limited Signals" featured example
    %
    % See also: audiopluginexample.PitchShifter
    
    %   Copyright 2015-2022 The MathWorks, Inc.
    
    %#codegen
    
    %----------------------------------------------------------------------
    % Public properties
    %----------------------------------------------------------------------
    properties
        %BPUpperCutoff Bandpass filter upper cutoff frequency (Hz)
        BPUpperCutoff = 180
        
        %Gain Gain applied at the output of the bandpass filter
        Gain = 0.05
    end
    
    properties (Access = private)
        pCrossover
        pIntegrator
        pFilter
        pGainFilter
    end
    
    %----------------------------------------------------------------------
    % Constant properties
    %----------------------------------------------------------------------
    properties (Constant, Hidden)
        % audioPluginInterface manages the number of input/output channels
        % and also instantiates the value class, audioPluginParameter to
        % generate plugin UI parameters.
        PluginInterface = audioPluginInterface(...
            'InputChannels',2,...
            'OutputChannels',2,...
            'PluginName','BassEnhancer',...
            audioPluginParameter('BPUpperCutoff',...
            'DisplayName','Upper Cutoff', ...
            'Label','Hz','Mapping',{'lin',80 200}, ...
            'Style', 'rotaryknob', 'Layout', [1 2]),...
            audioPluginParameter('Gain','Mapping',{'lin',0 .1}, ...
            'Style', 'rotaryknob', 'Layout', [1 1]), ...
            audioPluginGridLayout('RowHeight', [100 20], ...
            'ColumnWidth', [100 100], 'Padding', [10 10 10 30]),...
            'BackgroundImage', audiopluginexample.private.mwatlogo);
    end
    
    methods (Access = protected)
        
        function z = stepImpl(obj,x)
            % Split input to LP and HP
            [lp,hp] = obj.pCrossover(x);
            lpSum = sum(lp,2);
            % Pass lowpass component through non-linear device to create
            % harmonics
            integratorOutput = obj.pIntegrator(lpSum);
            % Bandpass filter
            bpOuput = obj.pFilter(integratorOutput);
            gainOutput = obj.pGainFilter(bpOuput);
            % Create stereo output
            z1 = gainOutput + hp(:,1);
            z2 = gainOutput + hp(:,2);
            z = [z1,z2];
        end
        
        function setupImpl(obj,x)
            obj.pCrossover  = crossoverFilter('CrossoverFrequencies',60,'CrossoverSlopes',24);
            obj.pIntegrator = audioexample.FullWaveIntegrator;
            obj.pFilter     = audiopluginexample.VarSlopeBandpassFilter(60,obj.BPUpperCutoff,24,24);
            obj.pGainFilter = dsp.FIRFilter('Numerator',1);
            setup(obj.pGainFilter,x(:,1));
            obj.pGainFilter.Numerator = obj.Gain;
        end
        
        function resetImpl(obj)
            fs = getSampleRate(obj);
            obj.pCrossover.SampleRate = fs;
            setSampleRate(obj.pFilter, fs);
            
            reset(obj.pFilter);
            reset(obj.pCrossover);
            reset(obj.pIntegrator);
        end
        
        function processTunedPropertiesImpl(obj)
            if obj.pFilter.HighCutoff ~= obj.BPUpperCutoff
                obj.pFilter.HighCutoff    = obj.BPUpperCutoff;
            end
            if obj.pGainFilter.Numerator ~= obj.Gain
                obj.pGainFilter.Numerator = obj.Gain;
            end
        end

        function flag = isInputSizeMutableImpl(~,~)
            flag = true;
        end

        function s = saveObjectImpl(obj)
            s = saveObjectImpl@matlab.System(obj);
            s = savePluginProps(obj,s);
            if isLocked(obj)
                s.pCrossover = matlab.System.saveObject(obj.pCrossover);
                s.pIntegrator = matlab.System.saveObject(obj.pIntegrator);
                s.pFilter = matlab.System.saveObject(obj.pFilter);
                s.pGainFilter = matlab.System.saveObject(obj.pGainFilter);
            end
        end

        function loadObjectImpl(obj, s, wasLocked)
            if wasLocked
                obj.pCrossover = matlab.System.loadObject(s.pCrossover);
                obj.pIntegrator = matlab.System.loadObject(s.pIntegrator);
                obj.pFilter = matlab.System.loadObject(s.pFilter);
                obj.pGainFilter = matlab.System.loadObject(s.pGainFilter);
            end
            loadObjectImpl@matlab.System(obj,s,wasLocked);
            reload(obj,s);
        end

    end
end