Code covered by the BSD License  

Highlights from
Framing Routines

image thumbnail
from Framing Routines by Kamil Wojcicki
Functions for division of a vector into overlapped frames and its reconstruction back from frames.

frames2vec( frames, Ns, direction, window, synthesis )
function [ vec ] = frames2vec( frames, Ns, direction, window, synthesis )
% FRAMES2VEC Converts frames to signal using weighted overlap-and-add synthesis. 
%
%   A=FRAMES2VEC(B,N,D,W,S) converts frames in matrix B (stored as rows 
%   or columns as specified by D) into signal using weighted overlap-and-add
%   procedure specified by synthesis window W and synthesis type S.
%
%   Summary
%
%           B is a matrix of frames
%
%           N is a frame shift (in samples) originally used to split 
%             the signal into frames; alternatively, N can specify the matrix 
%             of indexes originally used to split the signal into frames
%             (i.e., the second output argument of the VEC2FRAMES function)
%
%           D specifies if the frames in B are rows or columns,
%             i.e., D = 'rows' or 'cols', respectively
%
%           W is the synthesis window function to be applied to each frame,
%             given as either a function handle, e.g., W = @hanning
%             or as a vector of window samples, e.g., W = hanning( M )
%
%           S specifies overlap-and-add synthesis of one of three types:  
%                   S = 'A&R';      % Allen & Rabiner's method
%                   S = 'G&L';      % Griffin & Lim's method
%                   S = 'Vanilla';  % Vanilla approach (no synthesis window)
%
%           A is the synthesized output signal 
%
%   Examples
%
%           % generate input signal samples
%           signal = [ 1:20 ]
%
%           % divide the input signal into seven-sample-long frames with a shift
%           % of three samples, pad the last frame with zeros so that no samples 
%           % are discarded, apply the Hanning analysis window to each frame and
%           % return frames as columns vectors
%           frames = vec2frames( signal, 7, 3, 'cols', @hanning, 0 )
%
%           % synthesize the frames back to signal using weighted overlap-and-add
%           % procedure; note the extra padding on the reconstructed signal
%           reconstructed = frames2vec( frames, 3, 'cols', @hanning, 'G&L' )
% 
%   See also VEC2FRAMES, DEMO

%   Author: Kamil Wojcicki, UTD, July 2011


    % usage information
    usage = 'usage: [ vec ] = frames2vec( frames, indexes, direction, window, synthesis );';

    % default settings 
    switch( nargin )
    case { 0, 1, 2 }, error( usage );
    case 3, synthesis='G&L'; window=@hanning; 
    case 4, synthesis='G&L'; 
    end

    % input validation
    if( isempty(frames) || isempty(Ns) || isempty(direction) ), error( usage ); end;
    if( Ns<1 ), error( usage ); end;


    % process based on frame direction
    switch( direction )

    % rows as frames
    case 'rows'     

        % get number of frames and frame length
        [ M, Nw ] = size( frames );

        if( length(Ns)==1 )
            % if frame duration provided, generate framing indexes
            indf = Ns*[ 0:(M-1) ].';                          % indexes for frames      
            inds = [ 1:Nw ];                                  % indexes for samples
            indexes = indf(:,ones(1,Nw)) + inds(ones(M,1),:); % framing indexes
        else 
            % otherwise, framing indexes were provided
            indexes = Ns;
            Ns = indexes(2,1)-indexes(1,1);
        end

        % determine signal duration
        L = max(indexes(:));

        % if synthesis window provided as a function handle
        % then generate synthesis window samples
        if( isa(window,'function_handle') )
            window = window( Nw );
        end
        window = window(:).';

        % allocate storage
        vec = zeros(1, L); 
        wsum = zeros(1, L); 

        % overlap-and-add syntheses 
        switch(upper(synthesis))
    
        % Allen & Rabiner's method
        case {'ALLEN & RABINER','A&R'}                   
    
            % overlap-and-add frames
            for m = 1:M, vec(indexes(m,:)) = vec(indexes(m,:)) + frames(m,:); end;

            % overlap-and-add window samples
            for m = 1:M, wsum(indexes(m,:)) = wsum(indexes(m,:)) + window; end;

            % for some tapered analysis windows, endpoint samples are very close 
            % to zero; as a consequence of this, wsum can be very close to
            % zero at its endpoints; division of vec by wsum at points where 
            % wsum is close to zero can produce large impulses; if you are 
            % experiencing this issue, one approach to address this is to limit
            % the lower bound of wsum as follows:
            %
            % wsum( wsum<1E-2 ) = 1E-2;  

            % divide out summed-up analysis windows
            vec = vec./wsum;
    
        % Griffin & Lim's method
        case {'GRIFFIN & LIM','G&L'}
    
            % apply synthesis window
            frames = frames * diag( window );

            % overlap-and-add frames
            for m = 1:M, vec(indexes(m,:)) = vec(indexes(m,:)) + frames(m,:); end;

            % overlap-and-add squared window samples
            for m = 1:M, wsum(indexes(m,:)) = wsum(indexes(m,:)) + window.^2; end;

            % for some tapered analysis windows, endpoint samples are very close 
            % to zero; as a consequence of this, wsum can be very close to
            % zero at its endpoints; division of vec by wsum at points where 
            % wsum is close to zero can produce large impulses; if you are 
            % experiencing this issue, one approach to address this is to limit
            % the lower bound of wsum as follows:
            %
            % wsum( wsum<1E-2 ) = 1E-2;  

            % divide out squared and summed-up analysis/synthesis windows
            vec = vec./wsum;

        % vanilla approach
        case {'VANILLA'}

            % overlap-and-add frames
            for m = 1:M, vec(indexes(m,:)) = vec(indexes(m,:)) + frames(m,:); end;
    
        % unsupported approach
        otherwise

            error(sprintf('%s: synthesis type not supported.', synthesis));
    
        end 


    % columns as frames
    case 'cols'

        % get frame length and the number of frames 
        [ Nw, M ] = size( frames );

        if( length(Ns)==1 )
            % if frame duration provided, generate framing indexes
            indf = Ns*[ 0:(M-1) ];                            % indexes for frames      
            inds = [ 1:Nw ].';                                % indexes for samples
            indexes = indf(ones(Nw,1),:) + inds(:,ones(1,M)); % framing indexes
        else
            % otherwise, framing indexes were provided
            indexes = Ns;
            Ns = indexes(1,2)-indexes(1,1);
        end

        % determine signal duration
        L = max(indexes(:));

        % if synthesis window provided as a function handle
        % then generate synthesis window samples
        if( isa(window,'function_handle') )
            window = window( Nw );
        end
        window = window(:);

        % allocate storage
        vec = zeros(L, 1); 
        wsum = zeros(L, 1); 
       
        % overlap-and-add syntheses 
        switch(upper(synthesis))
    
        % Allen & Rabiner's method
        case {'ALLEN & RABINER','A&R'}                   
    
            % overlap-and-add frames
            for m = 1:M, vec(indexes(:,m)) = vec(indexes(:,m)) + frames(:,m); end;

            % overlap-and-add window samples
            for m = 1:M, wsum(indexes(:,m)) = wsum(indexes(:,m)) + window; end;

            % for some tapered analysis windows, endpoint samples are very close 
            % to zero; as a consequence of this, wsum can be very close to
            % zero at its endpoints; division of vec by wsum at points where 
            % wsum is close to zero can produce large impulses; if you are 
            % experiencing this issue, one approach to address this is to limit
            % the lower bound of wsum as follows:
            %
            % wsum( wsum<1E-2 ) = 1E-2;  

            % divide out summed-up analysis windows
            vec = vec./wsum;
    
        % Griffin & Lim's method
        case {'GRIFFIN & LIM','G&L'}
    
            % apply synthesis window
            frames = diag( window ) * frames;

            % overlap-and-add frames
            for m = 1:M, vec(indexes(:,m)) = vec(indexes(:,m)) + frames(:,m); end;

            % overlap-and-add squared window samples
            for m = 1:M, wsum(indexes(:,m)) = wsum(indexes(:,m)) + window.^2; end;

            % for some tapered analysis windows, endpoint samples are very close 
            % to zero; as a consequence of this, wsum can be very close to
            % zero at its endpoints; division of vec by wsum at points where 
            % wsum is close to zero can produce large impulses; if you are 
            % experiencing this issue, one approach to address this is to limit
            % the lower bound of wsum as follows:
            %
            % wsum( wsum<1E-2 ) = 1E-2;  

            % divide out squared and summed-up analysis/synthesis windows
            vec = vec./wsum;
    
        % vanilla approach
        case {'VANILLA'}

            % overlap-and-add frames
            for m = 1:M, vec(indexes(:,m)) = vec(indexes(:,m)) + frames(:,m); end;
    
        % unsupported approach
        otherwise

            error(sprintf('%s: synthesis type not supported.', synthesis));

        end

    end


% EOF 

Contact us