function hmm=hmmFromFile(name)
%HMMFROMFILE Loads hmm from HTK format file
%
%   hmm=hmmFromFile(name)
%
% returns structure hmm which has fields
% 
%   states is an array of 'state' structures
%   pNext     array of next state (log) probs
%   pSelf     array of same state (log) probs
% 
%

fid = fopen(name,'r');
if fid == -1
  error(['hmmFromFile: file ' name ' not found']);
end

finish = 1;
numMixes=1;   % in case none are specified
mixWeights=1;
currentMixture=1;
% hmm=emptyhmm;

string=fscanf(fid,'%s',1);
while string|finish
  switch string
  case {'<BeginHMM>','<NULLD>','<FBANK>','<DIAGC>'}
  
  case '<NumStates>'
    numStates = fscanf(fid,'%d', 1);
  
  case '<StreamInfo>'
    dummy = fscanf(fid,'%d', 2);
    
  case '<VecSize>'
    vecSize = fscanf(fid,'%d', 1);
    
  case '<State>'
    % we reach a new state: decrement to ignore HTK convention
    currentState = fscanf(fid,'%d', 1) - 1;
    
  case '<NumMixes>'
    % for the current state
    numMixes = fscanf(fid,'%d', 1);
    % allocate storage for this state
    mu = zeros(numMixes,vecSize);
    var = zeros(numMixes,vecSize);
    mixWeights = zeros(numMixes);
        
  case '<Mixture>'
    currentMixture = fscanf(fid,'%d', 1);
    % convert to logs on read in
    mixWeights(currentMixture) = log(fscanf(fid,'%g', 1));

  case '<Mean>'
    currentVecSize = fscanf(fid,'%d', 1);
    if (currentVecSize ~= vecSize)
      error('hmmFromFile: mean vector size inconsistency');
    end
    mu(currentMixture,:) = fscanf(fid,'%g',currentVecSize)';
  
  case '<Variance>'
    currentVecSize = fscanf(fid,'%d', 1);
    if (currentVecSize ~= vecSize)
      error('hmmFromFile: var vector size inconsistency');
    end
    var(currentMixture,:) = fscanf(fid,'%g',currentVecSize)';
  
  case '<GConst>'
    gConsts(currentMixture) = fscanf(fid,'%g', 1);
    % we have now got a complete state, so make an object of it
    s=emptystate;
    s.numMixes=numMixes;
    s.mu=mu;
    s.var=var;
    s.sd=sqrt(var);
    s.mixWeights=mixWeights;   
    s.logvar2pi = log(2*pi*var);
    states(currentState)=s;

  case '<TransP>'
    tpSize = fscanf(fid,'%d', 1);
    % check that it is commensurate with the number of states
    if (tpSize ~= numStates)
      error('hmmFromFile: trans size inconsistency');
    end
    tpmatrix = reshape(fscanf(fid,'%g',numStates*numStates), numStates, numStates);
    % just extract part of the diagonal
    trans = diag(tpmatrix(2:numStates-1,2:numStates-1));
  
  case '<EndHMM>'
    finish=0;
    
  otherwise
    disp(['hmmFromFile: unknown keyword ' string]);
  end;
  string=fscanf(fid,'%s',1);
end;
fclose(fid);

hmm.states=states;
hmm.pNext = log(ones(length(trans),1)-trans);
hmm.pSelf = log(trans);
hmm.label = name(length(name));
hmm.numStates=length(states);

%------------------------
function s=emptystate;

s.numMixes = [];
s.mu = [];
s.var = [];
s.sd = [];
s.mixWeights = [];
s.logvar2pi = [];