function [f x] = mirframe(x,varargin)
%   f = mirframe(x) creates the frame decomposition of the audio signal x.
%       (x can be a file name as well.)
%   Optional arguments:
%       mirframe(x,'Length',w,wu):
%           w is the length of the window in seconds (default: .05 seconds)
%           u is the unit, either 
%               's' (seconds, default unit) 
%            or 'sp' (number of samples)
%       mirframe(x,'Hop',h,hu):
%           h is the hop factor, or distance between successive frames
%               (default: half overlapping: each frame begins at the middle
%                   of the previous frame)
%           u is the unit, either 
%               '/1' (ratio with respect to the frame length, default unit)
%               '%' (ratio as percentage)
%               's' (seconds)
%               'sp' (number of samples)
%            or 'Hz' (hertz), i.e., number of frames per second: the
%                   exactness of the frame rate is ensured and may cause a
%                   slight fluctuation of the elementary hop distances.
%       These arguments can also be written as follows:
%           mirframe(x,w,wu,h,hu)
%               (where some of these parameters can be omitted).

if isempty(x)
    f = {};
    return
end
if iscell(x)
    x = x{1};
end
if nargin == 0
    f = miraudio;
elseif isa(x,'mirdesign')
    if not(get(x,'Eval'))
        % During bottom-up construction of the general design
        
        para = scanargin(varargin);
        type = get(x,'Type');
        f = mirdesign(@mirframe,x,para,{},struct,type);
        
        fl = get(x,'FrameLength');
        fh = get(x,'FrameHop');
        flu = get(x,'FrameLengthUnit');
        fhu = get(x,'FrameHopUnit');
        if fl
            f = set(f,'FrameLength',fl,'FrameLengthUnit',flu,...
                      'FrameHop',fh,'FrameHopUnit',fhu);
        else
            f = set(f,'FrameLength',para.wlength.val,...
                      'FrameLengthUnit',para.wlength.unit,...
                      'FrameHop',para.hop.val,...
                      'FrameHopUnit',para.hop.unit);
        end
        f = set(f,'FrameEval',1,...
                  'SeparateChannels',get(x,'SeparateChannels'));
        if not(isamir(x,'miraudio'))
            f = set(f,'NoChunk',1);
        end
    else
        % During top-down evaluation initiation
        
        if isstruct(varargin{1}) && isfield(varargin{1},'struct')
            tmp = varargin{1}.struct;
            x = set(x,'Struct',tmp);
            varargin{1} = rmfield(varargin{1},'struct');
        end
        e = evaleach(x);
        if iscell(e)
            e = e{1};
        end
        if isempty(mirgetdata(e))
            f = e;
        else
            f = mirframe(e,varargin{:});
        end
    end
elseif isa(x,'mirdata')
    if isframed(x)
        warning('WARNING IN MIRFRAME: The input data is already decomposed into frames. No more frame decomposition.');
        f = x;
    else
        x = purgedata(x);
        dx = get(x,'Data');
        if isa(x,'mirtemporal')
            dt = get(x,'Time');
        else
            dt = get(x,'FramePos');
        end
        sf = get(x,'Sampling');
        para = scanargin(varargin);
        dx2 = cell(1,length(dx));   % magnitude in framed structure 
        dt2 = cell(1,length(dx));   % time positions in framed structure
        fp = cell(1,length(dx));    % frame positions
        for k = 1:length(dx)    % For each audio file, ...
            dxk = dx{k};
            dtk = dt{k};
            if strcmpi(para.wlength.unit,'s')
                l = para.wlength.val*sf{k};
            elseif strcmpi(para.wlength.unit,'sp')
                l = para.wlength.val;
            end
            if strcmpi(para.hop.unit,'/1')
                h = para.hop.val*l;
            elseif strcmpi(para.hop.unit,'%')
                h = para.hop.val*l*.01;
            elseif strcmpi(para.hop.unit,'s')
                h = para.hop.val*sf{k};
            elseif strcmpi(para.hop.unit,'sp')
                h = para.hop.val;
            elseif strcmpi(para.hop.unit,'Hz')
                h = sf{k}/para.hop.val;
            end
            l = floor(l);
            dx2k = cell(1,length(dxk));
            dt2k = cell(1,length(dxk));
            fpk = cell(1,length(dxk));
            for j = 1:length(dxk)   % For each segment, ...
                dxj = dxk{j};
                dtj = dtk{j};
                if not(isa(x,'mirtemporal'))
                    dxj = dxj';
                    dtj = dtj(1,:)';
                end

                n = floor((size(dxj,1)-l)/h)+1; % Number of frames
                dx2j = zeros(l,n,size(dxj,3));
                dt2j = zeros(l,n);
                fpj = zeros(2,n);
                if n < 1
                    disp('Frame length longer than total sequence size. No frame decomposition.');
                    dx2j = dxj(:,1,:);
                    dt2j = dtj;
                    fpj = [dtj(1) ; dtj(end)];
                else
                    for i = 1:n % For each frame, ...
                        st = floor((i-1)*h+1);
                        stend = st+l-1;
                        dx2j(:,i,:) = dxj(st:stend,1,:);
                        dt2j(:,i) = dtj(st:stend);
                        fpj(:,i) = [dtj(st) dtj(stend)];
                    end
                end
                dx2k{j} = dx2j;
                dt2k{j} = dt2j;
                fpk{j} = fpj;
            end
            dx2{k} = dx2k;
            dt2{k} = dt2k;
            fp{k} = fpk;
        end
        if isa(x,'mirtemporal')
            f = set(x,'Time',dt2,'Data',dx2,'FramePos',fp);
        else
            f = mirtemporal([],'Time',dt2,'Data',dx2,'FramePos',fp,...
                    'Sampling',get(x,'Sampling'),'Name',get(x,'Name'),...
                    'Label',get(x,'Label'),'Channels',get(x,'Channels'),...
                    'Centered',0,'Title',get(x,'Title'));
        end
    end
else
    f = mirframe(miraudio(x),varargin{:});
end


function para = scanargin(v)
if not(isempty(v)) && isstruct(v{1})
    if length(v) == 1
        para = v{1};
    else
        para.wlength = v{1};
        para.hop = v{2};
    end
    return
end
para.wlength.val = 0.05;
para.wlength.unit = 's';
para.hop.val = 0.5;
para.hop.unit = '/1';
nv = length(v);
i = 1;
j = 1;
while i <= nv
    arg = v{i};
    if strcmpi(arg,'WinLength') || strcmpi(arg,'Length')
        if i < nv && isnumeric(v{i+1})
            i = i+1;
            j = 0;
            para.wlength.val = v{i};
        else
            error('ERROR IN MIRFRAME: Incorrect use of Length option. See help mirframe.'); 
        end
        if i < nv && ischar(v{i+1}) && ...
                (strcmpi(v{i+1},'s') || strcmpi(v{i+1},'sp'))
            i = i+1;
            para.wlength.unit = v{i};
        end
    elseif strcmpi(arg,'Hop')
        if i < nv && isnumeric(v{i+1})
            i = i+1;
            j = 0;
            para.hop.val = v{i};
        else
            error('ERROR IN MIRFRAME: Incorrect use of Hop option. See help mirframe.'); 
        end
        if i < nv && ischar(v{i+1}) && ...
                (strcmpi(v{i+1},'%') || strcmpi(v{i+1},'/1') || ...
                 strcmpi(v{i+1},'s') || strcmpi(v{i+1},'sp') || ...
                 strcmpi(v{i+1},'Hz'))
            i = i+1;
            para.hop.unit = v{i};
        end
    elseif isnumeric(arg)
        switch j
            case 1
                j = 2;
                para.wlength.val = arg;
                if i < nv && ischar(v{i+1}) && ...
                        (strcmpi(v{i+1},'s') || strcmpi(v{i+1},'sp'))
                    i = i+1;
                    para.wlength.unit = v{i};
                end
            case 2
                j = 3;
                para.hop.val = arg;
                if i < nv && ischar(v{i+1}) && ...
                        (strcmpi(v{i+1},'%') || strcmpi(v{i+1},'/1') || ...
                         strcmpi(v{i+1},'s') || strcmpi(v{i+1},'sp') || ...
                         strcmpi(v{i+1},'Hz'))
                    i = i+1;
                    para.hop.unit = v{i};
                end
            otherwise
                error('ERROR IN MIRFRAME: Syntax error. See help mirframe.');
        end
    elseif not(isempty(arg))
        error('ERROR IN MIRFRAME: Syntax error. See help mirframe.');
    end
    i = i+1;
end