classdef DampedParameter < handle
    %DampedParameter Re-usable damped parameter.
    %   Damped parameter can be thought of as a parameter with inertia. 
    
    %   Copyright 2016 The MathWorks, Inc.
    
    %#codegen
    properties
        %Value Target value
        %   Value specifies the target value for the damped parameter. The
        %   parameter will transition to the target value over time
        %   (depending on the transition delay).
        Value = 0
        %TransitionDelay Transition Delay parameter
        %   TransitionDelay specifies transition time between the previous
        %   Value and new Value.
        TransitionDelay = 0.01
        %SampleRate Sample Rate for the parameter
        SampleRate = 44100
    end
    
    properties (Access=private)
        Damping
        States = 0        
        visualObj
    end
        
    properties (Constant)
        Tolerance = 0.01;
    end
    
    methods
        function obj = DampedParameter(Val,D,Fs)
            
            if nargin > 0
                obj.Value = Val;
            end
            if nargin > 1
                obj.TransitionDelay = D;
            end
            if nargin > 2
                obj.SampleRate = Fs;
            end
            
            computeDampingCoefficient(obj);
        end
        
        function set.TransitionDelay(obj,dly)
            % Check that the transition delay is a finite, real,
            % nonnegative scalar
            validateattributes(dly, {'numeric'}, ...
                {'finite','real','scalar','nonnegative'},...
                'set.TransitionDelay','TransitionDelay');
            
            obj.TransitionDelay = dly;
            computeDampingCoefficient(obj);
        end
        
        function val = getDampedValue(obj,FrameSize)
            x = obj.Value*ones(FrameSize,1);
            
            % Access damping coefficient
            a = obj.Damping;
            
            % Access filter states
            z = obj.States;
            
            % Compute numerator coefficient
            Num = 1-a;
            
            % Compute the damped parameter value with smooth transitions
            [val,z] = filter(Num,[1 -a],x,z);
            
            if isempty(coder.target) && ~isempty(obj.visualObj)
                step(obj.visualObj,val);
            end
            
            % Store final states
            obj.States = z;
        end
        
        function reset(obj)
            % Re-initialize states
            obj.States = 0;
            % Compute initial damping coefficient from transition delay
            computeDampingCoefficient(obj);
        end
        
        function visualize(obj)
            
            if isempty(obj.visualObj) 
                
                obj.visualObj = dsp.TimeScope('TimeSpanOverrunAction','Scroll',...
                    'TimeSpan',1,'SampleRate',obj.SampleRate,...
                    'TimeUnits','Seconds','ShowGrid',true);
            
            end
            show(obj.visualObj);
        end
    end
    
    methods (Access = private)
        function computeDampingCoefficient(obj)
            % Find damping coefficient corresponding to desired transition
            % delay
            Fs = obj.SampleRate;
            c  = obj.Tolerance;
            la = log(c)/(obj.TransitionDelay*Fs);
            obj.Damping = exp(la);
        end
    end
end

