function varargout = Huff06(xC, ArgLevel, ArgSpeed)
% Huff06 Huffman encoder/decoder with (or without) recursive splitting
% Vectors of integers are Huffman encoded,
% these vectors are collected in a cell array, xC.
% If first argument is a cell array the function do encoding,
% else decoding is done.
%
% [y, Res] = Huff06(xC, Level, Speed); % encoding
% y = Huff06(xC); % encoding
% xC = Huff06(y); % decoding
% ------------------------------------------------------------------
% Arguments:
% y a column vector of non-negative integers (bytes) representing
% the code, 0 <= y(i) <= 255.
% Res a matrix that sum up the results, size is (NumOfX+1)x4
% one line for each of the input sequences, the columns are
% Res(:,1) - number of elements in the sequence
% Res(:,2) - zero-order entropy of the sequence
% Res(:,3) - bits needed to code the sequence
% Res(:,4) - bit rate for the sequence, Res(:,3)/Res(:,1)
% Then the last line is total (which include bits needed to store NumOfX)
% xC a cell array of column vectors of integers representing the
% symbol sequences. (should not be to large integers)
% If only one sequence is to be coded, we must make the cell array
% like: xC=cell(2,1); xC{1}=x; % where x is the sequence
% Level How many levels of splitting that is allowed, legal values 1-8
% If Level=1, no further splitting of the sequences will be done
% and there will be no recursive splitting.
% Speed For complete coding set Speed to 0. Set Speed to 1 to cheat
% during encoding, y will then be a sequence of zeros only,
% but it will be of correct length and the other output
% arguments will be correct.
% ------------------------------------------------------------------
% SOME NOTES ON THE FUNCTION
% huff06 depends on other functions for Huffman code, and the functions in this file
% HuffLen - find length of codewords (HL)
% HuffTabLen - find bits needed to store Huffman table information (HL)
% HuffCode - find huffman codewords
% HuffTree - find huffman tree
%----------------------------------------------------------------------
% Copyright (c) 1999-2000. Karl Skretting. All rights reserved.
% Hogskolen in Stavanger (Stavanger University), Signal Processing Group
% Mail: karl.skretting@tn.his.no Homepage: http://www.ux.his.no/~karlsk/
%
% HISTORY:
% Ver. 1.0 13.06.2000 KS: Function made based on huff04
% Ver. 1.1 20.06.2000 KS: Handle some more exceptions
% Ver. 1.2 21.06.2000 KS: Handle also negative values
% Ver. 1.3 23.06.2000 KS: Use logarithms for some sequences (line 114)
% Ver. 1.4 31.07.2000 KS: If a sequence has many zeros, Run + Value coding
% is done. (from line 255 and some more)
% Ver. 1.5 02.08.2000 KS: May have larger integers in PutVLIC and GetVLIC
% Ver. 1.6 18.01.2001 KS: MaxL in line 218 was reduced from 2^16 to 50000.
% For some sequences we may have length of code word larger than 16, even
% if probability was larger than 2^(-16). Ex: Hi=[12798,14241,7126,7159,3520,...
% 3512,1857,1799,1089,1092,681,680,424,431,320,304,201,204,115,118,77,83,45,...
% 40,24,26,18,14,4,12,3,3,4,2,2,0,1]', sum(Hi)=58029
% Ver. 1.7 21.08.2001 KS: MaxL in line 218 and 420 must be the same
% We may now have long code words (also see HuffTabLen.m)
%----------------------------------------------------------------------
global y Byte BitPos Speed Level
Mfile='Huff06';
Debug=0; % note Debug is defined in EncodeVector and DecodeVector too
% check input and output arguments, and assign values to arguments
if (nargin < 1);
error([Mfile,': function must have input arguments, see help.']);
end
if (nargout < 1);
error([Mfile,': function must have output arguments, see help.']);
end
if (~iscell(xC))
Encode=0;Decode=1;
y=xC(:); % first argument is y
else
Encode=1;Decode=0;
if (nargin < 3); Speed=0; else Speed=ArgSpeed; end;
if (nargin < 2); Level=8; else Level=ArgLevel; end;
if ((length(Speed(:))~=1));
error([Mfile,': Speed argument is not scalar, see help.']);
end
if Speed; Speed=1; end;
if ((length(Level(:))~=1));
error([Mfile,': Level argument is not scalar, see help.']);
end
Level=floor(Level);
if (Level < 1); Level=1; end;
if (Level > 8); Level=8; end;
NumOfX = length(xC);
end
if Encode
Res=zeros(NumOfX,4);
% initalize the global variables
y=zeros(10,1); % put some zeros into y initially
Byte=0;BitPos=1; % ready to write into first position
% start encoding, first write VLIC to give number of sequences
PutVLIC(NumOfX);
if Debug
disp([Mfile,' (Encode): Level=',int2str(Level),' Speed=',int2str(Speed),...
' NumOfX=',int2str(NumOfX)]);
end
% now encode each sequence continuously
Ltot=0;
for num=1:NumOfX
x=xC{num};
x=full(x(:)); % make sure x is a non-sparse column vector
L=length(x);Ltot=Ltot+L;
y=[y(1:Byte);zeros(50+2*L,1)]; % make more space available in y
% now find some info about x to better code it
maxx=max(x);
minx=min(x);
if (minx<0)
Negative=1;
else
Negative=0;
end
if ( (((maxx*4)>L) | (maxx>1023)) & (L>1) & (maxx>minx))
% the test for LogCode could be better, I think, (ver. 1.3)
LogCode=1; % this could be 0 if LogCode is not wanted
else
LogCode=0;
end
PutBit(LogCode);
PutBit(Negative);
I=find(x); % non-zero entries in x
Sg=(sign(x(I))+1)/2; % the signs may be needed later, 0/1
x=abs(x);
if LogCode
xa=x; % additional bits
x(I)=floor(log2(x(I)));
xa(I)=xa(I)-2.^x(I);
x(I)=x(I)+1;
end
[bits, ent]=EncodeVector(x); % store the (abs and/or log) values
if Negative % store the signs
for i=1:length(Sg); PutBit(Sg(i)); end;
bits=bits+length(Sg);
ent=ent+length(Sg)/L;
end
if LogCode % store the additional bits
for i=1:L
for ii=(x(i)-1):(-1):1
PutBit(bitget(xa(i),ii));
end
end
bits=bits+sum(x)-length(I);
ent=ent+(sum(x)-length(I))/L;
end
if L>0; Res(num,1)=L; else Res(num,1)=1; end;
Res(num,2)=ent;
Res(num,3)=bits;
end
y=y(1:Byte);
varargout(1) = {y};
if (nargout >= 2)
% now calculate results for the total
if Ltot<1; Ltot=1; end; % we do not want Ltot to be zero
Res(NumOfX+1,3)=Byte*8;
Res(NumOfX+1,1)=Ltot;
Res(NumOfX+1,2)=sum(Res(1:NumOfX,1).*Res(1:NumOfX,2))/Ltot;
Res(:,4)=Res(:,3)./Res(:,1);
varargout(2) = {Res};
end
end
if Decode
% initalize the global variables, y is set earlier
Byte=0;BitPos=1; % ready to read from first position
NumOfX=GetVLIC; % first read number of sequences
if Debug
disp([Mfile,'(Decode): NumOfX=',int2str(NumOfX),' length(y)=',int2str(length(y))]);
end
xC=cell(NumOfX,1);
for num=1:NumOfX
LogCode=GetBit;
Negative=GetBit;
x=DecodeVector; % get the (abs and/or log) values
L=length(x);
I=find(x);
if Negative
Sg=zeros(size(I));
for i=1:length(I); Sg(i)=GetBit; end; % and the signs (0/1)
Sg=Sg*2-1; % (-1/1)
else
Sg=ones(size(I));
end
if LogCode % read additional bits too