function opfiles = calcbeatchroma(listfile,srcprepend,srcext, ...
                                  dstprepend,dstext,skip,fctr,fsd, ...
                                  tmean, tsd)
% calcbeatchroma(listfile,srcprepend,srcext,dstprepend,dstext,fctr,fsd,tmean,tsd)
%   Take listile, a list of input MP3 or WAV files and calculate 
%   beat-synchronous chroma features for each one. 
%   input file names each have srcprepend prepended and srcext appended;
%   features are written to .mat files with the same root name but
%   with dstprepend prepended and dstext appended.  First <skip>
%   items are skipped (for resumption of interrupted runs).
%   fctr and fsd specify a spectral window used to extract chroma 
%   elements with center at fctr Hz, and gaussian log-F half-width
%   of fsd octaves.
%   Return a cell array of the output files written.
% 2008-08-110 dpwe@ee.columbia.edu  after coversongs/src/calclistftrs

if nargin < 2; srcprepend = ''; end
if nargin < 3; srcext = ''; end
if nargin < 4; dstprepend = ''; end
if nargin < 5; dstext = ''; end
if nargin < 6; skip = 0; end
% downweight fundamentals below here
if nargin < 7; fctr = 400; end % or maybe 100 for bass
if nargin < 8; fsd = 1.0; end
if nargin < 9; ctype = 1; end
if nargin < 10; tmean = 240.0; end
if nargin < 11; tsd = 1.0; end

if exist('isp_ifchromagram') ~= 2
  addpath('isptoolbox');
end
if exist('mp3read') ~= 2
  addpath('mp3readwrite');
end

if iscell(listfile)
  files = listfile;
  listfile = 'passed in cell array';
else
  files = listfileread(listfile);
end
nfiles = length(files);

if nfiles < 1
  error(['No sound file names read from ',listfile]);
end

% preallocate to placate mlint
opfiles{nfiles} = '';

% Process every input file
for songn = 1:nfiles
  tline = files{songn};

  % figure out input file names
  if length(srcext) > 0
    if strcmp(tline(end-length(srcext)+1:end), srcext)
      % chop off srcext already there
      tline = tline(1:end-length(srcext));
    end
  else
    %% no srcext specified - must be part of input file name
    %% separate name and extension for input file
    %[srcpath, srcname, srcext] = fileparts(tline);
    %tline = fullfile(srcpath,srcname);
    
    % No, if ext not specified, just leave it in place
  end
    
  % So file names are:
  ifname = fullfile(srcprepend,[tline,srcext]);
  ofname = fullfile(dstprepend,[tline,dstext]);

  if fexist(ofname)
    disp(['Output file ',ofname,' exists - skipping']);
  else

    % header info for output file
    vsn = 20080810.0;
    desc = 'Classic beat-chroma matrices';

    if songn > skip

      % wav files or mp3 files
      if strcmp(srcext,'.mp3')
        [d,sr] = mp3read(ifname,'size');
        if sr >= 32000
          ds = 2;
        else
          ds = 1;
        end
        [d,sr] = mp3read(ifname,0,1,ds); 
      else
        [d,sr]=wavread(ifname);
        if size(d,2) == 2
          % collapse stereo data to mono
          d = d(:,1) + d(:,2);
        end
      end

      %      [F,bts] = chrombeatftrs(d,sr,fctr,fsd,ctype,tmean,tsd);
      % in-line now
      fftlen = 2 ^ (round(log(sr*(2048/22050))/log(2)));
      ffthop = fftlen/4;
      ifsr = sr/ffthop;
      nbin = 12;
      %Y = chromagram_IF(d,sr,fftlen,nbin,fctr,fsd);
      % Jesper Jensen's optimized version
      Y = isp_ifchromagram(d,sr,fftlen,nbin,fctr,fsd);

      % Get the beats for this tempo
      bts = beat2(d,sr,[tmean tsd],400,0);

      % condense the chroma per beat
      F = beatavg(Y,bts*ifsr);

      % Make sure the parent directory exists
      ofdir = fileparts(ofname);
      mymkdir(ofdir)

      % Write the data out
      save(ofname,'ifname','F','bts','tmean','tsd','fctr','fsd','vsn','desc');

      disp([datestr(rem(now,1),'HH:MM:SS'), ' song ',num2str(songn),' ', ...
            tline,' bpm=', sprintf('%.0f ',60/median(diff(bts)))]);

    end

  end
  
  opfiles{songn} = ofname;
  
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function X = beatavg(Y,bts)
% X = beatavg(Y,bys)
%    Calculate average of columns of Y according to grid defined 
%    (real-valued) column indices in vector bts.
%    For folding spectrograms down into beat-sync features.
% 2006-09-26 dpwe@ee.columbia.edu

% beat-based segments
%bts = beattrack(d,sr);
%bttime = mean(diff(bts));
% map beats to specgram slices
ncols = size(Y,2);
coltimes = 0:(ncols-1);
% Ensure last value is end of array, and it only occurs once
bts = bts(bts < max(coltimes));
btse = [bts,max(coltimes)];
nbts = length(bts);
cols2beats = zeros(nbts, ncols);
for b = 1:nbts
  cols2beats(b,:) = ((coltimes >= btse(b)) & (coltimes < btse(b+1)))*1/(btse(b+1)-btse(b));
end

% The actual desired output
X = Y * cols2beats';

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function r = mymkdir(dir)
% r = mymkdir(dir)
%   Ensure that dir exists by creating all its parents as needed.
% 2006-08-06 dpwe@ee.columbia.edu

[x,m,i] = fileattrib(dir);
if x == 0
  [pdir,nn] = fileparts(dir);
  disp(['creating ',dir,' ... ']);
  mymkdir(pdir);
  % trailing slash results in empty nn
  if length(nn) > 0
    mkdir(pdir, nn);
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function E = fexist(F)
%  E = fexist(F)  returns 1 if file F exists, else 0
% 2006-08-06 dpwe@ee.columbia.edu

x = dir(F);

E = length(x);
