function [adapGainIndices, adapVecIndices] = ... 
    clltp( target, a, subblockLength, minDelay, adapGainCB, lpcInputPast )
% function [adapGainIndices, adapVecIndices] =
%     clltp( target, subblockLength, minDelay, adapGainCB, lpcInputPast )
%
% Closed-Loop LTP Filter (Analysis-by-Synthesis)
%
% target:             input vector
% a: 		      linear prediction coefficients	 
% subblockLength:     adapInputBlock is devided in subblocks of size subblockLength
% minDelay:           minimal delay (maximal delay is determined by size of adapInputPast)	
% adapGainCB:	      codebook for quantization of adaptive gains
% lpcInputPast:       old excitation of LPC filter
% 
% adapGainIndices:    vector containing adap gain indicess (size: number of subblocks in adapInputBlock)		
% adapVecIndices      vector containing adap indices (size: number of subblocks in adapInputBlock)
%  
% Author:  Markus Hauenstein
% Date:    05.01.2002 
% Contact: www.markus-hauenstein.de

blockLength = length(target);
maxDelay = length(lpcInputPast);
numberOfSubblocks = blockLength / subblockLength;
lpcOrder = length(a);
zInvLpc = zeros(lpcOrder,1);

adapVecCBSize = maxDelay-minDelay+1;
adapVecCB = zeros(subblockLength,adapVecCBSize);
synFilterOutSignals = zeros(subblockLength,adapVecCBSize);


if numberOfSubblocks ~= floor(blockLength / subblockLength), 
  error( 'clltp: blockLength and subblockLength do not fit' )
end

adapGainIndices = zeros(numberOfSubblocks,1);
adapVecIndices = zeros(numberOfSubblocks,1);

% construct adaptive codebook 

if minDelay < subblockLength/2,
  error( 'clltp: Cannot construct adaptive codebook' )
end

if minDelay >= subblockLength,
  for l = 1:adapVecCBSize,
    adapVecCB(:,l) = lpcInputPast(l:l+subblockLength-1);
  end
else
  lMax = maxDelay - subblockLength + 1;
  for l = 1:lMax,
    adapVecCB(:,l) = lpcInputPast(l:l+subblockLength-1);
  end
  for l = lMax+1:adapVecCBSize,
    index1 = l:maxDelay;
    missing = subblockLength - (maxDelay-l+1);
    index2 = l:l+missing-1;
    index = [index1,index2];
    adapVecCB(:,l) = lpcInputPast(index);
  end
end


subblockIndex = 1 : subblockLength;

for j=1:numberOfSubblocks,

  % calculate filter outputs
  for l=1:adapVecCBSize,
    synFilterOutSignals(:,l) = filter( 1, [1;-a], adapVecCB(:,l), zInvLpc );
  end

  % Vector quantization of target subblock   
  [bestAdapGainIndex, bestAdapVecIndex] = ...
      gsvecq( target(subblockIndex), adapGainCB, synFilterOutSignals );

  adapGainIndices(j) = bestAdapGainIndex;
  adapVecIndices(j) = bestAdapVecIndex;

  bestAdapInput = adapGainCB(bestAdapGainIndex) * adapVecCB(bestAdapVecIndex);
  [dummy, zInvLpc] = filter(1, [1;-a], bestAdapInput, zInvLpc);

  % set indices for next subblock
  subblockIndex = subblockIndex + subblockLength;   
end
