
function [fx,fpad] = linframe(x,fhop,flen,padtype)
% LINFRAME Splits a signal in linearly spaced frames.
%   [fx,fpad] = linframe(x,fhop,flen,padtype)
%
%   By returning a matrix version of the framed signal we enable
%   vectorized processing. It can be used for MDCT using 'sym'
%   (symmetric) padtype.
%
%   x:       input signal
%   fhop:    hop length (default 128)
%   flen:    length of frame (if empty defaults to 2*fhop)
%   padtype: how to pad start/end of signal. Values: 'trunc','pad','sym'
%            defaults to 'pad'
%   fx:      framed output signal. (frame per column)
%   fpad:    misc info for padding.unpadding
%            fpad(1): start pad
%            fpad(2): end pad
%            we use this value in linunframe() and so we return
%            equal length signal as the original. This way we can
%            calculate the difference etc.
%            fpad(3): contains the length of x (for reconstruction)
%            (added recently, i don't require pad(2) but anyway...)
%            fpad(4): frame hop
%            fpad(5): frame length (number of rows)
%            fpad(6): number of frames (number of columns)

% ------- linframe.m ---------------------------------------
% Marios Athineos, marios@ee.columbia.edu
% http://www.ee.columbia.edu/~marios/
% Copyright (c) 2002-2003 by Columbia University.
% All rights reserved.
% ----------------------------------------------------------

% Check arguments
if (nargin < 2)
    fhop = 128;
end
if (nargin < 3)
    flen = 2*fhop;
end
if (nargin < 4)
    padtype = 'pad';
end
if isempty(flen)
    flen = 2*fhop;
end

fpad = [0 0 0];
% Make column
x = x(:);
% Length of signal
xlen    = length(x);
fpad(3) = xlen;
% Number of frames
fnum = fix((xlen-flen+fhop)/fhop);
% Unframed samples
frem = rem(xlen-flen+fhop,fhop);

switch padtype
    % What should we do with the rem samples ?
case 'trunc'
    % Just discard what doesn't fit
    fpad(2) = -frem;
case 'pad'
    % Pad end with zeros (to complete extra frame)
    if (frem~=0)
        fpad(2) = fhop-frem;
        fnum    = fnum+1;
        x       = [x;ditherit(zeros(fpad(2),1))];
    end
case 'sym'
    % Pad with zeros both front and end symmetricaly (MDCT 50%) 
    if (isequal(frem,0))
        fnum    = fnum+2;
        fpad(1) = fhop;
        fpad(2) = fhop;
    else
        fnum    = fnum+3;
        fpad(1) = fix(((3*fhop)-frem)/2);
        fpad(2) = fpad(1)+1;
    end
%    x = [ditherit(zeros(fpad(1),1));x;ditherit(zeros(fpad(2),1))];
    x = [zeros(fpad(1),1); x; zeros(fpad(2),1)];
case 'sym2'
    % Pad with zeros both front and end symmetricaly (this came up for
    % feature extraction and doesn't assume 50% overlap)
    % This method is only defined for even fhop
    if rem(fhop,2)
        error('sym2 is defined only for fhop even');
    elseif fhop <= 0
        error('sym2 is defined only for possitive fhop');
    end            
    fnum = ceil(xlen/fhop);
    % Zero pad end if we need it
    if fnum*fhop > xlen
        x(fnum*fhop) = 0;
    end
    fpad(1) = (flen-fhop) / 2;
    fpad(2) = fpad(1);
    x = [zeros(fpad(1),1); x; zeros(fpad(2),1)];    
otherwise
    error('Wrong padtype.');
end

% Preallocate and store it frame per column
fx = zeros(flen,fnum);
% Index of frame start (to be added to sidx)
fidx = fhop*(0:(fnum-1));
% Make matrix of frame indexes (Tony's trick)
fidx = fidx(ones(flen,1),:);
% Index of sample ralative to frame start
sidx = (1:flen).';
% Make matrix of sample indexes
sidx = sidx(:,ones(1,fnum));
% Voila! This is as vectorized as it gets !!!
fx(:) = x(fidx+sidx);

% Put the frame length and number of frames in fpad
[fpad(5),fpad(6)] = size(fx);
fpad(4) = fhop;

% ----------------------------------------------------------
% Note:
% We used Tony's Trick (mathworks.com Tech-Note 1109)
% The following multiplication gives the same result
% but it's more expensive.
% fidx = ones(flen,1)*fidx;
% sidx = sidx*ones(1,fnum);