% FUNCTION [ OUT, P ] = ENERGY( IN_P )
%
% Version 1 - 040223
% By Guillaume Lathoud at IDIAP - lathoud@idiap.ch
%
% Compute energy of hamming-windowed frames from a WAV file.
% 
% %%%%%%%%%%
% INPUT PARAMETERS
%
% IN_P can contain many parameter fields, of which one is mandatory:
%
% - IN_P.IN_NAME:  string, name of the WAV file.
%
% For other parameters (frame length, frame shift...) look at the
% code:     dbtype energy
%
% %%%%%%%%%%
% OUTPUT PARAMETERS
%
% - OUT: 2 x N_FRAMES matrix
%   - first row are frame indices
%   - second row are energy values
% 
% Note that we use the 'periodic' Hamming window, and that energy of
% window samples "X" is computed as "mean( ( X .* W ) .^ 2 )" where W are the
% Hamming window coefficients. Therefore the energy value is normalized
% by the length of the window.

% - P: same parameter structure as IN_P, enriched with default values
% where needed + sampling frequency P.FS of the WAV file.

function [ out, p ] = energy( in_p )

  if nargin < 1
    error( 'energy needs one input argument' );
  end

  p = in_p;
  
  if nargout < 1
    error( 'energy needs at least one output argument' );
  end
  
  required_param = { 'in_name'  };
  check_param( required_param, fieldnames( p ) );
  
  % All frames by default
  %
  % A typical value would be:
  %   p.frame_list = [ 10 15; 17 19];
  % -> treat frames 10 to 15, and 17 to 19
  p_default.frame_list = [-Inf +Inf];  % Means first to last

  % Parameters for energy computation
  p_default.frame_length_sec = 0.032;  % in seconds
  p_default.frame_shift_sec  = [];   % in seconds, half frame length by default (see below)

  p_default.verbose = 1;
  p_default.verbose_time = 10;  % seconds between two messages
  
  p = fill_default( p, p_default );
  
  if isempty(p.frame_shift_sec)
    p.frame_shift_sec = p.frame_length_sec / 2;
  end
  
  % Verbosity

  if p.verbose
    disp( '--------------------------------------------------' );
    disp( 'energy parameters:' );
    disp( p );

    disp( 'energy: p.in_name=' );
    disp( [ '''' p.in_name '''' ] );

  end  

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % 2) Open WAV file
  
  if p.verbose
    disp( 'energy: opening WAV file...' );
  end
  
  siz = wavread( p.in_name, 'size' );
  n_samples = siz( 1 );
  if siz( 2 ) ~= 1
    error( [ 'energy: problem with ' p.in_name ' - I' ...
	     ' can only deal with monochannel files.' ] );
  end

  % Get sampling frequency
  [ y, fs ] = wavread( p.in_name, 1 );
  frame_length = round( fs * p.frame_length_sec );
  frame_shift  = round( fs * p.frame_shift_sec );
  
  % Define frames

  f_start  = frame_start( n_samples, frame_length, frame_shift );
  n_frames = length( f_start );
  
  % Make sure we don't go beyond the beginning or end of the file
  % This inherently replace "-Inf" and "+Inf" values
  p.frame_list = min( p.frame_list, n_frames );
  p.frame_list = max( p.frame_list, 1 );
  
  % How many frames are we going to proceed?
  
  aux = p.frame_list;
  aux(:,1) = 1 - aux(:,1);
  n_frames_to_proceed = sum(aux(:));
    
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % 6) Proceed waveform (loop through time frames)
  
  if p.verbose
    disp( '--------------------------------------------------' );
    disp( 'energy: processing waveform...' );
  end
  
  % Prepare memory for output
  out = repmat( NaN, 2, n_frames_to_proceed );
  
  x = repmat( NaN, frame_length, 1 );
  win = hamming( frame_length, 'periodic' );
  
  if p.verbose
    chrono = chrono_start( n_frames_to_proceed, p.verbose_time );
  end
  
  frames_done = 0;
  for a = 1:size( p.frame_list, 1 )
    for b = p.frame_list( a, 1 ):p.frame_list( a, 2 )
      
      if p.verbose & ( n_frames_to_proceed < 100 )
	disp( sprintf( 'Working on frame #%d...', b ) );
      end

      % Store the frame index
      out( 1, frames_done+1 ) = b;
      
      % Read data
      s = f_start( b );
      e = s + frame_length - 1;
      x = wavread( p.in_name, [ s e ] );

      % Apply hamming window and compute energy
      out( 2, frames_done + 1 ) = mean( ( x .* win ) .^ 2 );
            
      % Count frames
      
      frames_done = frames_done + 1;
      
      if p.verbose
	chrono = chrono_check( chrono, frames_done );
      end
      
    end
  end
  
  if p.verbose
    chrono_stop( chrono );
    disp( 'energy: done.' );
    disp( '--------------------------------------------------' );
  end
  
  % Return sampling frequency
  p.fs = fs;
  