% Copyright (C) 2018  Symeon Symeonidis, Stefanos Tsantilas, Stelios Mitilineos
% simos421@gmail.com, steftsantilas@gmail.com, smitil@gmail.com
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.

function CstTDMMeshSettings(mws, CellsPerWavelenth, MinimumCell)

%'@ set mesh properties (Hexahedral)
Mesh = invoke(mws,'Mesh');
invoke(Mesh,'MeshType','PBA');
invoke(Mesh,'SetCreator','High Frequency');

MeshSettings = invoke(mws,'MeshSettings');
invoke(MeshSettings,'SetMeshType','Hex');
invoke(MeshSettings,'Set','Version','1%');

%'MAX CELL - WAVELENGTH REFINEMENT
invoke(MeshSettings,'Set','StepsPerWaveNear',num2str(CellsPerWavelenth));
invoke(MeshSettings,'Set','StepsPerWaveFar',num2str(CellsPerWavelenth));
invoke(MeshSettings,'Set','WavelengthRefinementSameAsNear','1');
%'MAX CELL - GEOMETRY REFINEMENT
invoke(MeshSettings,'Set','StepsPerBoxNear',num2str(CellsPerWavelenth));
invoke(MeshSettings,'Set','StepsPerBoxFar',num2str(CellsPerWavelenth));
invoke(MeshSettings,'Set','MaxStepNear',num2str(CellsPerWavelenth));
invoke(MeshSettings,'Set','MaxStepFar',num2str(CellsPerWavelenth));
invoke(MeshSettings,'Set','ModelBoxDescrNear','maxedge');
invoke(MeshSettings,'Set','ModelBoxDescrFar','maxedge');
invoke(MeshSettings,'Set','UseMaxStepAbsolute','0');
invoke(MeshSettings,'Set','GeometryRefinementSameAsNear','1');
%'MIN CELL
invoke(MeshSettings,'Set','UseRatioLimitGeometry','1');
invoke(MeshSettings,'Set','RatioLimitGeometry',num2str(MinimumCell));
invoke(MeshSettings,'Set','MinStepGeometryX','0');
invoke(MeshSettings,'Set','MinStepGeometryY','0');
invoke(MeshSettings,'Set','MinStepGeometryZ','0');
invoke(MeshSettings,'Set','UseSameMinStepGeometryXYZ','1');

MeshSettings = invoke(mws,'MeshSettings');
invoke(MeshSettings,'SetMeshType','Hex');
invoke(MeshSettings,'Set','FaceRefinementOn','0');
invoke(MeshSettings,'Set','FaceRefinementPolicy','2');
invoke(MeshSettings,'Set','FaceRefinementRatio','2');
invoke(MeshSettings,'Set','FaceRefinementStep','0');
invoke(MeshSettings,'Set','FaceRefinementNSteps','2');
invoke(MeshSettings,'Set','EllipseRefinementOn','0');
invoke(MeshSettings,'Set','EllipseRefinementPolicy','2');
invoke(MeshSettings,'Set','EllipseRefinementRatio','2');
invoke(MeshSettings,'Set','EllipseRefinementStep','0');
invoke(MeshSettings,'Set','EllipseRefinementNSteps','2');
invoke(MeshSettings,'Set','FaceRefinementBufferLines','3');
invoke(MeshSettings,'Set','EdgeRefinementOn','1');
invoke(MeshSettings,'Set','EdgeRefinementPolicy','1');
invoke(MeshSettings,'Set','EdgeRefinementRatio','2');
invoke(MeshSettings,'Set','EdgeRefinementStep','0');
invoke(MeshSettings,'Set','EdgeRefinementBufferLines','3');
invoke(MeshSettings,'Set','RefineEdgeMaterialGlobal','0');
invoke(MeshSettings,'Set','RefineAxialEdgeGlobal','0');
invoke(MeshSettings,'Set','BufferLinesNear','3');
invoke(MeshSettings,'Set','UseDielectrics','1');
invoke(MeshSettings,'Set','EquilibrateOn','0');
invoke(MeshSettings,'Set','Equilibrate','1.5');
invoke(MeshSettings,'Set','IgnoreThinPanelMaterial','0');

MeshSettings = invoke(mws,'MeshSettings');
invoke(MeshSettings,'SetMeshType','Hex');
invoke(MeshSettings,'Set','SnapToAxialEdges','1');
invoke(MeshSettings,'Set','SnapToPlanes','1');
invoke(MeshSettings,'Set','SnapToSpheres','1');
invoke(MeshSettings,'Set','SnapToEllipses','1');
invoke(MeshSettings,'Set','SnapToCylinders','1');
invoke(MeshSettings,'Set','SnapToCylinderCenters','1');
invoke(MeshSettings,'Set','SnapToEllipseCenters','1');

Discretizer = invoke(mws,'Discretizer');
invoke(Discretizer,'MeshType','PBA');
invoke(Discretizer,'PBAType','Fast PBA');
invoke(Discretizer,'AutomaticPBAType','True');
invoke(Discretizer,'FPBAAccuracyEnhancement','enable');
invoke(Discretizer,'ConnectivityCheck','False');
invoke(Discretizer,'ConvertGeometryDataAfterMeshing','True');
invoke(Discretizer,'UsePecEdgeModel','True');
invoke(Discretizer,'GapDetection','False');
invoke(Discretizer,'FPBAGapTolerance','1e-3');
invoke(Discretizer,'SetMaxParallelMesherThreads','Hex','12');
invoke(Discretizer,'SetParallelMesherMode','Hex','Maximum');
invoke(Discretizer,'PointAccEnhancement','0');
invoke(Discretizer,'UseSplitComponents','True');
invoke(Discretizer,'EnableSubgridding','False');
invoke(Discretizer,'PBAFillLimit','99');
invoke(Discretizer,'AlwaysExcludePec','False');
end


% pop_snapread() - load an EEG SnapMaster file (pop out window if no arguments).
%
% Usage:
%   >> [dat] = pop_snapread( filename, gain);
%
% Graphic interface:
%   "Relative gain" - [edit box] to compute the relative gain, fisrt look at
%                   the text header of the snapmater file with a text editor.
%                   Find the recording unit, usually in volts (UNITS field).
%                   Then, find the voltage range in the "CHANNEL.RANGE" [cmin cmax]
%                   field. Finally, determine the gain of the amplifiers (directly
%                   on the machine, not in the header file).
%                   Knowing that the recording precision is 12 bits. The folowing
%                   formula
%                                    1/2^12*[cmax-cmin]*1e6/gain
%                   returns the relative gain. You have to compute it and enter
%                   it in the edit box. Enter 1, for preserving the data file units.
%                   (note that if the voltage range is not the same for all channels
%                   or if the CONVERSION.POLY field in the file header
%                   is not "0 + 1x" for all channels,  you will have to load the data
%                   using snapread() and scale manually all channels, then import
%                   the Matlab array into EEGLAB).
%
% Inputs:
%   filename       - SnapMaster file name
%   gain           - relative gain. See graphic interface help.
%
% Outputs:
%   dat            - EEGLAB data structure
%
% Author: Arnaud Delorme, CNL/Salk Institute, 13 March 2002
%
% See also: eeglab(), snapread()

% Copyright (C) 13 March 2002 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [EEG, command] = pop_snapread(filename, gain);
command = '';
EEG = [];

if nargin < 1
	% ask user
	[filename, filepath] = uigetfile('*.SMA', 'Choose a SnapMaster file -- pop_snapread()');
	if filename == 0 return; end;
	filename = [filepath filename];

    promptstr    = { 'Relative gain (see help)' };
    inistr       = { '400' };
    result       = inputdlg2( promptstr, 'Import SnapMaster file -- pop_snapread()', 1,  inistr, 'pop_snapread');
    if length(result) == 0 return; end;
    gain   = eval( result{1} );

end;

if exist('gain') ~= 1
    gain = 1;
end;

% load datas
% ----------
EEG = eeg_emptyset;
[EEG.data,params,events, head] = snapread(filename);

EEG.data            = EEG.data*gain;
EEG.comments        = [ 'Original file: ' filename ];
EEG.filepath        = '';
EEG.setname 		= 'SnapMaster file';
EEG.nbchan          = params(1);
EEG.pnts            = params(2);
EEG.trials          = 1;
EEG.srate           = params(3);
EEG.xmin            = 0;

A = find(events ~= 0);
if ~isempty(A)
    EEG.event = struct( 'type', mattocell(events(A), [1], ones(1,length(events(A)))), ...
                        'latency', mattocell(A(:)', [1], ones(1,length(A))) );
end;

EEG = eeg_checkset(EEG, 'eventconsistency');
EEG = eeg_checkset(EEG, 'makeur');
command = sprintf('EEG = pop_snapread(''%s'', %f);', filename, gain);

return;


classdef imtool3DROI_ellipse < imtool3DROI_rect

    properties (SetAccess = protected, GetAccess = protected)
        nPoints = 20;   %number of points to use to define the polygon that makes the elliptical mask
    end

    methods
        %constructor
        function ROI = imtool3DROI_ellipse(varargin)

            switch nargin
                case 0  %use the current figure

                    %let the user draw the ROI
                    h = imellipse;

                    %get the parent axes
                    ha = get(h,'Parent');

                    %get the handle of the image
                    hi = imhandles(ha);
                    if length(hi)>1
                        for i=1:length(hi)
                            if ndims(get(hi(i),'CData'))<3
                                imageHandle = hi(i);
                            end
                        end
                    else
                        imageHandle = hi;
                    end

                    %get the position
                    pos = getPosition(h);
                    position = [pos(1)+pos(3)/2 pos(2)+pos(4)/2 pos(3) pos(4)];

                    %delete the imroi object
                    delete(h);
                case 1 %user inputs only the handle to the image
                    imageHandle = varargin{1};
                    parent = get(imageHandle,'Parent');
                    h = imellipse(parent);
                    pos = getPosition(h);
                    position = [pos(1)+pos(3)/2 pos(2)+pos(4)/2 pos(3) pos(4)];
                    delete(h);
                case 2 %user inputs both the parent handle and a position
                    imageHandle = varargin{1};
                    position = varargin{2};
                case 3
                    imageHandle = varargin{1};
                    position = varargin{2};
                    if isempty(position)
                        parent = get(imageHandle,'Parent');
                        h = imellipse(parent);
                        pos = getPosition(h);
                        position = [pos(1)+pos(3)/2 pos(2)+pos(4)/2 pos(3) pos(4)];
                        delete(h);
                    end
                    tool = varargin{3};

            end

            %contruct the rect ROI
            if ~exist('tool','var'), tool=[]; end
            ROI@imtool3DROI_rect(imageHandle,position, tool)

            %make the rectangle an ellipse
            set(ROI.graphicsHandles(1),'Curvature',[1 1]);

            %update the position
            newPosition(ROI,position)

            %Set the button down functions of the graphics
            for i=1:length(ROI.graphicsHandles)
                fun = @(hObject,evnt) ButtonDownFunction(hObject,evnt,ROI,i); set(ROI.graphicsHandles(i),'ButtonDownFcn',fun);
            end

        end

        function newPosition(ROI,position)

            %set the position property of the ROI
            ROI.position = position;

            %find the top left corner of the box
            pos = [position(1)-position(3)/2 position(2)-position(4)/2 position(3) position(4)];

            %get the graphics handles
            graphicsHandles = ROI.graphicsHandles;

            %get the corner positions
            t = pi/4:pi/2:2*pi-pi/4;
            [x,y] = getEllipsePoints(position,t,'');

            %set the new position of the rectangle and other graphics
            %objects
            set(graphicsHandles(1),'Position',pos);
            set(graphicsHandles(2),'Xdata',position(1),'Ydata',position(2));
            set(graphicsHandles(3),'Xdata',x(3),'Ydata',y(3));
            set(graphicsHandles(4),'Xdata',x(4),'Ydata',y(4));
            set(graphicsHandles(5),'Xdata',x(2),'Ydata',y(2));
            set(graphicsHandles(6),'Xdata',x(1),'Ydata',y(1));
            set(graphicsHandles(7),'Xdata',pos(1),'Ydata',position(2));
            set(graphicsHandles(8),'Xdata',pos(1)+pos(3),'Ydata',position(2));
            set(graphicsHandles(9),'Xdata',position(1),'Ydata',pos(2));
            set(graphicsHandles(10),'Xdata',position(1),'Ydata',pos(2)+pos(4));

            %get the ROI measurements
            stats = getMeasurements(ROI);

            %set the textbox
            V = get(gca,'View');
            if V(1)==-90
                x = pos(1) + pos(3) + ROI.tbuff;
            else
                x = pos(1);
            end
            y = pos(2)-ROI.tbuff;

            str = {['Mean: ' num2str(stats.mean,'%+.2f')], ['STD:     ' num2str(stats.STD,'%.2f')]};
            set(ROI.textHandle,'String',str,'Position',[x y]);

            %notify a new position
            notify(ROI,'newROIPosition');
        end

        function [x, y] = getPoly(ROI)
            %get the position
            position = ROI.position;

            %find the top left corner of the box
            pos = [position(1)-position(3)/2 position(2)-position(3)/2 position(3) position(4)];

            %make the polygon
            [x,y] = getEllipsePoints(position,ROI.nPoints,'nPoints');
        end

        function stats = getMeasurements(ROI)
            [x, y] = getPoly(ROI);
            im = double(get(ROI.imageHandle,'CData'));

            m = size(im,1);
            n = size(im,2);
            %Scale the polygon to match the size of the displayed image (in
            %the case that the displayed image is being upsampled to match
            %the screen resolution).
            x = x*n/ROI.imageHandle.XData(2);
            y = y*m/ROI.imageHandle.YData(2);
            mask = poly2mask(x,y,m,n);

            im = im(mask);

            stats.mean = mean(im);
            stats.STD = std(im);
            stats.min = min(im);
            stats.max = max(im);
            stats.mask = mask;
            stats.position = ROI.position;

        end

        function varargout = autoCenterROI(ROI,varargin)
            Tforeground = .2;
            Tbackground = .8;
            pos=ROI.position(1:2);
            switch nargin
                case 1
                    weighting = 'pixels';
                    mode = 'normal';
                case 2
                    weighting = varargin{1}; %Weighting can be 'pixels' or 'mask'
                    mode ='normal'; %can be 'normal' or 'force positive contrast';
                case 3
                    weighting = varargin{1};
                    mode = varargin{2};
            end

            %Get the image
            im = double(get(ROI.imageHandle,'CData'));
            %Get coordinate system
            [X, Y]=meshgrid((1:size(im,2))-pos(1),(1:size(im,1))-pos(2));
            R=sqrt((X).^2 +(Y.^2));
            %get the mask
            stats = getMeasurements(ROI);
            mask=stats.mask;

            amin=min(im(mask));
            amax=max(im(mask));
            sim=mat2gray(im,[amin amax]);
            t=graythresh(sim(mask)); %Otsu threshold
            bw=im2bw(sim,t);
            bw=bw & mask;
            %bw=bwareaopen(bw,100);

            switch mode
                case 'force positive contrast'
                    obj=mean(im(bw));
                    bkg=mean(im(~bw & mask));
                case 'normal'
                    bkg=mean(im(mask & R>quantile(R(mask),Tbackground)));
                    obj=mean(im(mask & R<quantile(R(mask),Tforeground)));
                otherwise
                    bkg=mean(im(mask & R>quantile(R(mask),Tbackground)));
                    obj=mean(im(mask & R<quantile(R(mask),Tforeground)));
            end
            contrast=obj-bkg;
            if contrast<0
                bw=~bw & mask;
            end

            if any(bw(:))
                success = true;
                %compute the centroid of the rod
                center=zeros(1,2);
                switch weighting
                    case 'pixels'
                        center(1) = sum(X(bw).*im(bw))/sum(im(bw));
                        center(2) = sum(Y(bw).*im(bw))/sum(im(bw));
                    case 'mask'
                        center(1) = sum(X(bw).*bw(bw))/sum(bw(bw));
                        center(2) = sum(Y(bw).*bw(bw))/sum(bw(bw));
                    otherwise
                        center(1) = sum(X(bw).*im(bw))/sum(im(bw));
                        center(2) = sum(Y(bw).*im(bw))/sum(im(bw));
                end

                position = [center 0 0];
                position=position+ROI.position;
                newPosition(ROI,position);
            else
                success = false;
            end

            switch nargout
                case 1
                    varargout{1} = success;
            end

        end

        function success = autoCenterROIFindCircleMethod(ROI,circleRange)
            rescale=4;
            %Get the image
            im = double(get(ROI.imageHandle,'CData'));
            stats = getMeasurements(ROI);
            mask=stats.mask;

            %Crop the image
            [Yind Xind]=ind2sub(size(im),find(mask(:)));
            im=im(min(Yind):max(Yind),min(Xind):max(Xind));

            %Upsample the image
            im=imresize(im,rescale);

            %Find the circles
            warning('off','images:imfindcircles:warnForLargeRadiusRange')
            center = imfindcircles(im, round(rescale*circleRange),'Sensitivity',.95);
            warning('on','images:imfindcircles:warnForLargeRadiusRange')

            %move the ROI
            if ~isempty(center)
                center=center(1,:);
                success=true;
                center=center/rescale;
                center=center + [min(Xind) min(Yind)];
                position = [center ROI.position(3:4)];
                newPosition(ROI,position);
            else
                success=false;
            end

        end

    end

end

function [x,y] = getEllipsePoints(position,t,mode)
%This function returns a list of vertices of an elliptical polygon with
%nPoints number of vertices;
if strcmp(mode,'nPoints')
    t=linspace(0,2*pi,t); %elliptical equation is parameterized by t
end
a = position(3)/2;
b = position(4)/2;
x = a*cos(t); x = x+position(1);
y = b*sin(t); y = y+position(2);
end

function ButtonDownFunction(hObject,evnt,ROI,n)

%get the parent figure handle
fig = ROI.figureHandle;

%get the type of click
click = get(fig,'SelectionType');

if strcmp(click,'normal')
    %get the current button motion and button up functions of the figure
    WBMF_old = get(fig,'WindowButtonMotionFcn');
    WBUF_old = get(fig,'WindowButtonUpFcn');

    %set the new window button motion function and button up function of the figure
    fun = @(src,evnt) ButtonMotionFunction(src,evnt,ROI,n);
    fun2=@(src,evnt)  ButtonUpFunction(src,evnt,ROI,WBMF_old,WBUF_old);
    set(fig,'WindowButtonMotionFcn',fun,'WindowButtonUpFcn',fun2);
end
end

function ButtonMotionFunction(src,evnt,ROI,n)
cp = get(ROI.axesHandle,'CurrentPoint'); cp=[cp(1,1) cp(1,2)];

position = getPosition(ROI);

switch n
    case 2                                          %middle cross
        position(1) = cp(1); position(2) = cp(2);

    case 3                                          %top left corner
        %find the x and y for the current position
        [x,y] = getEllipsePoints(position,5*pi/4,'');
        dx = x-cp(1); dy = y-cp(2);
        cp(1) = position(1)-(position(3)/2+dx); cp(2) = position(2)-(position(4)/2+dy);

         %find the bottom edge
        bottom = position(2)+position(4)/2;
        %get the new height
        height = bottom - cp(2);
        if height>1
            cy = cp(2)+height/2;
            position(2) = cy;
            position(4) = height;
            %Adjust cp(1) if you want to fix the aspect ratio
            if ROI.fixedAspectRatio
                cp(1) = position(1)+position(3)/2-height*ROI.aspectRatio;
            end
        end
        %find the right edge
        right = position(1)+position(3)/2;
        %find the new width
        width = right-cp(1);
        if width>1
            %find the new center
            cx = cp(1)+width/2;
            position(1) = cx;
            position(3) = width;
        end

    case 4                                          %top right corner
        %find the x and y for the current position
        [x,y] = getEllipsePoints(position,7*pi/4,'');
        dx = cp(1)-x; dy = y-cp(2);
        cp(1) = position(1)+(position(3)/2+dx); cp(2) = position(2)-(position(4)/2+dy);
         %find the bottom edge
        bottom = position(2)+position(4)/2;
        %get the new height
        height = bottom - cp(2);
        if height>1
            cy = cp(2)+height/2;
            position(2) = cy;
            position(4) = height;
            %Adjust cp(1) if you want to fix the aspect ratio
            if ROI.fixedAspectRatio
                cp(1) = position(1)-position(3)/2+height*ROI.aspectRatio;
            end
        end

        %find the left edge
        left = position(1)-position(3)/2;
        %find the new width
        width = cp(1) - left;
        if width>1
            cx = cp(1)-width/2;
            position(1) = cx;
            position(3) = width;
        end

    case 5                                          %bottom left corner
        %find the x and y for the current position
        [x,y] = getEllipsePoints(position,3*pi/4,'');
        dx = x-cp(1); dy = cp(2)-y;
        cp(1) = position(1)-(position(3)/2+dx); cp(2) = position(2)+(position(4)/2+dy);
        %find the top edge
        top = position(2)-position(4)/2;
        %get the new height
        height = cp(2) - top;
        if height>1
            cy = cp(2)-height/2;
            position(2) = cy;
            position(4) = height;
            %Adjust cp(1) if you want to fix the aspect ratio
            if ROI.fixedAspectRatio
                cp(1) = position(1)+position(3)/2+-height*ROI.aspectRatio;
            end
        end

        %find the right edge
        right = position(1)+position(3)/2;
        %find the new width
        width = right-cp(1);
        if width>1
            %find the new center
            cx = cp(1)+width/2;
            position(1) = cx;
            position(3) = width;
        end

    case 6                                          %bottom right corner
        %find the x and y for the current position
        [x,y] = getEllipsePoints(position,pi/4,'');
        dx = cp(1)-x; dy = cp(2)-y;
        cp(1) = position(1)+(position(3)/2+dx); cp(2) = position(2)+(position(4)/2+dy);
        %find the top edge
        top = position(2)-position(4)/2;
        %get the new height
        height = cp(2) - top;
        if height>1
            cy = cp(2)-height/2;
            position(2) = cy;
            position(4) = height;
            %Adjust cp(1) if you want to fix the aspect ratio
            if ROI.fixedAspectRatio
                cp(1) = position(1)-position(3)/2+height*ROI.aspectRatio;
            end
        end

        %find the left edge
        left = position(1)-position(3)/2;
        %find the new width
        width = cp(1) - left;
        if width>1
            cx = cp(1)-width/2;
            position(1) = cx;
            position(3) = width;
        end

    case 7                                          %left
        %find the right edge
        right = position(1)+position(3)/2;
        %find the new width
        width = right-cp(1);
        if width>1
            %find the new center
            cx = cp(1)+width/2;
            position(1) = cx;
            position(3) = width;
        end
        if ROI.fixedAspectRatio
            position(4) = width/ROI.aspectRatio;
        end

    case 8                                          %right
        %find the left edge
        left = position(1)-position(3)/2;
        %find the new width
        width = cp(1) - left;
        if width>1
            cx = cp(1)-width/2;
            position(1) = cx;
            position(3) = width;
        end

        if ROI.fixedAspectRatio
            position(4) = width/ROI.aspectRatio;
        end

    case 9                                          %top
        %find the bottom edge
        bottom = position(2)+position(4)/2;
        %get the new height
        height = bottom - cp(2);
        if height>1
            cy = cp(2)+height/2;
            position(2) = cy;
            position(4) = height;
        end

        if ROI.fixedAspectRatio
            position(3) = height*ROI.aspectRatio;
        end

    case 10                                         %bottom
        %find the top edge
        top = position(2)-position(4)/2;
        %get the new height
        height = cp(2) - top;
        if height>1
            cy = cp(2)-height/2;
            position(2) = cy;
            position(4) = height;
        end

        if ROI.fixedAspectRatio
            position(3) = height*ROI.aspectRatio;
        end

end

newPosition(ROI,position);

end

function ButtonUpFunction(src,evnt,ROI,WBMF_old,WBUF_old)
fig = ROI.figureHandle;

set(fig,'WindowButtonMotionFcn',WBMF_old,'WindowButtonUpFcn',WBUF_old);

end


classdef PatternSearchOptimizer < AbstractOptimizer
    %PatternSearchOptimizer Summary of this class goes here
    %   Detailed explanation goes here

    properties
        options(1,1) PatternSearchOptions = PatternSearchOptions();
    end

    methods
        function obj = PatternSearchOptimizer()
            obj.options = PatternSearchOptions();
        end

        function [exitflag, message] = optimize(obj, lvdOpt, writeOutput, callOutputFcn, hLvdMainGUI)
            [x0All, actVars, varNameStrs] = lvdOpt.vars.getTotalScaledXVector();
            [lbAll, ubAll, lbUsAll, ubUsAll] = lvdOpt.vars.getTotalScaledBndsVector();
%             typicalX = lvdOpt.vars.getTypicalScaledXVector();

            if(isempty(x0All) && isempty(actVars))
                exitflag = 0;
                message = 'No variables enabled on script.  Aborting optimization.';

                return;
            end

            evtNumToStartScriptExecAt = obj.getEvtNumToStartScriptExecAt(lvdOpt, actVars);
            evtToStartScriptExecAt = lvdOpt.lvdData.script.getEventForInd(evtNumToStartScriptExecAt);

            objFuncWrapper = @(x) lvdOpt.objFcn.evalObjFcn(x, evtToStartScriptExecAt);
            nonlcon = @(x) lvdOpt.constraints.evalConstraints(x, true, evtToStartScriptExecAt, true, []);

%             initMeshSize = norm(typicalX)/(10*length(typicalX));
            opts = obj.options.getOptionsForOptimizer(x0All);
%             opts = optimoptions(opts, 'ScaleMesh',scaleMesh, 'UseParallel',usePara, 'InitialMeshSize',initMeshSize);

            problem.objective = objFuncWrapper;
            problem.x0 = x0All;
            problem.Aineq = [];
            problem.bineq = [];
            problem.Aeq = [];
            problem.beq = [];
            problem.lb = lbAll;
            problem.ub = ubAll;
            problem.nonlcon = nonlcon;
            problem.options = opts;
            problem.solver = 'patternsearch';

            problem.lvdData = lvdOpt.lvdData; %need to get lvdData in somehow

            %%% Run optimizer
            celBodyData = lvdOpt.lvdData.celBodyData;
            recorder = ma_OptimRecorder();

            if(callOutputFcn)
                propNames = lvdOpt.lvdData.launchVehicle.tankTypes.getFirstThreeTypesCellArr();
%                 handlesObsOptimGui = ma_ObserveOptimGUI(celBodyData, problem, true, writeOutput, [], varNameStrs, lbUsAll, ubUsAll);

                out = AppDesignerGUIOutput();
                ma_ObserveOptimGUI_App(out);
                handlesObsOptimGui = out.output{1};

                hOptimStatusLabel = handlesObsOptimGui.optimStatusLabel;
                hFinalStateOptimLabel = handlesObsOptimGui.finalStateOptimLabel;
                hDispAxes = handlesObsOptimGui.dispAxesPanel;
                hCancelButton = handlesObsOptimGui.cancelButton;
                optimStartTic = tic();

                outputFnc = @(optimvalues,options,flag) PatternSearchOptimizer.getOutputFunction(optimvalues,options,flag, hOptimStatusLabel, hFinalStateOptimLabel, hDispAxes, hCancelButton, ...
                                                                                problem.objective, problem.lb, problem.ub, celBodyData, recorder, propNames, writeOutput, varNameStrs, lbUsAll, ubUsAll, optimStartTic);
                problem.options.OutputFcn = outputFnc;
            end

            [exitflag, message] = lvd_executeOptimProblem(celBodyData, writeOutput, problem, recorder, callOutputFcn);

            if(callOutputFcn)
                close(handlesObsOptimGui.ma_ObserveOptimGUI);
            end
        end

        function options = getOptions(obj)
            options = obj.options;
        end

        function tf = usesParallel(obj)
            tf = obj.options.useParallel.optionVal;
        end

        function numWorkers = getNumParaWorkers(obj)
            numWorkers = obj.options.getNumParaWorkers();
        end

        function openOptionsDialog(obj)
%             lvd_editPatternSearchOptionsGUI(obj);

            output = AppDesignerGUIOutput({false});
            lvd_editPatternSearchOptionsGUI_App(obj, output);
        end
    end

    methods(Static, Access=private)
        function [stop,options,optchanged] = getOutputFunction(optimValues,options,flag, hOptimStatusLabel, hFinalStateOptimLabel, hDispAxes, hCancelButton, ...
                                                               objFcn, lb, ub, celBodyData, recorder, propNames, writeOutput, varLabels, lbUsAll, ubUsAll, optimStartTic)

            optchanged = false;
            x = optimValues.x;
            maxConstr = PatternSearchOptimizer.getConstrViolation(optimValues);

            switch flag
                case 'iter'
                    stop = get(hCancelButton,'Value');

                    recorder.iterNums(end+1) = optimValues.iteration;
                    recorder.xVals(end+1) = {x};
                    recorder.fVals(end+1) = optimValues.fval;
                    recorder.maxCVal(end+1) = maxConstr;
                case {'init','interrupt','done'}
                    stop = get(hCancelButton,'Value');
            end

            if(stop == true)
                return;
            end

            [~, stateLog] = objFcn(x);

%             finalStateLogEntry = stateLog.getFinalStateLogEntry();
%             finalStateLogEntryMA = finalStateLogEntry.getMAFormattedStateLogMatrix(true);

            stateLogMA = stateLog.getMAFormattedStateLogMatrix(true);

            if(strcmpi(flag,'init') || strcmpi(flag,'iter'))
                PatternSearchOptimizer.writeOptimStatus(hOptimStatusLabel, optimValues, flag, writeOutput, optimStartTic);
                ma_UpdateStateReadout(hFinalStateOptimLabel, 'final', propNames, stateLogMA, celBodyData);
                PatternSearchOptimizer.generatePlots(x, optimValues, flag, hDispAxes, lb, ub, varLabels, lbUsAll, ubUsAll);
                drawnow;
            end
        end

        function writeOptimStatus(hOptimStatusLabel, optimValues, flag, writeOutput, timer)
            elapTime = toc(timer);

            maxConstr = PatternSearchOptimizer.getConstrViolation(optimValues);

            if(length(optimValues.method) > 13)
                method = optimValues.method(1:13);
            else
                method = optimValues.method;
            end

            outStr = {};
            outStr{end+1} = ['State                = ', flag];
            outStr{end+1} = '                        ';
            outStr{end+1} = ['Iterations           = ', num2str(optimValues.iteration)];
            outStr{end+1} = ['Function Evals       = ', num2str(optimValues.funccount)];
            outStr{end+1} = ['Objective Value      = ', num2str(optimValues.fval)];
            outStr{end+1} = ['Constraint Violation = ', num2str(maxConstr)];
            outStr{end+1} = ['Method               = ', method];
            outStr{end+1} = ['Mesh Size            = ', num2str(optimValues.meshsize)];
            outStr{end+1} = '                       ';
            outStr{end+1} = ['Elapsed Time         = ', num2str(elapTime), ' sec'];

            set(hOptimStatusLabel, 'String', outStr);

            switch flag
                case 'iter'
                    formatstr = ' %- 12.1i %- 12.0i %- 12.6g %- 12.3g %- 13s %- 12.3g';

                    iter = optimValues.iteration;
                    fcnt = optimValues.funccount;
                    val  = optimValues.fval;
                    feas = maxConstr;
                    mesh = optimValues.meshsize;

                    hRow = sprintf(formatstr,iter,fcnt,val,feas,method,mesh);
                    writeOutput(hRow,'append');
                case 'init'
                    hdrStr = sprintf('%- 13s%- 13s%- 13s%- 13s%- 13s%- 13s', 'Iteration','Fcn-Count','f(x)-Value', 'Feasibility', 'Method', 'Mesh Size');
                    writeOutput(hdrStr,'append');
            end
        end

        function generatePlots(x, optimValues, flag, hDispAxes, lb, ub, varLabels, lbUsAll, ubUsAll)
            persistent fValPlotIsLog tLayout hPlot1 hPlot2 hPlot3

            if(isempty(fValPlotIsLog))
                fValPlotIsLog = true;
            end

            switch flag
                case 'init'
                    if(isvalid(hDispAxes))
%                         set(hDispAxes,'Visible','on');
%                         subplot(hDispAxes);
%                         axes(hDispAxes);
                        tLayout = tiledlayout(hDispAxes, 3,1);
                    end
                    fValPlotIsLog = true;
            end

            hPlot1 = nexttile(tLayout, 1);
            if(strcmpi(flag,'init'))

                hPlot1.XTickLabel= [];
                hPlot1.YTickLabel= [];
                hPlot1.ZTickLabel= [];
%                 axes(hPlot1);
            else
%                 axes(hPlot1);
            end
            optimplotxKsptot(x, optimValues, flag, lb, ub, varLabels, lbUsAll, ubUsAll);

            hPlot2 = nexttile(tLayout, 2);
            if(strcmpi(flag,'init'))
                hPlot2.XTickLabel= [];
                hPlot2.YTickLabel= [];
                hPlot2.ZTickLabel= [];
                h = hPlot2;
            else
                h = hPlot2;
%                 axes(hPlot2);
            end
            if(optimValues.fval<=0)
                fValPlotIsLog = false;
                set(h,'yscale','linear');
            end
            psplotbestf(optimValues, flag);
            if(fValPlotIsLog)
                set(h,'yscale','log');
            else
                set(h,'yscale','linear');
            end
            grid on;
            grid minor;

            hPlot3 = nexttile(tLayout, 3);
            if(strcmpi(flag,'init'))
                hPlot3.XTickLabel= [];
                hPlot3.YTickLabel= [];
                hPlot3.ZTickLabel= [];
                h = hPlot3;
            else
                h = hPlot3;
%                 axes(hPlot3);
            end
            psplotmaxconstr(optimValues, flag);

            if(not(isempty(h.Children)))
                hLine = h.Children(1);
                if(isa(hLine,'matlab.graphics.chart.primitive.Line'))
                    yDataLine = hLine.YData;
                    if(abs(max(yDataLine) / min(yDataLine)) >= 10 && all(yDataLine > 0))
                        set(h,'yscale','log');
                    else
                        set(h,'yscale','linear');
                    end
                else
                    set(h,'yscale','linear');
                end
            end

            grid on;
            grid minor;
        end

        function maxConstr = getConstrViolation(optimValues)
            if(not(isfield(optimValues,'nonlinineq')))
                optimValues.nonlinineq = [];
            end

            if(not(isfield(optimValues,'nonlineq')))
                optimValues.nonlineq = [];
            end

            maxConstr = max([max(abs(optimValues.nonlinineq)), max(abs(optimValues.nonlineq))]);

            if(isempty(maxConstr))
                maxConstr = 0;
            end
        end
    end
end


function [newF,cData] = surface_outlines(plotdat,patchobj,colmap)

% helper function to compute the borders of ROIs on surface data
%
% input:
%
% plotdat   - cell array (1x2) with the data to plot for a single
%             hemisphere in each cell.
%             plotdat{1} = left hemisphere, plotdat{2} = right hemisphere
%
% patchobj  - cell array (1x2) containing the patch objects for left {1}
%             and right {2} hemispheres. Only need the Face and Vertex info
%             here, so could be structs in the cells.
%             e.g. patchobj{hem}.Faces = yourFaces;
%             patchobj{hem}.Vertices = yourVertices;
%
% colmap    - colormap to color the ROI outlines with. Can also be a single
%             color for all borders (e.g. [0.2 0.2 0.2]).
%
% output:
%
% newF      - the new Faces containing only the outline faces around each ROI
%
% cData     - the color information for the new outline faces. use with
%             patch as patch(...,'FaceVertexCdata',cData)
%
%
%  Examples:
%  % make surface figure
%  h = make_surface_figure('surfacefiles',surffiles);
%  [outlineF, outlineCData] = surface_outlines({ldat,rdat},{h.obj(1),h.obj(2)}, [0 0 0]);
%  % left lateral hem
%  patch(h.ax(1),'Faces',outlineF{1},'Vertices',h.obj(1).Vertices,'FaceVertexCData',outlineCData{1},...,
%         'FaceColor',fcolormode,'EdgeColor','none','SpecularStrength',.2,'FaceAlpha',facealpha,'SpecularExponent',200);
%  % right lateral hem
%  patch(h.ax(3),'Faces',outlineF{2},'Vertices',h.obj(3).Vertices,'FaceVertexCData',outlineCData{2},...,
%         'FaceColor',fcolormode,'EdgeColor','none','SpecularStrength',.2,'FaceAlpha',facealpha,'SpecularExponent',200);
%
%
%
% ..
%     Author and copyright information:
%     -------------------------------------------------------------------------
%     Copyright (C) 2018 Stephan Geuter
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.
% ..
%

%
% ..
%    Programmers' notes:
%    List dates and changes here, and author of changes
%
%   3/30/2018 - created
%   Stephan Geuter, sgeuter@jhmi.edu
%

% regionIDs = [199 214 280 360  20 100 170];
% col = lines(numel(regionIDs));
%

% loop hemispheres
for hem=1:2

    % get data for this hemisphere
    atlasDat = plotdat{hem};
    atlasDat(isnan(atlasDat)) = 0;

    % get Faces, Vertices of the brain surface
    F = patchobj{hem}.Faces;
    V = patchobj{hem}.Vertices;

    % unique ROI/blob ID's
    hemRegions = unique(atlasDat(isfinite(atlasDat)));

    newF{hem}  = double.empty(0,3);
    cData{hem} = double.empty(0,3);

    % loop ROIs
    for r=1:numel(hemRegions)

        % find the vertices that belong to the current ROI
        idx = atlasDat .* single(ismember(atlasDat,hemRegions(r)));

        if numel(unique(idx))>1 && any(unique(idx)~=0)
            % compute the new Faces
            Fclasses = idx(F);
            roiFace  = F(any(diff(Fclasses,1,2),2) , :);

            % get color for current ROI outline
            if size(colmap,1) == 1
                roiCol   = repmat(colmap,size(roiFace,1),1);
            else
                roiCol   = repmat(colmap(hemRegions(r),:),size(roiFace,1),1);
            end

            % cat data across ROIs
            newF{hem} = vertcat(newF{hem},roiFace);
            cData{hem}= vertcat(cData{hem},roiCol);
        end
    end

%     for j=find(cellregexp(h.label,hemstr))
%         hp(j) = patch(h.ax(j),'Faces',newF{hem},'Vertices',V,'FaceColor','flat',...
%             'Edgecolor','none','FaceVertexCdata',cData{hem},...
%             'SpecularStrength',.2,'SpecularExponent',200);
%         material(hp(j),'dull');
%         lighting(h.ax(j),'gouraud');
%     end
end


function proposals= calcEdgeBoxesForIm( input, ebconfig )
rmpath(genpath([pwd '/rigor']));
rmpath(genpath([pwd '/mcg/']));
if(isstr(input))
	im = im2double(imread(input));
else
        im = im2double(input); % Just to make input consistent
end
if(size(im, 3) == 1)
        im=repmat(im,[1,1,3]);
end
% load pre-trained edge detection model and set opts
if(~exist(ebconfig.modelPath))
    fprintf('Path to model does not exist. Please make sure you give a proper full path\n');
    return;
end

model = load(ebconfig.modelPath);
model = model.model;
model.opts.multiscale = 0;
model.opts.sharpen = 2;
model.opts.nThread = 4;

%Write code to set options
% call edgeBoxes() to get back options

opts = edgeBoxes();
bbs=edgeBoxes(im,model,opts);
if(isfield((ebconfig.opts),'numProposals'))
	numProposals=ebconfig.opts.numProposals;
        if(size(bbs,1)>=numProposals)
       	        bbs=bbs(1:numProposals);
       	else
               	fprintf('Only %d proposals were generated for input image.\n',size(bbs,1));
        end
end
%edges boxes produces baoxes as "[x y w, h]"
%we convert to [x y x+w y+h]==[xmin ymin xmax ymax]
boxes=bbs(:,1:4);
boxes=[boxes(:,1) boxes(:,2) boxes(:,1)+ boxes(:,3) boxes(:,2)+boxes(:,4)];
proposals.boxes= boxes;
proposals.scores = bbs(:,5);

addpath(genpath([pwd '/mcg/']));
addpath(genpath([pwd '/rigor']));
end


function [features, gparams, feature_info] = init_features(features, gparams, is_color_image, img_sample_sz, size_mode)

if nargin < 3
    size_mode = 'same';
end

% Set missing global parameters to default values
if ~isfield(gparams, 'normalize_power')
    gparams.normalize_power = [];
end
if ~isfield(gparams, 'normalize_size')
    gparams.normalize_size = true;
end
if ~isfield(gparams, 'normalize_dim')
    gparams.normalize_dim = false;
end
if ~isfield(gparams, 'square_root_normalization')
    gparams.square_root_normalization = false;
end
if ~isfield(gparams, 'use_gpu')
    gparams.use_gpu = false;
end

% find which features to keep
feat_ind = false(length(features),1);
for n = 1:length(features)

    if ~isfield(features{n}.fparams,'useForColor')
        features{n}.fparams.useForColor = true;
    end

    if ~isfield(features{n}.fparams,'useForGray')
        features{n}.fparams.useForGray = true;
    end

    if (features{n}.fparams.useForColor && is_color_image) || (features{n}.fparams.useForGray && ~is_color_image)
        % keep feature
        feat_ind(n) = true;
    end
end

% remove features that are not used
features = features(feat_ind);

num_features = length(features);

feature_info.min_cell_size = zeros(num_features,1);

% Initialize features by
% - setting the dimension (nDim)
% - specifying if a cell array is returned (is_cell)
% - setting default values of missing feature-specific parameters
% - loading and initializing necessary data (e.g. the lookup table or the network)
for k = 1:length(features)
    if isequal(features{k}.getFeature, @get_fhog)
        if ~isfield(features{k}.fparams, 'nOrients')
            features{k}.fparams.nOrients = 9;
        end
        features{k}.fparams.nDim = 3*features{k}.fparams.nOrients+5-1;
        features{k}.is_cell = false;
        features{k}.is_cnn = false;

    elseif isequal(features{k}.getFeature, @get_table_feature)
        table = load(['lookup_tables/' features{k}.fparams.tablename]);
        features{k}.fparams.nDim = size(table.(features{k}.fparams.tablename),2);
        features{k}.is_cell = false;
        features{k}.is_cnn = false;

    elseif isequal(features{k}.getFeature, @get_colorspace)
        features{k}.fparams.nDim = 1;
        features{k}.is_cell = false;
        features{k}.is_cnn = false;

    elseif isequal(features{k}.getFeature, @get_cnn_layers) || isequal(features{k}.getFeature, @get_OFcnn_layers)
        % make sure the layers are correcly sorted
        features{k}.fparams.output_layer = sort(features{k}.fparams.output_layer);

        % Set default parameters
        if ~isfield(features{k}.fparams, 'input_size_mode')
            features{k}.fparams.input_size_mode = 'adaptive';
        end
        if ~isfield(features{k}.fparams, 'input_size_scale')
            features{k}.fparams.input_size_scale = 1;
        end
        if ~isfield(features{k}.fparams, 'downsample_factor')
            features{k}.fparams.downsample_factor = ones(1, length(features{k}.fparams.output_layer));
        end

        % load the network
        net = load_cnn(features{k}.fparams, img_sample_sz);

        % find the dimensionality of each layer
        features{k}.fparams.nDim = net.info.dataSize(3, features{k}.fparams.output_layer+1)';

        % find the stride of the layers
        if isfield(net.info, 'receptiveFieldStride')
            net_info_stride = cat(2, [1; 1], net.info.receptiveFieldStride);
        else
            net_info_stride = [1; 1];
        end

        % compute the cell size of the layers (takes down-sampling factor
        % into account)
        features{k}.fparams.cell_size = net_info_stride(1, features{k}.fparams.output_layer+1)' .* features{k}.fparams.downsample_factor';

        % this feature will always return a cell array
        features{k}.is_cell = true;
        features{k}.is_cnn = true;
    elseif isequal(features{k}.getFeature,@get_eitel_cnn)
        features{k}.fparams = make_eitel_feature(features{k}.fparams);
    else
        error('Unknown feature type');
    end

    % Set default cell size
    if ~isfield(features{k}.fparams, 'cell_size')
        features{k}.fparams.cell_size = 1;
    end

    % Set default penalty
    if ~isfield(features{k}.fparams, 'penalty')
        features{k}.fparams.penalty = zeros(length(features{k}.fparams.nDim),1);
    end

    % Find the minimum cell size of each layer
    feature_info.min_cell_size(k) = min(features{k}.fparams.cell_size);
end

% Order the features in increasing minimal cell size
[~, feat_ind] = sort(feature_info.min_cell_size);
features = features(feat_ind);
feature_info.min_cell_size = feature_info.min_cell_size(feat_ind);

% Set feature info
feature_info.dim_block = cell(num_features,1);
feature_info.penalty_block = cell(num_features,1);

for k = 1:length(features)
    % update feature info
    feature_info.dim_block{k} = features{k}.fparams.nDim;
    feature_info.penalty_block{k} = features{k}.fparams.penalty(:);
end
% Feature info for each cell block
feature_info.dim = cell2mat(feature_info.dim_block);
feature_info.penalty = cell2mat(feature_info.penalty_block);

% Find if there is any CNN feature
cnn_feature_ind = -1;
for k = 1:length(features)
    if features{k}.is_cnn
        cnn_feature_ind = k;
    end
end

% This ugly code sets the image sample size to be used for extracting the
% features. It then computes the data size (size of the features) and the
% image support size (the corresponding size in the image).
if cnn_feature_ind > 0
    scale = features{cnn_feature_ind}.fparams.input_size_scale;

    new_img_sample_sz = img_sample_sz;

    % First try decrease one
    net_info = net.info;

    if ~strcmpi(size_mode, 'same') && strcmpi(features{cnn_feature_ind}.fparams.input_size_mode, 'adaptive')
        orig_sz = net.info.dataSize(1:2,end)' / features{cnn_feature_ind}.fparams.downsample_factor(end);

        if strcmpi(size_mode, 'exact')
            desired_sz = orig_sz + 1;
        elseif strcmpi(size_mode, 'odd_cells')
            desired_sz = orig_sz + 1 + mod(orig_sz,2);
        end

        while desired_sz(1) > net_info.dataSize(1,end)
            new_img_sample_sz = new_img_sample_sz + [1, 0];
            net_info = vl_simplenn_display(net, 'inputSize', [round(scale * new_img_sample_sz), 3 1]);
        end
        while desired_sz(2) > net_info.dataSize(2,end)
            new_img_sample_sz = new_img_sample_sz + [0, 1];
            net_info = vl_simplenn_display(net, 'inputSize', [round(scale * new_img_sample_sz), 3 1]);
        end
    end

    feature_info.img_sample_sz = round(new_img_sample_sz);

    if strcmpi(features{cnn_feature_ind}.fparams.input_size_mode, 'adaptive')
        features{cnn_feature_ind}.img_input_sz = feature_info.img_sample_sz;
    else
        features{cnn_feature_ind}.img_input_sz = net.meta.normalization.imageSize(1:2);
    end

    % Sample size to be input to the net
    scaled_sample_sz = round(scale * features{cnn_feature_ind}.img_input_sz);

    if isfield(net_info, 'receptiveFieldStride')
        net_info_stride = cat(2, [1; 1], net_info.receptiveFieldStride);
    else
        net_info_stride = [1; 1];
    end

    net_stride = net_info_stride(:, features{cnn_feature_ind}.fparams.output_layer+1)';
    total_feat_sz = net_info.dataSize(1:2, features{cnn_feature_ind}.fparams.output_layer+1)';

    shrink_number = max(2 * ceil((net_stride(end,:) .* total_feat_sz(end,:) - scaled_sample_sz) ./ (2 * net_stride(end,:))), 0);

    deepest_layer_sz = total_feat_sz(end,:) - shrink_number;
    scaled_support_sz = net_stride(end,:) .* deepest_layer_sz;

    % Calculate output size for each layer
    cnn_output_sz = round(bsxfun(@rdivide, scaled_support_sz, net_stride));
    features{cnn_feature_ind}.fparams.start_ind = floor((total_feat_sz - cnn_output_sz)/2) + 1;
    features{cnn_feature_ind}.fparams.end_ind = features{cnn_feature_ind}.fparams.start_ind + cnn_output_sz - 1;

    feature_info.img_support_sz = round(scaled_support_sz .* feature_info.img_sample_sz ./ scaled_sample_sz);

    % Set the input size
    features{cnn_feature_ind}.fparams.net = set_cnn_input_size(net, feature_info.img_sample_sz);

    if gparams.use_gpu
        if isempty(gparams.gpu_id)
            gpuDevice();
        elseif gparams.gpu_id > 0
            gpuDevice(gparams.gpu_id);
        end
        features{cnn_feature_ind}.fparams.net = vl_simplenn_move(features{cnn_feature_ind}.fparams.net, 'gpu');
    end
else
    max_cell_size = max(feature_info.min_cell_size);

    if strcmpi(size_mode, 'same')
        feature_info.img_sample_sz = round(img_sample_sz);
    elseif strcmpi(size_mode, 'exact')
        feature_info.img_sample_sz = round(img_sample_sz / max_cell_size) * max_cell_size;
    elseif strcmpi(size_mode, 'odd_cells')
        new_img_sample_sz = (1 + 2*round(img_sample_sz / (2*max_cell_size))) * max_cell_size;

        % Check the size with the largest number of odd dimensions (choices in the
        % third dimension)
        feature_sz_choices = floor(bsxfun(@rdivide, bsxfun(@plus, new_img_sample_sz, reshape(0:max_cell_size-1, 1, 1, [])), feature_info.min_cell_size));
        num_odd_dimensions = sum(sum(mod(feature_sz_choices, 2) == 1, 1), 2);
        [~, best_choice] = max(num_odd_dimensions(:));
        pixels_added = best_choice - 1;
        feature_info.img_sample_sz = round(new_img_sample_sz + pixels_added);
    else
        error('Unknown size_mode');
    end

    % Setting the feature size and support size
    %     feature_info.data_sz = floor(bsxfun(@rdivide, feature_info.img_sample_sz, feature_info.min_cell_size));
    feature_info.img_support_sz = feature_info.img_sample_sz;
end

% Set the sample size and data size for each feature
feature_info.data_sz_block = cell(num_features,1);
for k = 1:length(features)
    if features{k}.is_cnn
        % CNN features have a different sample size, since the receptive
        % field is often larger than the support size
        features{k}.img_sample_sz = feature_info.img_sample_sz(:)';

        % Set the data size based on the computed output size
        feature_info.data_sz_block{k} = floor(bsxfun(@rdivide, cnn_output_sz, features{k}.fparams.downsample_factor'));
    else
        % implemented classic features always have the same sample and
        % support size
        features{k}.img_sample_sz = feature_info.img_support_sz(:)';
        features{k}.img_input_sz = features{k}.img_sample_sz;

        % Set data size based on cell size
        feature_info.data_sz_block{k} = floor(bsxfun(@rdivide, features{k}.img_sample_sz, features{k}.fparams.cell_size));
    end
end

feature_info.data_sz = cell2mat(feature_info.data_sz_block);


function retPhases = atlasEstimatePhases(vw, areaCorners, scanNum, fieldName)
% Define retinotopy phases for an angle and wedge map
%
%   retPhases = atlasEstimatePhases(vw, areaCorners, scanNum, fieldName)
%
% Lets the user interactively define the data phases corresponding to the
% fovea, periphery, upper and lower vertical meridians for the atlas and
% data fits.
%
% scanNum is the scan number of the wedge and ring in this view (and for
% the view's selected data type). fieldName is a 1 x 2 cell array
% specifying the field containing the polar angle and eccentricity data,
% respectively. (For PRF analyses, these are not necessarily loaded into
% the phase slot.)
%
if notDefined('fieldName'),		fieldName = {'ph' 'ph'};			end

nAreas = length(areaCorners);
for ii=1:nAreas
    corners = areaCorners{ii};
    retPhases(ii,1) = atlasEstimateBoundaryPhases(vw, corners(1,:), ...
							corners(2,:), scanNum(1), fieldName{1});
    retPhases(ii,2) = atlasEstimateBoundaryPhases(vw, corners(3,:), ...
							corners(4,:), scanNum(1), fieldName{1});
    retPhases(ii,3) = atlasEstimateBoundaryPhases(vw, corners(1,:), ...
							corners(4,:), scanNum(2), fieldName{2});
    retPhases(ii,4) = atlasEstimateBoundaryPhases(vw, corners(2,:), ...
							corners(3,:), scanNum(2), fieldName{2});
end

if nAreas > 1, retPhases = meanPhase(retPhases); end

%% this part of the code seems to attempt to adjust the phase difference
%% between the stored data in the flat view, and real world units. A couple
%% comments / points of confusion here:
%% (1) It seems that things would be much simplified if the downstream code
%% to this function dealt exclusively with data already in real-world
%% units.
%% (2) for traveling-wave data, the functions polarAngle and eccentricity
%% map between phase and real-world units. Perhaps this should be used?
%% (3) for pRF data, the loaded data are already in real world units.
%% (4) what exactly do the retPhases do?
%% ras, 04/09.
prompt = {'Foveal', 'Peripheral', 'Lower Phase (angle map)'};
def = {num2str(retPhases(1)), num2str(retPhases(2)), num2str(retPhases(3))};
dlgTitle = 'Adjust retinal phase estimates';
lineNo = 1;
answer = inputdlg(prompt, dlgTitle, lineNo, def);

% adjust the retPhases based on the user response
angleShift = retPhases(3) - str2double(answer{3});
for ii=1:3, retPhases(ii) = str2double(answer{ii}); end

% We shift the fourth (UVM) by the same amount as the LVM
retPhases(4) = retPhases(4) - angleShift;

return;

%----------------------------------------------------
function meanPh = atlasEstimateBoundaryPhases(vw, p1, p2, scanNum, fieldName)
%
%   meanPh = atlasEstimateBoundaryPhases(vw, p1, p2, scanNum, fieldName)
%
% Author:  Wandell
% Purpose:
%     Estimate the average phase along a line between two points.  This
%     code is used to provide first estimates of the foveal, peripheral,
%     UVM and LVM phase in building atlases.
%
% Example:
%
%   scanNum = 1
%   retPhase(1)= atlasEstimateBoundaryPhases(vw,corners(1,:),corners(2,:),scanNum);
%
%
% ras 04/2009:  allows the field to be passed as a parameter -- not only
% confined to phase field, and doesn't require multiple different scans for
% polar angle / eccentricity. This is critical for use with pRF models.

curSlice = viewGet(vw, 'Current Slice');
[x, y] = findLinePoints([p1(1) p1(2)], [p2(1) p2(2)]);

newCoords = zeros(3,length(x));
newCoords(1,:) = y;
newCoords(2,:) = x;
newCoords(3,:) = curSlice*ones(1,length(x));

% Convert coords to canonical frame of reference
newCoords = curOri2CanOri(vw, newCoords);
ph = getCurDataROI(vw, fieldName, scanNum, newCoords);
if ~isequal( lower(fieldName), 'ph' )
	% put the data into the range [0 2*pi].
	% there may be a chance that it is not correct that the ph data span
	% this range -- for instance, if someone provides polar angle data in a
	% different field. I should deal with this contingency, but it might be
	% even better to have the downstream code deal with real-world-unit
	% data, and leave the conversion to these units up to the user before
	% entering this function (ras 04/09)...
	ph = normalize(ph, 0, 2*pi);
end
cxph = exp(sqrt(-1)*ph);

% We add pi to the output so that the variables run from [0,2pi] instead of
% from [-pi,pi].  This is consistent with mrLoadRet encoding of phase.
meanPh = angle(mean(cxph));

if meanPh < 0, meanPh = meanPh + 2*pi; end
if meanPh > 2*pi, meanPh = meanPh - 2*pi; end

return;


function bmu_colors=som_bmucolor(bmus, m, colors)

% SOM_BMUCOLOR Returns the colors of the bmus according to a map colorcode
%
% bmu_colors=som_bmucolor(bmus, msize, colors);
%
% INPUT ARGUMENTS ([]'s are optional)
%
% bmus   (matrix) Nx1 vector of BMU indexes
% msize  (map struct, topol struct or 1x2 vector)
%          gives the map grid size
% colors (matrix) colormap(s): munits x 3 x d matrix of RGB vectors
%
% OUTPUT ARGUMENTS
%
% bmu_colors (Nx3xd matrix) color of the data point according to its BMU's
%              color(s).
%
% Idea is to get a color for each data point that links it to its BMU.
%
% EXAMPLE
%
% We want to show how an time series is projected  to a map. Instead of
% a trajectory, we use 'color linking'
%
% map=som_make(multi_dim_signal);
% bmus=som_bmu(map,multi_dim_signal);
% Colors=som_bmucolor(bmus, map, som_colorcode(map,'rgb1'));
% colorsignal(Colors, multi_dim_signal);
%
% See also SOM_COLORCODE.

% Copyright (c) 1999-2000 by the SOM toolbox programming team.
% http://www.cis.hut.fi/projects/somtoolbox/

% Version 2.0alpha Johan 170699

%% Check arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

error(nargchk(3, 3, nargin))   % check no. of input args is correct

% Check map grid size

if vis_valuetype(m,{'1x2'}),
  msize=m;
else
  [tmp,ok,tmp]=som_set(m);
  if isstruct(m) && all(ok)        % check m type
    switch m.type
    case 'som_topol'
      msize=m.msize;
      lattice=m.lattice;
    case 'som_map'
      msize=m.topol.msize;
      lattice=m.topol.lattice;
    otherwise
      error('Invalid map or topol struct.');
    end
  end
end

if length(msize)>2
  error('Only 2D maps allowed!');
end

n=prod(msize)

% Check colorcode size

if ~vis_valuetype(colors,{'nx3xdimrgb','nx3rgb'})
  error('Colorcode matrix not valid!');
end

% Check bmu vector

if ~vis_valuetype(bmus,{'nx1'}),
  error('Need a column vector of BMU indexes!');
else
  bmus=round(bmus);
  if max(bmus) > n || min(bmus) < 1
    error('BMU indexes exeed the map size!')
  end
end

%% Action %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bmu_c=colors(bmus,:,:);

%% Build output %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bmu_colors=squeeze(bmu_c);


function [scores, maxlabel] = classification_demo(im, use_gpu)
% [scores, maxlabel] = classification_demo(im, use_gpu)
%
% Image classification demo using BVLC CaffeNet.
%
% IMPORTANT: before you run this demo, you should download BVLC CaffeNet
% from Model Zoo (http://caffe.berkeleyvision.org/model_zoo.html)
%
% ****************************************************************************
% For detailed documentation and usage on Caffe's Matlab interface, please
% refer to Caffe Interface Tutorial at
% http://caffe.berkeleyvision.org/tutorial/interfaces.html#matlab
% ****************************************************************************
%
% input
%   im       color image as uint8 HxWx3
%   use_gpu  1 to use the GPU, 0 to use the CPU
%
% output
%   scores   1000-dimensional ILSVRC score vector
%   maxlabel the label of the highest score
%
% You may need to do the following before you start matlab:
%  $ export LD_LIBRARY_PATH=/opt/intel/mkl/lib/intel64:/usr/local/cuda-5.5/lib64
%  $ export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6
% Or the equivalent based on where things are installed on your system
%
% Usage:
%  im = imread('../../examples/images/cat.jpg');
%  scores = classification_demo(im, 1);
%  [score, class] = max(scores);
% Five things to be aware of:
%   caffe uses row-major order
%   matlab uses column-major order
%   caffe uses BGR color channel order
%   matlab uses RGB color channel order
%   images need to have the data mean subtracted

% Data coming in from matlab needs to be in the order
%   [width, height, channels, images]
% where width is the fastest dimension.
% Here is the rough matlab for putting image data into the correct
% format in W x H x C with BGR channels:
%   % permute channels from RGB to BGR
%   im_data = im(:, :, [3, 2, 1]);
%   % flip width and height to make width the fastest dimension
%   im_data = permute(im_data, [2, 1, 3]);
%   % convert from uint8 to single
%   im_data = single(im_data);
%   % reshape to a fixed size (e.g., 227x227).
%   im_data = imresize(im_data, [IMAGE_DIM IMAGE_DIM], 'bilinear');
%   % subtract mean_data (already in W x H x C with BGR channels)
%   im_data = im_data - mean_data;

% If you have multiple images, cat them with cat(4, ...)

% Add caffe/matlab to you Matlab search PATH to use matcaffe
if exist('../+caffe', 'dir')
  addpath('..');
else
  error('Please run this demo from caffe/matlab/demo');
end

% Set caffe mode
if exist('use_gpu', 'var') && use_gpu
  caffe.set_mode_gpu();
  gpu_id = 0;  % we will use the first gpu in this demo
  caffe.set_device(gpu_id);
else
  caffe.set_mode_cpu();
end

% Initialize the network using BVLC CaffeNet for image classification
% Weights (parameter) file needs to be downloaded from Model Zoo.
model_dir = '../../models/bvlc_reference_caffenet/';
net_model = [model_dir 'deploy.prototxt'];
net_weights = [model_dir 'bvlc_reference_caffenet.caffemodel'];
phase = 'test'; % run with phase test (so that dropout isn't applied)
if ~exist(net_weights, 'file')
  error('Please download CaffeNet from Model Zoo before you run this demo');
end

% Initialize a network
net = caffe.Net(net_model, net_weights, phase);

if nargin < 1
  % For demo purposes we will use the cat image
  fprintf('using caffe/examples/images/cat.jpg as input image\n');
  im = imread('../../examples/images/cat.jpg');
end

% prepare oversampled input
% input_data is Height x Width x Channel x Num
tic;
input_data = {prepare_image(im)};
toc;

% do forward pass to get scores
% scores are now Channels x Num, where Channels == 1000
tic;
% The net forward function. It takes in a cell array of N-D arrays
% (where N == 4 here) containing data of input blob(s) and outputs a cell
% array containing data from output blob(s)
scores = net.forward(input_data);
toc;

scores = scores{1};
scores = mean(scores, 2);  % take average scores over 10 crops

[~, maxlabel] = max(scores);

% call caffe.reset_all() to reset caffe
caffe.reset_all();

% ------------------------------------------------------------------------
function crops_data = prepare_image(im)
% ------------------------------------------------------------------------
% caffe/matlab/+caffe/imagenet/ilsvrc_2012_mean.mat contains mean_data that
% is already in W x H x C with BGR channels
d = load('../+caffe/imagenet/ilsvrc_2012_mean.mat');
mean_data = d.mean_data;
IMAGE_DIM = 256;
CROPPED_DIM = 227;

% Convert an image returned by Matlab's imread to im_data in caffe's data
% format: W x H x C with BGR channels
im_data = im(:, :, [3, 2, 1]);  % permute channels from RGB to BGR
im_data = permute(im_data, [2, 1, 3]);  % flip width and height
im_data = single(im_data);  % convert from uint8 to single
im_data = imresize(im_data, [IMAGE_DIM IMAGE_DIM], 'bilinear');  % resize im_data
im_data = im_data - mean_data;  % subtract mean_data (already in W x H x C, BGR)

% oversample (4 corners, center, and their x-axis flips)
crops_data = zeros(CROPPED_DIM, CROPPED_DIM, 3, 10, 'single');
indices = [0 IMAGE_DIM-CROPPED_DIM] + 1;
n = 1;
for i = indices
  for j = indices
    crops_data(:, :, :, n) = im_data(i:i+CROPPED_DIM-1, j:j+CROPPED_DIM-1, :);
    crops_data(:, :, :, n+5) = crops_data(end:-1:1, :, :, n);
    n = n + 1;
  end
end
center = floor(indices(2) / 2) + 1;
crops_data(:,:,:,5) = ...
  im_data(center:center+CROPPED_DIM-1,center:center+CROPPED_DIM-1,:);
crops_data(:,:,:,10) = crops_data(end:-1:1, :, :, 5);


function out = isMisorientation(o)
% check whether o is a misorientation

out = isa(o.SS,'crystalSymmetry') && isa(o.CS,'crystalSymmetry');


function pesq_mos= pesq_psychoacoustic_model (ref_data, ref_Nsamples, deg_data, ...
    deg_Nsamples )

global CALIBRATE Nfmax Nb Sl Sp
global nr_of_hz_bands_per_bark_band centre_of_band_bark
global width_of_band_hz centre_of_band_hz width_of_band_bark
global pow_dens_correction_factor abs_thresh_power
global Downsample SEARCHBUFFER DATAPADDING_MSECS Fs Nutterances
global Utt_Start Utt_End Utt_Delay NUMBER_OF_PSQM_FRAMES_PER_SYLLABE
global Fs Plot_Frame

% Plot_Frame= 75; % this is the frame whose spectrum will be plotted

FALSE= 0;
TRUE= 1;
NUMBER_OF_PSQM_FRAMES_PER_SYLLABE= 20;

maxNsamples = max (ref_Nsamples, deg_Nsamples);
Nf = Downsample * 8;
MAX_NUMBER_OF_BAD_INTERVALS = 1000;

start_frame_of_bad_interval= zeros( 1, MAX_NUMBER_OF_BAD_INTERVALS);
stop_frame_of_bad_interval= zeros( 1, MAX_NUMBER_OF_BAD_INTERVALS);
start_sample_of_bad_interval= zeros( 1, MAX_NUMBER_OF_BAD_INTERVALS);
stop_sample_of_bad_interval= zeros( 1, MAX_NUMBER_OF_BAD_INTERVALS);
number_of_samples_in_bad_interval= zeros( 1, MAX_NUMBER_OF_BAD_INTERVALS);
delay_in_samples_in_bad_interval= zeros( 1, MAX_NUMBER_OF_BAD_INTERVALS);
number_of_bad_intervals= 0;
there_is_a_bad_frame= FALSE;

Whanning= hann( Nf, 'periodic');
Whanning= Whanning';

D_POW_F = 2;
D_POW_S = 6;
D_POW_T = 2;
A_POW_F = 1;
A_POW_S = 6;
A_POW_T = 2;
D_WEIGHT= 0.1;
A_WEIGHT= 0.0309;

CRITERIUM_FOR_SILENCE_OF_5_SAMPLES = 500;
samples_to_skip_at_start = 0;
sum_of_5_samples= 0;
while ((sum_of_5_samples< CRITERIUM_FOR_SILENCE_OF_5_SAMPLES) ...
        && (samples_to_skip_at_start < maxNsamples / 2))
    sum_of_5_samples= sum( abs( ref_data( samples_to_skip_at_start...
        + SEARCHBUFFER * Downsample + 1: samples_to_skip_at_start...
        + SEARCHBUFFER * Downsample + 5)));

    if (sum_of_5_samples< CRITERIUM_FOR_SILENCE_OF_5_SAMPLES)
        samples_to_skip_at_start = samples_to_skip_at_start+ 1;
    end
end
% fprintf( 'samples_to_skip_at_start is %d\n', samples_to_skip_at_start);

samples_to_skip_at_end = 0;
sum_of_5_samples= 0;
while ((sum_of_5_samples< CRITERIUM_FOR_SILENCE_OF_5_SAMPLES) ...
        && (samples_to_skip_at_end < maxNsamples / 2))
    sum_of_5_samples= sum( abs( ref_data( maxNsamples - ...
        SEARCHBUFFER* Downsample + DATAPADDING_MSECS* (Fs/ 1000) ...
        - samples_to_skip_at_end - 4: maxNsamples - ...
        SEARCHBUFFER* Downsample + DATAPADDING_MSECS* (Fs/ 1000) ...
        - samples_to_skip_at_end)));
    if (sum_of_5_samples< CRITERIUM_FOR_SILENCE_OF_5_SAMPLES)
        samples_to_skip_at_end = samples_to_skip_at_end+ 1;
    end
end
% fprintf( 'samples_to_skip_at_end is %d\n', samples_to_skip_at_end);

start_frame = floor( samples_to_skip_at_start/ (Nf/ 2));
stop_frame = floor( (maxNsamples- 2* SEARCHBUFFER* Downsample ...
    + DATAPADDING_MSECS* (Fs/ 1000)- samples_to_skip_at_end) ...
    / (Nf/ 2))- 1;
% number of frames in speech data plus DATAPADDING_MSECS
% fprintf( 'start/end frame is %d/%d\n', start_frame, stop_frame);

D_disturbance= zeros( stop_frame+ 1, Nb);
DA_disturbance= zeros( stop_frame+ 1, Nb);

power_ref = pow_of (ref_data, SEARCHBUFFER* Downsample, ...
    maxNsamples- SEARCHBUFFER* Downsample+ DATAPADDING_MSECS* (Fs/ 1000),...
    maxNsamples- 2* SEARCHBUFFER* Downsample+ DATAPADDING_MSECS* (Fs/ 1000));
power_deg = pow_of (deg_data, SEARCHBUFFER * Downsample, ...
    maxNsamples- SEARCHBUFFER* Downsample+ DATAPADDING_MSECS* (Fs/ 1000),...
    maxNsamples- 2* SEARCHBUFFER* Downsample+ DATAPADDING_MSECS* (Fs/ 1000));
% fprintf( 'ref/deg power is %f/%f\n', power_ref, power_deg);

hz_spectrum_ref             = zeros( 1, Nf/ 2);
hz_spectrum_deg             = zeros( 1, Nf/ 2);
frame_is_bad                = zeros( 1, stop_frame + 1);
smeared_frame_is_bad        = zeros( 1, stop_frame + 1);
silent                      = zeros( 1, stop_frame + 1);

pitch_pow_dens_ref          = zeros( stop_frame + 1, Nb);
pitch_pow_dens_deg          = zeros( stop_frame + 1, Nb);

frame_was_skipped           = zeros( 1, stop_frame + 1);
frame_disturbance           = zeros( 1, stop_frame + 1);
frame_disturbance_asym_add  = zeros( 1, stop_frame + 1);

avg_pitch_pow_dens_ref      = zeros( 1, Nb);
avg_pitch_pow_dens_deg      = zeros( 1, Nb);
loudness_dens_ref           = zeros( 1, Nb);
loudness_dens_deg           = zeros( 1, Nb);
deadzone                    = zeros( 1, Nb);
disturbance_dens            = zeros( 1, Nb);
disturbance_dens_asym_add   = zeros( 1, Nb);

time_weight                 = zeros( 1, stop_frame + 1);
total_power_ref             = zeros( 1, stop_frame + 1);

% fid= fopen( 'tmp_mat.txt', 'wt');

for frame = 0: stop_frame
    start_sample_ref = 1+ SEARCHBUFFER * Downsample + frame* (Nf/ 2);
    hz_spectrum_ref= short_term_fft (Nf, ref_data, Whanning, ...
        start_sample_ref);

    utt = Nutterances;
    while ((utt >= 1) && ((Utt_Start(utt)- 1)* Downsample+ 1 ...
            > start_sample_ref))
        utt= utt - 1;
    end

    if (utt >= 1)
        delay = Utt_Delay(utt);
    else
        delay = Utt_Delay(1);
    end

    start_sample_deg = start_sample_ref + delay;

    if ((start_sample_deg > 0) && (start_sample_deg + Nf- 1 < ...
            maxNsamples+ DATAPADDING_MSECS* (Fs/ 1000)))
        hz_spectrum_deg= short_term_fft (Nf, deg_data, Whanning, ...
            start_sample_deg);
    else
        hz_spectrum_deg( 1: Nf/ 2)= 0;
    end

    pitch_pow_dens_ref( frame+ 1, :)= freq_warping (...
        hz_spectrum_ref, Nb, frame);
    %peak = maximum_of (pitch_pow_dens_ref, 0, Nb);
    pitch_pow_dens_deg( frame+ 1, :)= freq_warping (...
        hz_spectrum_deg, Nb, frame);

    total_audible_pow_ref = total_audible (frame, pitch_pow_dens_ref, 1E2);
    total_audible_pow_deg = total_audible (frame, pitch_pow_dens_deg, 1E2);
    silent(frame+ 1) = (total_audible_pow_ref < 1E7);

end
% fclose( fid);

avg_pitch_pow_dens_ref= time_avg_audible_of (stop_frame + 1, ...
    silent, pitch_pow_dens_ref, floor((maxNsamples- 2* SEARCHBUFFER* ...
    Downsample+ DATAPADDING_MSECS* (Fs/ 1000))/ (Nf / 2))- 1);
avg_pitch_pow_dens_deg= time_avg_audible_of (stop_frame + 1, ...
    silent, pitch_pow_dens_deg, floor((maxNsamples- 2* SEARCHBUFFER* ...
    Downsample+ DATAPADDING_MSECS* (Fs/ 1000))/ (Nf/ 2))- 1);

% fid= fopen( 'tmp_mat.txt', 'wt');
% fprintf( fid, '%f\n', avg_pitch_pow_dens_deg);
% fclose( fid);

if (CALIBRATE== 0)
    pitch_pow_dens_ref= freq_resp_compensation (stop_frame + 1, ...
        pitch_pow_dens_ref, avg_pitch_pow_dens_ref, ...
        avg_pitch_pow_dens_deg, 1000);
    if (Plot_Frame>= 0) % plot pitch_pow_dens_ref
        figure;
        subplot( 1, 2, 1);
        plot( centre_of_band_hz, 10* log10( eps+ ...
            pitch_pow_dens_ref( Plot_Frame+ 1, :)));
        axis( [0 Fs/2 0 95]); %xlabel( 'Hz'); ylabel( 'Db');
        title( 'reference signal bark spectrum with frequency compensation');
        subplot( 1, 2, 2);
        plot( centre_of_band_hz, 10* log10( eps+ ...
            pitch_pow_dens_deg( Plot_Frame+ 1, :)));
        axis( [0 Fs/2 0 95]); %xlabel( 'Hz'); ylabel( 'Db');
        title( 'degraded signal bark spectrum');
    end

end
% tmp1= pitch_pow_dens_ref';

MAX_SCALE = 5.0;
MIN_SCALE = 3e-4;
oldScale = 1;
THRESHOLD_BAD_FRAMES = 30;
for frame = 0: stop_frame

    total_audible_pow_ref = total_audible (frame, pitch_pow_dens_ref, 1);
    total_audible_pow_deg = total_audible (frame, pitch_pow_dens_deg, 1);
    total_power_ref (1+ frame) = total_audible_pow_ref;

    scale = (total_audible_pow_ref + 5e3)/ (total_audible_pow_deg + 5e3);
    if (frame > 0)
        scale = 0.2 * oldScale + 0.8 * scale;
    end
    oldScale = scale;

    if (scale > MAX_SCALE)
        scale = MAX_SCALE;
    elseif (scale < MIN_SCALE)
        scale = MIN_SCALE;
    end

    pitch_pow_dens_deg( 1+ frame, :) = ...
        pitch_pow_dens_deg( 1+ frame, :) * scale;

    if (frame== Plot_Frame)
        figure;
        subplot( 1, 2, 1);
        plot( centre_of_band_hz, 10* log10( eps+ ...
            pitch_pow_dens_ref( Plot_Frame+ 1, :)));
        axis( [0 Fs/2 0 95]); %xlabel( 'Hz'); ylabel( 'Db');
        subplot( 1, 2, 2);
        plot( centre_of_band_hz, 10* log10( eps+ ...
            pitch_pow_dens_deg( Plot_Frame+ 1, :)));
        axis( [0 Fs/2 0 95]); %xlabel( 'Hz'); ylabel( 'Db');
    end

    loudness_dens_ref = intensity_warping_of (frame, pitch_pow_dens_ref);
    loudness_dens_deg = intensity_warping_of (frame, pitch_pow_dens_deg);
    disturbance_dens = loudness_dens_deg - loudness_dens_ref;

    if (frame== Plot_Frame)
        figure;
        subplot( 1, 2, 1);
        plot( centre_of_band_hz, 10* log10( eps+ ...
            loudness_dens_ref));
        axis( [0 Fs/2 0 15]); %xlabel( 'Hz'); ylabel( 'Db');
        title( 'reference signal loudness density');
        subplot( 1, 2, 2);
        plot( centre_of_band_hz, 10* log10( eps+ ...
            loudness_dens_deg));
        axis( [0 Fs/2 0 15]); %xlabel( 'Hz'); ylabel( 'Db');
        title( 'degraded signal loudness density');
    end

    for band =1: Nb
        deadzone (band) = 0.25* min (loudness_dens_deg (band), ...
            loudness_dens_ref (band));
    end

    for band = 1: Nb
        d = disturbance_dens (band);
        m = deadzone (band);

        if (d > m)
            disturbance_dens (band) = disturbance_dens (band)- m;
%             disturbance_dens (band) = d- m;
        else
            if (d < -m)
                disturbance_dens (band) = disturbance_dens (band)+ m;
%                 disturbance_dens (band) = d+ m;
            else
                disturbance_dens (band) = 0;
            end
        end
    end

    if (frame== Plot_Frame)
        figure;
        subplot( 1, 2, 1);
        plot( centre_of_band_hz, disturbance_dens);
        axis( [0 Fs/2 -1 50]); %xlabel( 'Hz'); ylabel( 'Db');
        title( 'disturbance');
    end
    D_disturbance( frame+ 1, :)= disturbance_dens;

    frame_disturbance (1+ frame) = pseudo_Lp (disturbance_dens, D_POW_F);
    if (frame_disturbance (1+ frame) > THRESHOLD_BAD_FRAMES)
        there_is_a_bad_frame = TRUE;
    end

    disturbance_dens= multiply_with_asymmetry_factor (...
        disturbance_dens, frame, pitch_pow_dens_ref, pitch_pow_dens_deg);

    if (frame== Plot_Frame)
        subplot( 1, 2, 2);
        plot( centre_of_band_hz, disturbance_dens);
        axis( [0 Fs/2 -1 50]); %xlabel( 'Hz'); ylabel( 'Db');
        title( 'disturbance after asymmetry processing');
    end
    DA_disturbance( frame+ 1, :)= disturbance_dens;

    frame_disturbance_asym_add (1+ frame) = ...
        pseudo_Lp (disturbance_dens, A_POW_F);
end
% fid= fopen( 'tmp_mat.txt', 'wt');
% fprintf( fid, '%f\n', frame_disturbance);
% fclose( fid);

frame_was_skipped (1: 1+ stop_frame) = FALSE;

for utt = 2: Nutterances
    frame1 = floor (((Utt_Start(utt)- 1- SEARCHBUFFER )* Downsample+ 1+ ...
        Utt_Delay(utt))/ (Nf/ 2));
    j = floor( floor(((Utt_End(utt-1)- 1- SEARCHBUFFER)* Downsample+ 1+ ...
        Utt_Delay(utt-1)))/(Nf/ 2));
    delay_jump = Utt_Delay(utt) - Utt_Delay(utt-1);
    if (frame1 > j)
        frame1 = j;
    elseif (frame1 < 0)
        frame1 = 0;
    end
%     fprintf( 'frame1, j, delay_jump is %d, %d, %d\n', frame1, ...
%         j, delay_jump);

    if (delay_jump < -(Nf/ 2))
        frame2 = floor (((Utt_Start(utt)- 1- SEARCHBUFFER)* Downsample+ 1 ...
            + max (0, abs (delay_jump)))/ (Nf/ 2)) + 1;

        for frame = frame1: frame2
            if (frame < stop_frame)
                frame_was_skipped (1+ frame) = TRUE;
                frame_disturbance (1+ frame) = 0;
                frame_disturbance_asym_add (1+ frame) = 0;
            end
        end
    end
end

nn = DATAPADDING_MSECS* (Fs/ 1000) + maxNsamples;
tweaked_deg = zeros( 1, nn);
% fprintf( 'nn is %d\n', nn);

for i= SEARCHBUFFER* Downsample+ 1: nn- SEARCHBUFFER* Downsample
    utt = Nutterances;

    while ((utt >= 1) && ((Utt_Start (utt)- 1)* Downsample> i))
        utt = utt- 1;
    end
    if (utt >= 1)
        delay = Utt_Delay (utt);
    else
        delay = Utt_Delay (1);
    end

    j = i + delay;
    if (j < SEARCHBUFFER * Downsample+ 1)
        j = SEARCHBUFFER * Downsample+ 1;
    end
    if (j > nn - SEARCHBUFFER * Downsample)
        j = nn - SEARCHBUFFER * Downsample;
    end
    tweaked_deg (i) = deg_data (j);
end

if (there_is_a_bad_frame)

    for frame = 0: stop_frame
        frame_is_bad (1+ frame) = (frame_disturbance (1+ frame)...
            > THRESHOLD_BAD_FRAMES);
        smeared_frame_is_bad (1+ frame) = FALSE;
    end
    frame_is_bad (1) = FALSE;
    SMEAR_RANGE = 2;

    for frame = SMEAR_RANGE: stop_frame- 1- SMEAR_RANGE
        max_itself_and_left = frame_is_bad (1+ frame);
        max_itself_and_right = frame_is_bad (1+ frame);

        for i = -SMEAR_RANGE: 0
            if (max_itself_and_left < frame_is_bad (1+ frame+ i))
                max_itself_and_left = frame_is_bad (1+ frame+ i);
            end
        end

        for i = 0: SMEAR_RANGE
            if (max_itself_and_right < frame_is_bad (1+ frame + i))
                max_itself_and_right = frame_is_bad (1+ frame + i);
            end
        end

        mini = max_itself_and_left;
        if (mini > max_itself_and_right)
            mini = max_itself_and_right;
        end

        smeared_frame_is_bad (1+ frame) = mini;
    end

    MINIMUM_NUMBER_OF_BAD_FRAMES_IN_BAD_INTERVAL = 5;
    number_of_bad_intervals = 0;
    frame = 0;
    while (frame <= stop_frame)
        while ((frame <= stop_frame) && (~smeared_frame_is_bad (1+ frame)))
            frame= frame+ 1;
        end

        if (frame <= stop_frame)
            start_frame_of_bad_interval(1+ number_of_bad_intervals)= ...
                1+ frame;

            while ((frame <= stop_frame) && (...
                    smeared_frame_is_bad (1+ frame)))
                frame= frame+ 1;
            end

            if (frame <= stop_frame)
                stop_frame_of_bad_interval(1+ number_of_bad_intervals)= ...
                    1+ frame;
                if (stop_frame_of_bad_interval(1+ number_of_bad_intervals)- ...
                        start_frame_of_bad_interval(1+ number_of_bad_intervals)...
                        >= MINIMUM_NUMBER_OF_BAD_FRAMES_IN_BAD_INTERVAL)
                    number_of_bad_intervals= number_of_bad_intervals+ 1;
                end
            end
        end
    end

    for bad_interval = 0: number_of_bad_intervals - 1
        start_sample_of_bad_interval(1+ bad_interval) = ...
            (start_frame_of_bad_interval(1+ bad_interval)- 1) * (Nf/ 2) ...
            + SEARCHBUFFER * Downsample+ 1;
        stop_sample_of_bad_interval(1+ bad_interval) = ...
            (stop_frame_of_bad_interval(1+ bad_interval)- 1) * (Nf/ 2) ...
            + Nf + SEARCHBUFFER* Downsample;
        if (stop_frame_of_bad_interval(1+ bad_interval) > stop_frame+ 1)
            stop_frame_of_bad_interval(1+ bad_interval) = stop_frame+ 1;
        end

        number_of_samples_in_bad_interval(1+ bad_interval) = ...
            stop_sample_of_bad_interval(1+ bad_interval) - ...
            start_sample_of_bad_interval(1+ bad_interval)+ 1;
    end
%     fprintf( 'number of bad intervals %d\n', number_of_bad_intervals);
%     fprintf( '%d %d\n', number_of_samples_in_bad_interval(1), ...
%         number_of_samples_in_bad_interval(2));
%     fprintf( '%d %d\n', start_sample_of_bad_interval(1), ...
%         start_sample_of_bad_interval(2));

    SEARCH_RANGE_IN_TRANSFORM_LENGTH = 4;
    search_range_in_samples= SEARCH_RANGE_IN_TRANSFORM_LENGTH * Nf;

    for bad_interval= 0: number_of_bad_intervals- 1
        ref = zeros (1, 2 * search_range_in_samples + ...
            number_of_samples_in_bad_interval (1+ bad_interval));
        deg = zeros (1, 2 * search_range_in_samples + ...
            number_of_samples_in_bad_interval (1+ bad_interval));

        ref(1: search_range_in_samples) = 0;

        ref (search_range_in_samples+ 1: search_range_in_samples+ ...
                number_of_samples_in_bad_interval (1+ bad_interval)) = ...
                ref_data (start_sample_of_bad_interval( 1+ bad_interval) + 1: ...
                start_sample_of_bad_interval( 1+ bad_interval) + ...
                number_of_samples_in_bad_interval (1+ bad_interval));

        ref (search_range_in_samples + ...
                number_of_samples_in_bad_interval (1+ bad_interval) + 1: ...
                search_range_in_samples + ...
                number_of_samples_in_bad_interval (1+ bad_interval) + ...
                search_range_in_samples) = 0;

        for i = 0: 2 * search_range_in_samples + ...
                number_of_samples_in_bad_interval (1+ bad_interval) - 1
            j = start_sample_of_bad_interval (1+ bad_interval) - ...
                search_range_in_samples + i;
            nn = maxNsamples - SEARCHBUFFER * Downsample + ...
                DATAPADDING_MSECS  * (Fs / 1000);
            if (j <= SEARCHBUFFER * Downsample)
                j = SEARCHBUFFER * Downsample+ 1;
            end
            if (j > nn)
                j = nn;
            end
            deg (1+ i) = tweaked_deg (j);
        end

        [delay_in_samples, best_correlation]= compute_delay ...
            (1, 2 * search_range_in_samples + ...
            number_of_samples_in_bad_interval (1+ bad_interval), ...
            search_range_in_samples, ref, deg);
        delay_in_samples_in_bad_interval (1+ bad_interval) =  ...
            delay_in_samples;
%         fprintf( 'delay_in_samples, best_correlation is \n\t%d, %f\n', ...
%             delay_in_samples, best_correlation);
%
        if (best_correlation < 0.5)
            delay_in_samples_in_bad_interval  (1+ bad_interval) = 0;
        end
    end

    if (number_of_bad_intervals > 0)
        doubly_tweaked_deg = tweaked_deg( 1: maxNsamples + ...
            DATAPADDING_MSECS  * (Fs / 1000));
        for bad_interval= 0: number_of_bad_intervals- 1
            delay = delay_in_samples_in_bad_interval (1+ bad_interval);

            for i = start_sample_of_bad_interval (1+ bad_interval): ...
                    stop_sample_of_bad_interval (1+ bad_interval)
                j = i + delay;
                if (j < 1)
                    j = 1;
                end
                if (j > maxNsamples)
                    j = maxNsamples;
                end
                h = tweaked_deg (j);
                doubly_tweaked_deg (i) = h;
            end
        end

        untweaked_deg = deg_data;
        deg_data = doubly_tweaked_deg;

        for bad_interval= 0: number_of_bad_intervals- 1
            for frame = start_frame_of_bad_interval (1+ bad_interval): ...
                    stop_frame_of_bad_interval (1+ bad_interval)- 1
                frame= frame- 1;
                start_sample_ref = SEARCHBUFFER * Downsample + ...
                    frame * Nf / 2+ 1;
                start_sample_deg = start_sample_ref;
                hz_spectrum_deg= short_term_fft (Nf, deg_data, ...
                    Whanning, start_sample_deg);
                pitch_pow_dens_deg( 1+ frame, :)= freq_warping (...
                    hz_spectrum_deg, Nb, frame);
            end

            oldScale = 1;
            for frame = start_frame_of_bad_interval (1+ bad_interval): ...
                    stop_frame_of_bad_interval (1+ bad_interval)- 1
                frame= frame- 1;
                % see implementation for detail why 1 needed to be
                % subtracted
                total_audible_pow_ref = total_audible (frame, ...
                    pitch_pow_dens_ref, 1);
                total_audible_pow_deg = total_audible (frame, ...
                    pitch_pow_dens_deg, 1);
                scale = (total_audible_pow_ref + 5e3) / ...
                    (total_audible_pow_deg + 5e3);
                if (frame > 0)
                    scale = 0.2 * oldScale + 0.8*scale;
                end
                oldScale = scale;
                if (scale > MAX_SCALE)
                    scale = MAX_SCALE;
                end
                if (scale < MIN_SCALE)
                    scale = MIN_SCALE;
                end

                pitch_pow_dens_deg (1+ frame, :) = ...
                    pitch_pow_dens_deg (1+ frame, :)* scale;
                loudness_dens_ref= intensity_warping_of (frame, ...
                    pitch_pow_dens_ref);
                loudness_dens_deg= intensity_warping_of (frame, ...
                    pitch_pow_dens_deg);
                disturbance_dens = loudness_dens_deg - loudness_dens_ref;

                for band = 1: Nb
                    deadzone(band) = min (loudness_dens_deg(band), ...
                        loudness_dens_ref(band));
                    deadzone(band) = deadzone(band)* 0.25;
                end

                for band = 1: Nb
                    d = disturbance_dens (band);
                    m = deadzone (band);

                    if (d > m)
                        disturbance_dens (band) = ...
                            disturbance_dens (band)- m;
                    else
                        if (d < -m)
                            disturbance_dens (band) = ...
                                disturbance_dens (band)+ m;
                        else
                            disturbance_dens (band) = 0;
                        end
                    end
                end

                frame_disturbance( 1+ frame) = min (...
                    frame_disturbance( 1+ frame), pseudo_Lp(...
                    disturbance_dens, D_POW_F));
                disturbance_dens= multiply_with_asymmetry_factor ...
                    (disturbance_dens, frame, pitch_pow_dens_ref, ...
                    pitch_pow_dens_deg);
                frame_disturbance_asym_add(1+ frame) = min (...
                    frame_disturbance_asym_add(1+ frame), ...
                    pseudo_Lp (disturbance_dens, A_POW_F));
            end
        end
        deg_data = untweaked_deg;
    end
end

for frame = 0: stop_frame
    h = 1;
    if (stop_frame + 1 > 1000)
        n = floor( (maxNsamples - 2 * SEARCHBUFFER * Downsample)...
            / (Nf / 2)) - 1;
        timeWeightFactor = (n - 1000) / 5500;
        if (timeWeightFactor > 0.5)
            timeWeightFactor = 0.5;
        end
        h = (1.0 - timeWeightFactor) + timeWeightFactor * frame / n;
    end

    time_weight (1 +frame) = h;
end

% fid= fopen( 'tmp_mat1.txt', 'at');
% fprintf( '\n');
for frame = 0: stop_frame
    h = ((total_power_ref (1+ frame) + 1e5) / 1e7)^ 0.04;
%     if (frame== 118)
%         fprintf( '%f\n', h);
%         fprintf( '%f\n', frame_disturbance( 1+ frame));
%     end
    frame_disturbance( 1+ frame) = frame_disturbance( 1+ frame)/ h;

%     if (frame== 118)
%         fprintf( '%f\n', frame_disturbance( 1+ frame));
%     end
%
    frame_disturbance_asym_add( 1+ frame) = ...
        frame_disturbance_asym_add( 1+ frame)/ h;
    if (frame_disturbance( 1+ frame) > 45)
        frame_disturbance( 1+ frame) = 45;
    end
    if (frame_disturbance_asym_add( 1+ frame)> 45)
        frame_disturbance_asym_add( 1+ frame) = 45;
    end
end
% fclose ( fid);

d_indicator = Lpq_weight (start_frame, stop_frame, ...
    D_POW_S, D_POW_T, frame_disturbance, time_weight);
a_indicator = Lpq_weight (start_frame, stop_frame, ...
    A_POW_S, A_POW_T, frame_disturbance_asym_add, time_weight);

pesq_mos = 4.5 - D_WEIGHT * d_indicator - A_WEIGHT * a_indicator;

if (Plot_Frame> 0)
    figure;
    subplot( 1, 2, 1);
    mesh( 0: stop_frame, centre_of_band_hz, D_disturbance');
    title( 'disturbance');
    subplot( 1, 2, 2);
    mesh( 0: stop_frame, centre_of_band_hz, DA_disturbance');
    title( 'disturbance after asymmetry processing');
end

% fid= fopen( 'tmp_mat.txt', 'wt');
% fprintf( fid, 'time_weight\n');
% fprintf( fid, '%f\n', time_weight);
% fprintf( fid, 'frame_disturbance:\n');
% fprintf( fid, '%f\n', frame_disturbance);
% fprintf( fid, 'frame_disturbance_asym_add\n');
% fprintf( fid, '%f\n', frame_disturbance_asym_add);
% fclose( fid);

function result_time= Lpq_weight(start_frame, stop_frame, ...
        power_syllable, power_time, frame_disturbance, time_weight)

global NUMBER_OF_PSQM_FRAMES_PER_SYLLABE

% fid= fopen( 'tmp_mat1.txt', 'at');
% fprintf( 'result_time:\n');

result_time= 0;
total_time_weight_time = 0;
% fprintf( 'start/end frame: %d/%d\n', start_frame, stop_frame);
for start_frame_of_syllable = start_frame: ...
        NUMBER_OF_PSQM_FRAMES_PER_SYLLABE/2: stop_frame
    result_syllable = 0;
    count_syllable = 0;

    for frame = start_frame_of_syllable: ...
            start_frame_of_syllable + NUMBER_OF_PSQM_FRAMES_PER_SYLLABE- 1
        if (frame <= stop_frame)
            h = frame_disturbance(1+ frame);
%             if (start_frame_of_syllable== 101)
%                 fprintf( fid, '%f\n', h);
%             end
            result_syllable = result_syllable+ (h^ power_syllable);
        end
        count_syllable = count_syllable+ 1;
    end

    result_syllable = result_syllable/ count_syllable;
    result_syllable = result_syllable^ (1/power_syllable);

    result_time= result_time+ (time_weight (...
        1+ start_frame_of_syllable - start_frame) * ...
        result_syllable)^ power_time;
    total_time_weight_time = total_time_weight_time+ ...
        time_weight (1+ start_frame_of_syllable - start_frame)^ power_time;

%     fprintf( fid, '%f\n', result_time);
end
% fclose (fid);

% fprintf( 'total_time_weight_time is %f\n', total_time_weight_time);
result_time = result_time/ total_time_weight_time;
result_time= result_time^ (1/ power_time);
% fprintf( 'result_time is %f\n\n', result_time);

function [best_delay, max_correlation] = compute_delay (...
    start_sample, stop_sample, search_range, ...
    time_series1, time_series2)

n = stop_sample - start_sample+ 1;
power_of_2 = 2^ (ceil( log2( 2 * n)));

power1 = pow_of (time_series1, start_sample, stop_sample, n)* ...
    n/ power_of_2;
power2 = pow_of (time_series2, start_sample, stop_sample, n)* ...
    n/ power_of_2;
normalization = sqrt (power1 * power2);
% fprintf( 'normalization is %f\n', normalization);

if ((power1 <= 1e-6) || (power2 <= 1e-6))
    max_correlation = 0;
    best_delay= 0;
end

x1( 1: power_of_2)= 0;
x2( 1: power_of_2)= 0;
y( 1: power_of_2)= 0;

x1( 1: n)= abs( time_series1( start_sample: ...
    stop_sample));
x2( 1: n)= abs( time_series2( start_sample: ...
    stop_sample));

x1_fft= fft( x1, power_of_2)/ power_of_2;
x2_fft= fft( x2, power_of_2);
x1_fft_conj= conj( x1_fft);
y= ifft( x1_fft_conj.* x2_fft, power_of_2);

best_delay = 0;
max_correlation = 0;

% these loop can be rewritten
for i = -search_range: -1
    h = abs (y (1+ i + power_of_2)) / normalization;
    if (h > max_correlation)
        max_correlation = h;
        best_delay= i;
    end
end
for i = 0: search_range- 1
    h = abs (y (1+i)) / normalization;
    if (h > max_correlation)
        max_correlation = h;
        best_delay= i;
    end
end
best_delay= best_delay- 1;

function mod_disturbance_dens= multiply_with_asymmetry_factor (...
    disturbance_dens, frame, pitch_pow_dens_ref, pitch_pow_dens_deg)

global Nb
for i = 1: Nb
    ratio = (pitch_pow_dens_deg(1+ frame, i) + 50)...
        / (pitch_pow_dens_ref (1+ frame, i) + 50);
    h = ratio^ 1.2;
    if (h > 12)
        h = 12;
    elseif (h < 3)
        h = 0.0;
    end
    mod_disturbance_dens (i) = disturbance_dens (i) * h;
end

function loudness_dens = intensity_warping_of (...
    frame, pitch_pow_dens)

global abs_thresh_power Sl Nb centre_of_band_bark
ZWICKER_POWER= 0.23;
for band = 1: Nb
    threshold = abs_thresh_power (band);
    input = pitch_pow_dens (1+ frame, band);

    if (centre_of_band_bark (band) < 4)
        h =  6 / (centre_of_band_bark (band) + 2);
    else
        h = 1;
    end

    if (h > 2)
        h = 2;
    end
    h = h^ 0.15;
    modified_zwicker_power = ZWICKER_POWER * h;
    if (input > threshold)
        loudness_dens (band) = ((threshold / 0.5)^ modified_zwicker_power)...
            * ((0.5 + 0.5 * input / threshold)^ modified_zwicker_power- 1);
    else
        loudness_dens (band) = 0;
    end

    loudness_dens (band) = loudness_dens (band)* Sl;
end

function result= pseudo_Lp (x, p)

global Nb width_of_band_bark
totalWeight = 0;
result = 0;
for band = 2: Nb
    h = abs (x (band));
    w = width_of_band_bark (band);
    prod = h * w;

    result = result+ prod^ p;
    totalWeight = totalWeight+ w;
end
result = (result/ totalWeight)^ (1/p);
result = result* totalWeight;

function mod_pitch_pow_dens_ref= freq_resp_compensation (number_of_frames, ...
    pitch_pow_dens_ref, avg_pitch_pow_dens_ref, ...
    avg_pitch_pow_dens_deg, constant)

global Nb

for band = 1: Nb
    x = (avg_pitch_pow_dens_deg (band) + constant) / ...
        (avg_pitch_pow_dens_ref (band) + constant);
    if (x > 100.0)
        x = 100.0;
    elseif (x < 0.01)
        x = 0.01;
    end

    for frame = 1: number_of_frames
        mod_pitch_pow_dens_ref(frame, band) = ...
            pitch_pow_dens_ref(frame, band) * x;
    end
end

function avg_pitch_pow_dens= time_avg_audible_of(number_of_frames, ...
    silent, pitch_pow_dens, total_number_of_frames)

global Nb abs_thresh_power

for band = 1: Nb
    result = 0;
    for frame = 1: number_of_frames
        if (~silent (frame))
            h = pitch_pow_dens (frame, band);
            if (h > 100 * abs_thresh_power (band))
                result = result + h;
            end
        end

        avg_pitch_pow_dens (band) = result/ total_number_of_frames;
    end
end

function hz_spectrum= short_term_fft (Nf, data, Whanning, start_sample)

x1= data( start_sample: start_sample+ Nf-1).* Whanning;
x1_fft= fft( x1);
hz_spectrum= abs( x1_fft( 1: Nf/ 2)).^ 2;
hz_spectrum( 1)= 0;

function pitch_pow_dens= freq_warping( hz_spectrum, Nb, frame)

global nr_of_hz_bands_per_bark_band pow_dens_correction_factor
global Sp

hz_band = 1;
for bark_band = 1: Nb
    n = nr_of_hz_bands_per_bark_band (bark_band);
    sum = 0;
    for i = 1: n
        sum = sum+ hz_spectrum( hz_band);
        hz_band= hz_band+ 1;
    end
    sum = sum* pow_dens_correction_factor (bark_band);
    sum = sum* Sp;
    pitch_pow_dens (bark_band) = sum;

end

function total_audible_pow = total_audible (frame, ...
    pitch_pow_dens, factor)

global Nb abs_thresh_power

total_audible_pow = 0;
for band= 2: Nb
    h = pitch_pow_dens (frame+ 1,band);
    threshold = factor * abs_thresh_power (band);
    if (h > threshold)
        total_audible_pow = total_audible_pow+ h;
    end
end