function [c,info]=dtwfb(f,dualwt,varargin)
%DTWFB Dual-Tree Wavelet Filter Bank
%   Usage:  c=dtwfb(f,dualwt);
%           c=dtwfb(f,{dualw,J});
%           [c,info]=dtwfb(...);
%
%   Input parameters:
%         f      : Input data.
%         dualwt : Dual-tree Wavelet Filter bank definition.
%
%   Output parameters:
%         c    : Coefficients stored in a cell-array.
%         info : Additional transform parameters struct.
%
%   `c=dtwfbt(f,dualwt)` computes dual-tree complex wavelet coefficients 
%   of the signal *f*. The representation is approximately 
%   time-invariant and provides analytic behaviour. Due to these facts, 
%   the resulting subbands are nearly aliasing free making them suitable 
%   for severe coefficient modifications. The representation is two times
%   redundant, provided critical subsampling of all involved filter banks.
%
%   The shape of the filterbank tree and filters used is controlled by 
%   `dualwt` (for possible formats see below). The output *c* is a 
%   cell-array with each element containing a single subband. The subbands 
%   are ordered with the increasing subband centre frequency. 
%
%   In addition, the function returns struct. `info` containing transform 
%   parameters. It can be conveniently used for the inverse transform
%   |idtwfb| e.g. `fhat = idtwfb(c,info)`. It is also required by
%   the |plotwavelets| function.
%
%   If *f* is a matrix, the transform is applied to each column.
%
%   Two formats of `dualwt` are accepted:
% 
%   1) Cell array of parameters. First two elements of the array are 
%      mandatory `{dualw,J}`. 
% 
%      `dualw`   
%        Basic dual-tree filters
%      *J*
%        Number of levels of the filter bank tree
%
%      Possible formats of `dualw` are the same as in |fwtinit| except the
%      `wfiltdt_` prefix is used when searching for function specifying
%      the actual impulse responses. These filters were designed specially
%      for the dual-tree filter bank to achieve the half-sample shift 
%      ultimately resulting in analytic (complex) behaviour of the 
%      transform.
%      
%      The default shape of the filter bank tree is DWT i.e. only low-pass
%      output is decomposed further (*J* times in total).
%
%      Different filter bank tree shapes can be obtained by passing
%      additional flag in the cell array. Supported flags (mutually
%      exclusive) are:
%
%      `'dwt'`
%         Plain DWT tree (default). This gives one band per octave freq. 
%         resolution when using 2 channel basic wavelet filter bank.
%
%      `'full'`
%         Full filter bank tree. Both (all) basic filter bank outputs are
%         decomposed further up to depth *J* achieving linear frequency band
%         division.
%
%      `'doubleband'`,`'quadband'`,`'octaband'`
%         The filter bank is designed such that it mimics 4-band, 8-band or
%         16-band complex wavelet transform provided the basic filter bank
%         is 2 channel. In this case, *J* is treated such that it defines
%         number of levels of 4-band, 8-band or 16-band transform.
%
%      The dual-tree wavelet filter bank can use any basic wavelet
%      filter bank in the first stage of both trees, provided they are 
%      shifted by 1 sample (done internally). A custom first stage 
%      filter bank can be defined by passing the following
%      key-value pair in the cell array:
%
%      `'first'`,`w` 
%         `w` defines a regular basic filter bank. Accepted formats are the
%         same as in |fwtinit| assuming the `wfilt_` prefix.
%
%      Similarly, when working with a filter bank tree containing
%      decomposition of high-pass outputs, some filters in both trees must
%      be replaced by a regular basic filter bank in order to achieve the
%      approximately analytic behaviour. A custom filter bank can be
%      specified by passing another key-value pair in the cell array:
%
%      `'leaf'`,`w` 
%         `w` defines a regular basic filter bank. Accepted formats are the
%         same as in |fwtinit| assuming the `wfilt_` prefix.      
%
%   2) Another possibility is to pass directly a struct. returned by 
%      |dtwfbinit| and possibly modified by |wfbtremove|. 
%
%   Optional args.:
%   ---------------
%
%   In addition, the following flag groups are supported:
%
%   `'freq'`,`'nat'`
%      Frequency or natural (Paley) ordering of coefficient subbands.
%      By default, subbands are ordered according to frequency. The natural
%      ordering is how the subbands are obtained from the filter bank tree
%      without modifications. The ordering differs only in non-plain DWT
%      case.
%
%   Boundary handling:
%   ------------------
%
%   In contrast with |fwt|, |wfbt| and |wpfbt|, this function supports
%   periodic boundary handling only.
%
%   Examples:
%   ---------
%   
%   A simple example of calling the |dtwfb| function using the regular
%   DWT iterated filter bank. The second figure shows a magnitude frequency
%   response of an identical filter bank.:::
% 
%     [f,fs] = greasy;
%     J = 6;
%     [c,info] = dtwfb(f,{'qshift3',J});
%     figure(1);
%     plotwavelets(c,info,fs,'dynrange',90);
%     figure(2);
%     [g,a] = dtwfb2filterbank({'qshift3',J});
%     filterbankfreqz(g,a,1024,'plot','linabs');
%
%   The second example shows a decomposition using a full filter bank tree
%   of depth *J*:::
%
%     [f,fs] = greasy;
%     J = 5;
%     [c,info] = dtwfb(f,{'qshift4',J,'full'});
%     figure(1);
%     plotwavelets(c,info,fs,'dynrange',90);
%     figure(2);
%     [g,a] = dtwfb2filterbank({'qshift4',J,'full'});
%     filterbankfreqz(g,a,1024,'plot','linabs');
%
%   See also: dtwfbreal idtwfb plotwavelets dtwfb2filterbank
%
%   References: king02 sebaki05 bayse08

% Author: Zdenek Prusa
% Date:   30.6.2014

complainif_notenoughargs(nargin,2,'DTWFB');

definput.import = {'wfbtcommon'};
flags =ltfatarghelper({},definput,varargin);

% Initialize the wavelet tree structure
dtw = dtwfbinit(dualwt,flags.forder);
    
%% ----- step 1 : Verify f and determine its length -------
[f,Ls]=comp_sigreshape_pre(f,upper(mfilename),0);

% Determine next legal input data length.
L = wfbtlength(Ls,dtw,'per');

% Pad with zeros if the safe length L differs from the Ls.
if(Ls~=L)
   f=postpad(f,L); 
end

%% ----- step 3 : Run computation
[nodesBF, rangeLoc, rangeOut] = treeBFranges(dtw);

c = comp_dtwfb(f,dtw.nodes(nodesBF),dtw.dualnodes(nodesBF),rangeLoc,...
               rangeOut,'per',1);

%% ----- Optionally : Fill info struct ----
if nargout>1
   % Transform name
   info.fname = 'dtwfb';
   % Dual-Tree struct.
   info.wt = dtw;
   % Periodic boundary handling
   info.ext = 'per';
   % Lengths of subbands
   info.Lc = cellfun(@(cEl) size(cEl,1),c);
   % Signal length
   info.Ls = Ls;
   % Ordering of the subbands
   info.fOrder = flags.forder;
   % Cell format
   info.isPacked = 0;
end


