Chris@1: % -*- mode: latex; TeX-master: "Vorbis_I_spec"; -*- Chris@1: %!TEX root = Vorbis_I_spec.tex Chris@1: % $Id$ Chris@1: \section{Residue setup and decode} \label{vorbis:spec:residue} Chris@1: Chris@1: \subsection{Overview} Chris@1: Chris@1: A residue vector represents the fine detail of the audio spectrum of Chris@1: one channel in an audio frame after the encoder subtracts the floor Chris@1: curve and performs any channel coupling. A residue vector may Chris@1: represent spectral lines, spectral magnitude, spectral phase or Chris@1: hybrids as mixed by channel coupling. The exact semantic content of Chris@1: the vector does not matter to the residue abstraction. Chris@1: Chris@1: Whatever the exact qualities, the Vorbis residue abstraction codes the Chris@1: residue vectors into the bitstream packet, and then reconstructs the Chris@1: vectors during decode. Vorbis makes use of three different encoding Chris@1: variants (numbered 0, 1 and 2) of the same basic vector encoding Chris@1: abstraction. Chris@1: Chris@1: Chris@1: Chris@1: \subsection{Residue format} Chris@1: Chris@1: Residue format partitions each vector in the vector bundle into chunks, Chris@1: classifies each chunk, encodes the chunk classifications and finally Chris@1: encodes the chunks themselves using the the specific VQ arrangement Chris@1: defined for each selected classification. Chris@1: The exact interleaving and partitioning vary by residue encoding number, Chris@1: however the high-level process used to classify and encode the residue Chris@1: vector is the same in all three variants. Chris@1: Chris@1: A set of coded residue vectors are all of the same length. High level Chris@1: coding structure, ignoring for the moment exactly how a partition is Chris@1: encoded and simply trusting that it is, is as follows: Chris@1: Chris@1: \begin{itemize} Chris@1: \item Each vector is partitioned into multiple equal sized chunks Chris@1: according to configuration specified. If we have a vector size of Chris@1: \emph{n}, a partition size \emph{residue\_partition\_size}, and a total Chris@1: of \emph{ch} residue vectors, the total number of partitioned chunks Chris@1: coded is \emph{n}/\emph{residue\_partition\_size}*\emph{ch}. It is Chris@1: important to note that the integer division truncates. In the below Chris@1: example, we assume an example \emph{residue\_partition\_size} of 8. Chris@1: Chris@1: \item Each partition in each vector has a classification number that Chris@1: specifies which of multiple configured VQ codebook setups are used to Chris@1: decode that partition. The classification numbers of each partition Chris@1: can be thought of as forming a vector in their own right, as in the Chris@1: illustration below. Just as the residue vectors are coded in grouped Chris@1: partitions to increase encoding efficiency, the classification vector Chris@1: is also partitioned into chunks. The integer elements of each scalar Chris@1: in a classification chunk are built into a single scalar that Chris@1: represents the classification numbers in that chunk. In the below Chris@1: example, the classification codeword encodes two classification Chris@1: numbers. Chris@1: Chris@1: \item The values in a residue vector may be encoded monolithically in a Chris@1: single pass through the residue vector, but more often efficient Chris@1: codebook design dictates that each vector is encoded as the additive Chris@1: sum of several passes through the residue vector using more than one Chris@1: VQ codebook. Thus, each residue value potentially accumulates values Chris@1: from multiple decode passes. The classification value associated with Chris@1: a partition is the same in each pass, thus the classification codeword Chris@1: is coded only in the first pass. Chris@1: Chris@1: \end{itemize} Chris@1: Chris@1: Chris@1: \begin{center} Chris@1: \includegraphics[width=\textwidth]{residue-pack} Chris@1: \captionof{figure}{illustration of residue vector format} Chris@1: \end{center} Chris@1: Chris@1: Chris@1: Chris@1: \subsection{residue 0} Chris@1: Chris@1: Residue 0 and 1 differ only in the way the values within a residue Chris@1: partition are interleaved during partition encoding (visually treated Chris@1: as a black box--or cyan box or brown box--in the above figure). Chris@1: Chris@1: Residue encoding 0 interleaves VQ encoding according to the Chris@1: dimension of the codebook used to encode a partition in a specific Chris@1: pass. The dimension of the codebook need not be the same in multiple Chris@1: passes, however the partition size must be an even multiple of the Chris@1: codebook dimension. Chris@1: Chris@1: As an example, assume a partition vector of size eight, to be encoded Chris@1: by residue 0 using codebook sizes of 8, 4, 2 and 1: Chris@1: Chris@1: \begin{programlisting} Chris@1: Chris@1: original residue vector: [ 0 1 2 3 4 5 6 7 ] Chris@1: Chris@1: codebook dimensions = 8 encoded as: [ 0 1 2 3 4 5 6 7 ] Chris@1: Chris@1: codebook dimensions = 4 encoded as: [ 0 2 4 6 ], [ 1 3 5 7 ] Chris@1: Chris@1: codebook dimensions = 2 encoded as: [ 0 4 ], [ 1 5 ], [ 2 6 ], [ 3 7 ] Chris@1: Chris@1: codebook dimensions = 1 encoded as: [ 0 ], [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ] Chris@1: Chris@1: \end{programlisting} Chris@1: Chris@1: It is worth mentioning at this point that no configurable value in the Chris@1: residue coding setup is restricted to a power of two. Chris@1: Chris@1: Chris@1: Chris@1: \subsection{residue 1} Chris@1: Chris@1: Residue 1 does not interleave VQ encoding. It represents partition Chris@1: vector scalars in order. As with residue 0, however, partition length Chris@1: must be an integer multiple of the codebook dimension, although Chris@1: dimension may vary from pass to pass. Chris@1: Chris@1: As an example, assume a partition vector of size eight, to be encoded Chris@1: by residue 0 using codebook sizes of 8, 4, 2 and 1: Chris@1: Chris@1: \begin{programlisting} Chris@1: Chris@1: original residue vector: [ 0 1 2 3 4 5 6 7 ] Chris@1: Chris@1: codebook dimensions = 8 encoded as: [ 0 1 2 3 4 5 6 7 ] Chris@1: Chris@1: codebook dimensions = 4 encoded as: [ 0 1 2 3 ], [ 4 5 6 7 ] Chris@1: Chris@1: codebook dimensions = 2 encoded as: [ 0 1 ], [ 2 3 ], [ 4 5 ], [ 6 7 ] Chris@1: Chris@1: codebook dimensions = 1 encoded as: [ 0 ], [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ] Chris@1: Chris@1: \end{programlisting} Chris@1: Chris@1: Chris@1: Chris@1: \subsection{residue 2} Chris@1: Chris@1: Residue type two can be thought of as a variant of residue type 1. Chris@1: Rather than encoding multiple passed-in vectors as in residue type 1, Chris@1: the \emph{ch} passed in vectors of length \emph{n} are first Chris@1: interleaved and flattened into a single vector of length Chris@1: \emph{ch}*\emph{n}. Encoding then proceeds as in type 1. Decoding is Chris@1: as in type 1 with decode interleave reversed. If operating on a single Chris@1: vector to begin with, residue type 1 and type 2 are equivalent. Chris@1: Chris@1: \begin{center} Chris@1: \includegraphics[width=\textwidth]{residue2} Chris@1: \captionof{figure}{illustration of residue type 2} Chris@1: \end{center} Chris@1: Chris@1: Chris@1: \subsection{Residue decode} Chris@1: Chris@1: \subsubsection{header decode} Chris@1: Chris@1: Header decode for all three residue types is identical. Chris@1: \begin{programlisting} Chris@1: 1) [residue\_begin] = read 24 bits as unsigned integer Chris@1: 2) [residue\_end] = read 24 bits as unsigned integer Chris@1: 3) [residue\_partition\_size] = read 24 bits as unsigned integer and add one Chris@1: 4) [residue\_classifications] = read 6 bits as unsigned integer and add one Chris@1: 5) [residue\_classbook] = read 8 bits as unsigned integer Chris@1: \end{programlisting} Chris@1: Chris@1: \varname{[residue\_begin]} and Chris@1: \varname{[residue\_end]} select the specific sub-portion of Chris@1: each vector that is actually coded; it implements akin to a bandpass Chris@1: where, for coding purposes, the vector effectively begins at element Chris@1: \varname{[residue\_begin]} and ends at Chris@1: \varname{[residue\_end]}. Preceding and following values in Chris@1: the unpacked vectors are zeroed. Note that for residue type 2, these Chris@1: values as well as \varname{[residue\_partition\_size]}apply to Chris@1: the interleaved vector, not the individual vectors before interleave. Chris@1: \varname{[residue\_partition\_size]} is as explained above, Chris@1: \varname{[residue\_classifications]} is the number of possible Chris@1: classification to which a partition can belong and Chris@1: \varname{[residue\_classbook]} is the codebook number used to Chris@1: code classification codewords. The number of dimensions in book Chris@1: \varname{[residue\_classbook]} determines how many Chris@1: classification values are grouped into a single classification Chris@1: codeword. Note that the number of entries and dimensions in book Chris@1: \varname{[residue\_classbook]}, along with Chris@1: \varname{[residue\_classifications]}, overdetermines to Chris@1: possible number of classification codewords. Chris@1: If \varname{[residue\_classifications]}\^{}\varname{[residue\_classbook]}.dimensions Chris@1: exceeds \varname{[residue\_classbook]}.entries, the Chris@1: bitstream should be regarded to be undecodable. Chris@1: Chris@1: Next we read a bitmap pattern that specifies which partition classes Chris@1: code values in which passes. Chris@1: Chris@1: \begin{programlisting} Chris@1: 1) iterate [i] over the range 0 ... [residue\_classifications]-1 { Chris@1: Chris@1: 2) [high\_bits] = 0 Chris@1: 3) [low\_bits] = read 3 bits as unsigned integer Chris@1: 4) [bitflag] = read one bit as boolean Chris@1: 5) if ( [bitflag] is set ) then [high\_bits] = read five bits as unsigned integer Chris@1: 6) vector [residue\_cascade] element [i] = [high\_bits] * 8 + [low\_bits] Chris@1: } Chris@1: 7) done Chris@1: \end{programlisting} Chris@1: Chris@1: Finally, we read in a list of book numbers, each corresponding to Chris@1: specific bit set in the cascade bitmap. We loop over the possible Chris@1: codebook classifications and the maximum possible number of encoding Chris@1: stages (8 in Vorbis I, as constrained by the elements of the cascade Chris@1: bitmap being eight bits): Chris@1: Chris@1: \begin{programlisting} Chris@1: 1) iterate [i] over the range 0 ... [residue\_classifications]-1 { Chris@1: Chris@1: 2) iterate [j] over the range 0 ... 7 { Chris@1: Chris@1: 3) if ( vector [residue\_cascade] element [i] bit [j] is set ) { Chris@1: Chris@1: 4) array [residue\_books] element [i][j] = read 8 bits as unsigned integer Chris@1: Chris@1: } else { Chris@1: Chris@1: 5) array [residue\_books] element [i][j] = unused Chris@1: Chris@1: } Chris@1: } Chris@1: } Chris@1: Chris@1: 6) done Chris@1: \end{programlisting} Chris@1: Chris@1: An end-of-packet condition at any point in header decode renders the Chris@1: stream undecodable. In addition, any codebook number greater than the Chris@1: maximum numbered codebook set up in this stream also renders the Chris@1: stream undecodable. All codebooks in array [residue\_books] are Chris@1: required to have a value mapping. The presence of codebook in array Chris@1: [residue\_books] without a value mapping (maptype equals zero) renders Chris@1: the stream undecodable. Chris@1: Chris@1: Chris@1: Chris@1: \subsubsection{packet decode} Chris@1: Chris@1: Format 0 and 1 packet decode is identical except for specific Chris@1: partition interleave. Format 2 packet decode can be built out of the Chris@1: format 1 decode process. Thus we describe first the decode Chris@1: infrastructure identical to all three formats. Chris@1: Chris@1: In addition to configuration information, the residue decode process Chris@1: is passed the number of vectors in the submap bundle and a vector of Chris@1: flags indicating if any of the vectors are not to be decoded. If the Chris@1: passed in number of vectors is 3 and vector number 1 is marked 'do not Chris@1: decode', decode skips vector 1 during the decode loop. However, even Chris@1: 'do not decode' vectors are allocated and zeroed. Chris@1: Chris@1: Depending on the values of \varname{[residue\_begin]} and Chris@1: \varname{[residue\_end]}, it is obvious that the encoded Chris@1: portion of a residue vector may be the entire possible residue vector Chris@1: or some other strict subset of the actual residue vector size with Chris@1: zero padding at either uncoded end. However, it is also possible to Chris@1: set \varname{[residue\_begin]} and Chris@1: \varname{[residue\_end]} to specify a range partially or Chris@1: wholly beyond the maximum vector size. Before beginning residue Chris@1: decode, limit \varname{[residue\_begin]} and Chris@1: \varname{[residue\_end]} to the maximum possible vector size Chris@1: as follows. We assume that the number of vectors being encoded, Chris@1: \varname{[ch]} is provided by the higher level decoding Chris@1: process. Chris@1: Chris@1: \begin{programlisting} Chris@1: 1) [actual\_size] = current blocksize/2; Chris@1: 2) if residue encoding is format 2 Chris@1: 3) [actual\_size] = [actual\_size] * [ch]; Chris@1: 4) [limit\_residue\_begin] = maximum of ([residue\_begin],[actual\_size]); Chris@1: 5) [limit\_residue\_end] = maximum of ([residue\_end],[actual\_size]); Chris@1: \end{programlisting} Chris@1: Chris@1: The following convenience values are conceptually useful to clarifying Chris@1: the decode process: Chris@1: Chris@1: \begin{programlisting} Chris@1: 1) [classwords\_per\_codeword] = [codebook\_dimensions] value of codebook [residue\_classbook] Chris@1: 2) [n\_to\_read] = [limit\_residue\_end] - [limit\_residue\_begin] Chris@1: 3) [partitions\_to\_read] = [n\_to\_read] / [residue\_partition\_size] Chris@1: \end{programlisting} Chris@1: Chris@1: Packet decode proceeds as follows, matching the description offered earlier in the document. Chris@1: \begin{programlisting} Chris@1: 1) allocate and zero all vectors that will be returned. Chris@1: 2) if ([n\_to\_read] is zero), stop; there is no residue to decode. Chris@1: 3) iterate [pass] over the range 0 ... 7 { Chris@1: Chris@1: 4) [partition\_count] = 0 Chris@1: Chris@1: 5) while [partition\_count] is less than [partitions\_to\_read] Chris@1: Chris@1: 6) if ([pass] is zero) { Chris@1: Chris@1: 7) iterate [j] over the range 0 .. [ch]-1 { Chris@1: Chris@1: 8) if vector [j] is not marked 'do not decode' { Chris@1: Chris@1: 9) [temp] = read from packet using codebook [residue\_classbook] in scalar context Chris@1: 10) iterate [i] descending over the range [classwords\_per\_codeword]-1 ... 0 { Chris@1: Chris@1: 11) array [classifications] element [j],([i]+[partition\_count]) = Chris@1: [temp] integer modulo [residue\_classifications] Chris@1: 12) [temp] = [temp] / [residue\_classifications] using integer division Chris@1: Chris@1: } Chris@1: Chris@1: } Chris@1: Chris@1: } Chris@1: Chris@1: } Chris@1: Chris@1: 13) iterate [i] over the range 0 .. ([classwords\_per\_codeword] - 1) while [partition\_count] Chris@1: is also less than [partitions\_to\_read] { Chris@1: Chris@1: 14) iterate [j] over the range 0 .. [ch]-1 { Chris@1: Chris@1: 15) if vector [j] is not marked 'do not decode' { Chris@1: Chris@1: 16) [vqclass] = array [classifications] element [j],[partition\_count] Chris@1: 17) [vqbook] = array [residue\_books] element [vqclass],[pass] Chris@1: 18) if ([vqbook] is not 'unused') { Chris@1: Chris@1: 19) decode partition into output vector number [j], starting at scalar Chris@1: offset [limit\_residue\_begin]+[partition\_count]*[residue\_partition\_size] using Chris@1: codebook number [vqbook] in VQ context Chris@1: } Chris@1: } Chris@1: Chris@1: 20) increment [partition\_count] by one Chris@1: Chris@1: } Chris@1: } Chris@1: } Chris@1: Chris@1: 21) done Chris@1: Chris@1: \end{programlisting} Chris@1: Chris@1: An end-of-packet condition during packet decode is to be considered a Chris@1: nominal occurrence. Decode returns the result of vector decode up to Chris@1: that point. Chris@1: Chris@1: Chris@1: Chris@1: \subsubsection{format 0 specifics} Chris@1: Chris@1: Format zero decodes partitions exactly as described earlier in the Chris@1: 'Residue Format: residue 0' section. The following pseudocode Chris@1: presents the same algorithm. Assume: Chris@1: Chris@1: \begin{itemize} Chris@1: \item \varname{[n]} is the value in \varname{[residue\_partition\_size]} Chris@1: \item \varname{[v]} is the residue vector Chris@1: \item \varname{[offset]} is the beginning read offset in [v] Chris@1: \end{itemize} Chris@1: Chris@1: Chris@1: \begin{programlisting} Chris@1: 1) [step] = [n] / [codebook\_dimensions] Chris@1: 2) iterate [i] over the range 0 ... [step]-1 { Chris@1: Chris@1: 3) vector [entry\_temp] = read vector from packet using current codebook in VQ context Chris@1: 4) iterate [j] over the range 0 ... [codebook\_dimensions]-1 { Chris@1: Chris@1: 5) vector [v] element ([offset]+[i]+[j]*[step]) = Chris@1: vector [v] element ([offset]+[i]+[j]*[step]) + Chris@1: vector [entry\_temp] element [j] Chris@1: Chris@1: } Chris@1: Chris@1: } Chris@1: Chris@1: 6) done Chris@1: Chris@1: \end{programlisting} Chris@1: Chris@1: Chris@1: Chris@1: \subsubsection{format 1 specifics} Chris@1: Chris@1: Format 1 decodes partitions exactly as described earlier in the Chris@1: 'Residue Format: residue 1' section. The following pseudocode Chris@1: presents the same algorithm. Assume: Chris@1: Chris@1: \begin{itemize} Chris@1: \item \varname{[n]} is the value in Chris@1: \varname{[residue\_partition\_size]} Chris@1: \item \varname{[v]} is the residue vector Chris@1: \item \varname{[offset]} is the beginning read offset in [v] Chris@1: \end{itemize} Chris@1: Chris@1: Chris@1: \begin{programlisting} Chris@1: 1) [i] = 0 Chris@1: 2) vector [entry\_temp] = read vector from packet using current codebook in VQ context Chris@1: 3) iterate [j] over the range 0 ... [codebook\_dimensions]-1 { Chris@1: Chris@1: 4) vector [v] element ([offset]+[i]) = Chris@1: vector [v] element ([offset]+[i]) + Chris@1: vector [entry\_temp] element [j] Chris@1: 5) increment [i] Chris@1: Chris@1: } Chris@1: Chris@1: 6) if ( [i] is less than [n] ) continue at step 2 Chris@1: 7) done Chris@1: \end{programlisting} Chris@1: Chris@1: Chris@1: Chris@1: \subsubsection{format 2 specifics} Chris@1: Chris@1: Format 2 is reducible to format 1. It may be implemented as an additional step prior to and an additional post-decode step after a normal format 1 decode. Chris@1: Chris@1: Chris@1: Format 2 handles 'do not decode' vectors differently than residue 0 or Chris@1: 1; if all vectors are marked 'do not decode', no decode occurrs. Chris@1: However, if at least one vector is to be decoded, all the vectors are Chris@1: decoded. We then request normal format 1 to decode a single vector Chris@1: representing all output channels, rather than a vector for each Chris@1: channel. After decode, deinterleave the vector into independent vectors, one for each output channel. That is: Chris@1: Chris@1: \begin{enumerate} Chris@1: \item If all vectors 0 through \emph{ch}-1 are marked 'do not decode', allocate and clear a single vector \varname{[v]}of length \emph{ch*n} and skip step 2 below; proceed directly to the post-decode step. Chris@1: \item Rather than performing format 1 decode to produce \emph{ch} vectors of length \emph{n} each, call format 1 decode to produce a single vector \varname{[v]} of length \emph{ch*n}. Chris@1: \item Post decode: Deinterleave the single vector \varname{[v]} returned by format 1 decode as described above into \emph{ch} independent vectors, one for each outputchannel, according to: Chris@1: \begin{programlisting} Chris@1: 1) iterate [i] over the range 0 ... [n]-1 { Chris@1: Chris@1: 2) iterate [j] over the range 0 ... [ch]-1 { Chris@1: Chris@1: 3) output vector number [j] element [i] = vector [v] element ([i] * [ch] + [j]) Chris@1: Chris@1: } Chris@1: } Chris@1: Chris@1: 4) done Chris@1: \end{programlisting} Chris@1: Chris@1: \end{enumerate} Chris@1: Chris@1: Chris@1: Chris@1: Chris@1: Chris@1: Chris@1: