Blame doc/07-floor1.tex

Packit 06404a
% -*- mode: latex; TeX-master: "Vorbis_I_spec"; -*-
Packit 06404a
%!TEX root = Vorbis_I_spec.tex
Packit 06404a
% $Id$
Packit 06404a
\section{Floor type 1 setup and decode} \label{vorbis:spec:floor1}
Packit 06404a
Packit 06404a
\subsection{Overview}
Packit 06404a
Packit 06404a
Vorbis floor type one uses a piecewise straight-line representation to
Packit 06404a
encode a spectral envelope curve. The representation plots this curve
Packit 06404a
mechanically on a linear frequency axis and a logarithmic (dB)
Packit 06404a
amplitude axis. The integer plotting algorithm used is similar to
Packit 06404a
Bresenham's algorithm.
Packit 06404a
Packit 06404a
Packit 06404a
Packit 06404a
\subsection{Floor 1 format}
Packit 06404a
Packit 06404a
\subsubsection{model}
Packit 06404a
Packit 06404a
Floor type one represents a spectral curve as a series of
Packit 06404a
line segments.  Synthesis constructs a floor curve using iterative
Packit 06404a
prediction in a process roughly equivalent to the following simplified
Packit 06404a
description:
Packit 06404a
Packit 06404a
\begin{itemize}
Packit 06404a
 \item  the first line segment (base case) is a logical line spanning
Packit 06404a
from x_0,y_0 to x_1,y_1 where in the base case x_0=0 and x_1=[n], the
Packit 06404a
full range of the spectral floor to be computed.
Packit 06404a
Packit 06404a
\item the induction step chooses a point x_new within an existing
Packit 06404a
logical line segment and produces a y_new value at that point computed
Packit 06404a
from the existing line's y value at x_new (as plotted by the line) and
Packit 06404a
a difference value decoded from the bitstream packet.
Packit 06404a
Packit 06404a
\item floor computation produces two new line segments, one running from
Packit 06404a
x_0,y_0 to x_new,y_new and from x_new,y_new to x_1,y_1. This step is
Packit 06404a
performed logically even if y_new represents no change to the
Packit 06404a
amplitude value at x_new so that later refinement is additionally
Packit 06404a
bounded at x_new.
Packit 06404a
Packit 06404a
\item the induction step repeats, using a list of x values specified in
Packit 06404a
the codec setup header at floor 1 initialization time.  Computation
Packit 06404a
is completed at the end of the x value list.
Packit 06404a
Packit 06404a
\end{itemize}
Packit 06404a
Packit 06404a
Packit 06404a
Consider the following example, with values chosen for ease of
Packit 06404a
understanding rather than representing typical configuration:
Packit 06404a
Packit 06404a
For the below example, we assume a floor setup with an [n] of 128.
Packit 06404a
The list of selected X values in increasing order is
Packit 06404a
0,16,32,48,64,80,96,112 and 128.  In list order, the values interleave
Packit 06404a
as 0, 128, 64, 32, 96, 16, 48, 80 and 112.  The corresponding
Packit 06404a
list-order Y values as decoded from an example packet are 110, 20, -5,
Packit 06404a
-45, 0, -25, -10, 30 and -10.  We compute the floor in the following
Packit 06404a
way, beginning with the first line:
Packit 06404a
Packit 06404a
\begin{center}
Packit 06404a
\includegraphics[width=8cm]{floor1-1}
Packit 06404a
\captionof{figure}{graph of example floor}
Packit 06404a
\end{center}
Packit 06404a
Packit 06404a
We now draw new logical lines to reflect the correction to new_Y, and
Packit 06404a
iterate for X positions 32 and 96:
Packit 06404a
Packit 06404a
\begin{center}
Packit 06404a
\includegraphics[width=8cm]{floor1-2}
Packit 06404a
\captionof{figure}{graph of example floor}
Packit 06404a
\end{center}
Packit 06404a
Packit 06404a
Although the new Y value at X position 96 is unchanged, it is still
Packit 06404a
used later as an endpoint for further refinement.  From here on, the
Packit 06404a
pattern should be clear; we complete the floor computation as follows:
Packit 06404a
Packit 06404a
\begin{center}
Packit 06404a
\includegraphics[width=8cm]{floor1-3}
Packit 06404a
\captionof{figure}{graph of example floor}
Packit 06404a
\end{center}
Packit 06404a
Packit 06404a
\begin{center}
Packit 06404a
\includegraphics[width=8cm]{floor1-4}
Packit 06404a
\captionof{figure}{graph of example floor}
Packit 06404a
\end{center}
Packit 06404a
Packit 06404a
A more efficient algorithm with carefully defined integer rounding
Packit 06404a
behavior is used for actual decode, as described later.  The actual
Packit 06404a
algorithm splits Y value computation and line plotting into two steps
Packit 06404a
with modifications to the above algorithm to eliminate noise
Packit 06404a
accumulation through integer roundoff/truncation.
Packit 06404a
Packit 06404a
Packit 06404a
Packit 06404a
\subsubsection{header decode}
Packit 06404a
Packit 06404a
A list of floor X values is stored in the packet header in interleaved
Packit 06404a
format (used in list order during packet decode and synthesis).  This
Packit 06404a
list is split into partitions, and each partition is assigned to a
Packit 06404a
partition class.  X positions 0 and [n] are implicit and do not belong
Packit 06404a
to an explicit partition or partition class.
Packit 06404a
Packit 06404a
A partition class consists of a representation vector width (the
Packit 06404a
number of Y values which the partition class encodes at once), a
Packit 06404a
'subclass' value representing the number of alternate entropy books
Packit 06404a
the partition class may use in representing Y values, the list of
Packit 06404a
[subclass] books and a master book used to encode which alternate
Packit 06404a
books were chosen for representation in a given packet.  The
Packit 06404a
master/subclass mechanism is meant to be used as a flexible
Packit 06404a
representation cascade while still using codebooks only in a scalar
Packit 06404a
context.
Packit 06404a
Packit 06404a
\begin{Verbatim}[commandchars=\\\{\}]
Packit 06404a
Packit 06404a
  1) [floor1\_partitions] = read 5 bits as unsigned integer
Packit 06404a
  2) [maximum\_class] = -1
Packit 06404a
  3) iterate [i] over the range 0 ... [floor1\_partitions]-1 \{
Packit 06404a
Packit 06404a
        4) vector [floor1\_partition\_class\_list] element [i] = read 4 bits as unsigned integer
Packit 06404a
Packit 06404a
     \}
Packit 06404a
Packit 06404a
  5) [maximum\_class] = largest integer scalar value in vector [floor1\_partition\_class\_list]
Packit 06404a
  6) iterate [i] over the range 0 ... [maximum\_class] \{
Packit 06404a
Packit 06404a
        7) vector [floor1\_class\_dimensions] element [i] = read 3 bits as unsigned integer and add 1
Packit 06404a
	8) vector [floor1\_class\_subclasses] element [i] = read 2 bits as unsigned integer
Packit 06404a
        9) if ( vector [floor1\_class\_subclasses] element [i] is nonzero ) \{
Packit 06404a
Packit 06404a
             10) vector [floor1\_class\_masterbooks] element [i] = read 8 bits as unsigned integer
Packit 06404a
Packit 06404a
           \}
Packit 06404a
Packit 06404a
       11) iterate [j] over the range 0 ... (2 exponent [floor1\_class\_subclasses] element [i]) - 1 \{
Packit 06404a
Packit 06404a
             12) array [floor1\_subclass\_books] element [i],[j] =
Packit 06404a
                 read 8 bits as unsigned integer and subtract one
Packit 06404a
           \}
Packit 06404a
      \}
Packit 06404a
Packit 06404a
 13) [floor1\_multiplier] = read 2 bits as unsigned integer and add one
Packit 06404a
 14) [rangebits] = read 4 bits as unsigned integer
Packit 06404a
 15) vector [floor1\_X\_list] element [0] = 0
Packit 06404a
 16) vector [floor1\_X\_list] element [1] = 2 exponent [rangebits];
Packit 06404a
 17) [floor1\_values] = 2
Packit 06404a
 18) iterate [i] over the range 0 ... [floor1\_partitions]-1 \{
Packit 06404a
Packit 06404a
       19) [current\_class\_number] = vector [floor1\_partition\_class\_list] element [i]
Packit 06404a
       20) iterate [j] over the range 0 ... ([floor1\_class\_dimensions] element [current\_class\_number])-1 \{
Packit 06404a
             21) vector [floor1\_X\_list] element ([floor1\_values]) =
Packit 06404a
                 read [rangebits] bits as unsigned integer
Packit 06404a
             22) increment [floor1\_values] by one
Packit 06404a
           \}
Packit 06404a
     \}
Packit 06404a
Packit 06404a
 23) done
Packit 06404a
\end{Verbatim}
Packit 06404a
Packit 06404a
An end-of-packet condition while reading any aspect of a floor 1
Packit 06404a
configuration during setup renders a stream undecodable.  In addition,
Packit 06404a
a \varname{[floor1\_class\_masterbooks]} or
Packit 06404a
\varname{[floor1\_subclass\_books]} scalar element greater than the
Packit 06404a
highest numbered codebook configured in this stream is an error
Packit 06404a
condition that renders the stream undecodable.  Vector
Packit 06404a
[floor1\_x\_list] is limited to a maximum length of 65 elements; a
Packit 06404a
setup indicating more than 65 total elements (including elements 0 and
Packit 06404a
1 set prior to the read loop) renders the stream undecodable.  All
Packit 06404a
vector [floor1\_x\_list] element values must be unique within the
Packit 06404a
vector; a non-unique value renders the stream undecodable.
Packit 06404a
Packit 06404a
\subsubsection{packet decode} \label{vorbis:spec:floor1-decode}
Packit 06404a
Packit 06404a
Packet decode begins by checking the \varname{[nonzero]} flag:
Packit 06404a
Packit 06404a
\begin{Verbatim}[commandchars=\\\{\}]
Packit 06404a
  1) [nonzero] = read 1 bit as boolean
Packit 06404a
\end{Verbatim}
Packit 06404a
Packit 06404a
If \varname{[nonzero]} is unset, that indicates this channel contained
Packit 06404a
no audio energy in this frame.  Decode immediately returns a status
Packit 06404a
indicating this floor curve (and thus this channel) is unused this
Packit 06404a
frame.  (A return status of 'unused' is different from decoding a
Packit 06404a
floor that has all points set to minimum representation amplitude,
Packit 06404a
which happens to be approximately -140dB).
Packit 06404a
Packit 06404a
Packit 06404a
Assuming \varname{[nonzero]} is set, decode proceeds as follows:
Packit 06404a
Packit 06404a
\begin{Verbatim}[commandchars=\\\{\}]
Packit 06404a
  1) [range] = vector \{ 256, 128, 86, 64 \} element ([floor1\_multiplier]-1)
Packit 06404a
  2) vector [floor1\_Y] element [0] = read \link{vorbis:spec:ilog}{ilog}([range]-1) bits as unsigned integer
Packit 06404a
  3) vector [floor1\_Y] element [1] = read \link{vorbis:spec:ilog}{ilog}([range]-1) bits as unsigned integer
Packit 06404a
  4) [offset] = 2;
Packit 06404a
  5) iterate [i] over the range 0 ... [floor1\_partitions]-1 \{
Packit 06404a
Packit 06404a
       6) [class] = vector [floor1\_partition\_class]  element [i]
Packit 06404a
       7) [cdim]  = vector [floor1\_class\_dimensions] element [class]
Packit 06404a
       8) [cbits] = vector [floor1\_class\_subclasses] element [class]
Packit 06404a
       9) [csub]  = (2 exponent [cbits])-1
Packit 06404a
      10) [cval]  = 0
Packit 06404a
      11) if ( [cbits] is greater than zero ) \{
Packit 06404a
Packit 06404a
             12) [cval] = read from packet using codebook number
Packit 06404a
                 (vector [floor1\_class\_masterbooks] element [class]) in scalar context
Packit 06404a
          \}
Packit 06404a
Packit 06404a
      13) iterate [j] over the range 0 ... [cdim]-1 \{
Packit 06404a
Packit 06404a
             14) [book] = array [floor1\_subclass\_books] element [class],([cval] bitwise AND [csub])
Packit 06404a
             15) [cval] = [cval] right shifted [cbits] bits
Packit 06404a
	     16) if ( [book] is not less than zero ) \{
Packit 06404a
Packit 06404a
	           17) vector [floor1\_Y] element ([j]+[offset]) = read from packet using codebook
Packit 06404a
                       [book] in scalar context
Packit 06404a
Packit 06404a
                 \} else [book] is less than zero \{
Packit 06404a
Packit 06404a
	           18) vector [floor1\_Y] element ([j]+[offset]) = 0
Packit 06404a
Packit 06404a
                 \}
Packit 06404a
          \}
Packit 06404a
Packit 06404a
      19) [offset] = [offset] + [cdim]
Packit 06404a
Packit 06404a
     \}
Packit 06404a
Packit 06404a
 20) done
Packit 06404a
\end{Verbatim}
Packit 06404a
Packit 06404a
An end-of-packet condition during curve decode should be considered a
Packit 06404a
nominal occurrence; if end-of-packet is reached during any read
Packit 06404a
operation above, floor decode is to return 'unused' status as if the
Packit 06404a
\varname{[nonzero]} flag had been unset at the beginning of decode.
Packit 06404a
Packit 06404a
Packit 06404a
Vector \varname{[floor1\_Y]} contains the values from packet decode
Packit 06404a
needed for floor 1 synthesis.
Packit 06404a
Packit 06404a
Packit 06404a
Packit 06404a
\subsubsection{curve computation} \label{vorbis:spec:floor1-synth}
Packit 06404a
Packit 06404a
Curve computation is split into two logical steps; the first step
Packit 06404a
derives final Y amplitude values from the encoded, wrapped difference
Packit 06404a
values taken from the bitstream.  The second step plots the curve
Packit 06404a
lines.  Also, although zero-difference values are used in the
Packit 06404a
iterative prediction to find final Y values, these points are
Packit 06404a
conditionally skipped during final line computation in step two.
Packit 06404a
Skipping zero-difference values allows a smoother line fit.
Packit 06404a
Packit 06404a
Although some aspects of the below algorithm look like inconsequential
Packit 06404a
optimizations, implementors are warned to follow the details closely.
Packit 06404a
Deviation from implementing a strictly equivalent algorithm can result
Packit 06404a
in serious decoding errors.
Packit 06404a
Packit 06404a
{\em Additional note:} Although \varname{[floor1\_final\_Y]} values in
Packit 06404a
the prediction loop and at the end of step 1 are inherently limited by
Packit 06404a
the prediction algorithm to [0, \varname{[range]}), it is possible to
Packit 06404a
  abuse the setup and codebook machinery to produce negative or
Packit 06404a
  over-range results.  We suggest that decoder implementations guard
Packit 06404a
  the values in vector \varname{[floor1\_final\_Y]} by clamping each
Packit 06404a
  element to [0, \varname{[range]}) after step 1.  Variants of this
Packit 06404a
    suggestion are acceptable as valid floor1 setups cannot produce
Packit 06404a
    out of range values.
Packit 06404a
Packit 06404a
\begin{description}
Packit 06404a
\item[step 1: amplitude value synthesis]
Packit 06404a
Packit 06404a
Unwrap the always-positive-or-zero values read from the packet into
Packit 06404a
+/- difference values, then apply to line prediction.
Packit 06404a
Packit 06404a
\begin{Verbatim}[commandchars=\\\{\}]
Packit 06404a
  1) [range] = vector \{ 256, 128, 86, 64 \} element ([floor1\_multiplier]-1)
Packit 06404a
  2) vector [floor1\_step2\_flag] element [0] = set
Packit 06404a
  3) vector [floor1\_step2\_flag] element [1] = set
Packit 06404a
  4) vector [floor1\_final\_Y] element [0] = vector [floor1\_Y] element [0]
Packit 06404a
  5) vector [floor1\_final\_Y] element [1] = vector [floor1\_Y] element [1]
Packit 06404a
  6) iterate [i] over the range 2 ... [floor1\_values]-1 \{
Packit 06404a
Packit 06404a
       7) [low\_neighbor\_offset] = \link{vorbis:spec:low:neighbor}{low\_neighbor}([floor1\_X\_list],[i])
Packit 06404a
       8) [high\_neighbor\_offset] = \link{vorbis:spec:high:neighbor}{high\_neighbor}([floor1\_X\_list],[i])
Packit 06404a
Packit 06404a
       9) [predicted] = \link{vorbis:spec:render:point}{render\_point}( vector [floor1\_X\_list] element [low\_neighbor\_offset],
Packit 06404a
				      vector [floor1\_final\_Y] element [low\_neighbor\_offset],
Packit 06404a
                                      vector [floor1\_X\_list] element [high\_neighbor\_offset],
Packit 06404a
				      vector [floor1\_final\_Y] element [high\_neighbor\_offset],
Packit 06404a
                                      vector [floor1\_X\_list] element [i] )
Packit 06404a
Packit 06404a
      10) [val] = vector [floor1\_Y] element [i]
Packit 06404a
      11) [highroom] = [range] - [predicted]
Packit 06404a
      12) [lowroom]  = [predicted]
Packit 06404a
      13) if ( [highroom] is less than [lowroom] ) \{
Packit 06404a
Packit 06404a
            14) [room] = [highroom] * 2
Packit 06404a
Packit 06404a
          \} else [highroom] is not less than [lowroom] \{
Packit 06404a
Packit 06404a
            15) [room] = [lowroom] * 2
Packit 06404a
Packit 06404a
          \}
Packit 06404a
Packit 06404a
      16) if ( [val] is nonzero ) \{
Packit 06404a
Packit 06404a
            17) vector [floor1\_step2\_flag] element [low\_neighbor\_offset] = set
Packit 06404a
            18) vector [floor1\_step2\_flag] element [high\_neighbor\_offset] = set
Packit 06404a
            19) vector [floor1\_step2\_flag] element [i] = set
Packit 06404a
            20) if ( [val] is greater than or equal to [room] ) \{
Packit 06404a
Packit 06404a
                  21) if ( [highroom] is greater than [lowroom] ) \{
Packit 06404a
Packit 06404a
                        22) vector [floor1\_final\_Y] element [i] = [val] - [lowroom] + [predicted]
Packit 06404a
Packit 06404a
		      \} else [highroom] is not greater than [lowroom] \{
Packit 06404a
Packit 06404a
                        23) vector [floor1\_final\_Y] element [i] = [predicted] - [val] + [highroom] - 1
Packit 06404a
Packit 06404a
                      \}
Packit 06404a
Packit 06404a
                \} else [val] is less than [room] \{
Packit 06404a
Packit 06404a
                    24) if ([val] is odd) \{
Packit 06404a
Packit 06404a
                        25) vector [floor1\_final\_Y] element [i] =
Packit 06404a
                            [predicted] - (([val] + 1) divided by  2 using integer division)
Packit 06404a
Packit 06404a
                      \} else [val] is even \{
Packit 06404a
Packit 06404a
                        26) vector [floor1\_final\_Y] element [i] =
Packit 06404a
                            [predicted] + ([val] / 2 using integer division)
Packit 06404a
Packit 06404a
                      \}
Packit 06404a
Packit 06404a
                \}
Packit 06404a
Packit 06404a
          \} else [val] is zero \{
Packit 06404a
Packit 06404a
            27) vector [floor1\_step2\_flag] element [i] = unset
Packit 06404a
            28) vector [floor1\_final\_Y] element [i] = [predicted]
Packit 06404a
Packit 06404a
          \}
Packit 06404a
Packit 06404a
     \}
Packit 06404a
Packit 06404a
 29) done
Packit 06404a
Packit 06404a
\end{Verbatim}
Packit 06404a
Packit 06404a
Packit 06404a
Packit 06404a
\item[step 2: curve synthesis]
Packit 06404a
Packit 06404a
Curve synthesis generates a return vector \varname{[floor]} of length
Packit 06404a
\varname{[n]} (where \varname{[n]} is provided by the decode process
Packit 06404a
calling to floor decode).  Floor 1 curve synthesis makes use of the
Packit 06404a
\varname{[floor1\_X\_list]}, \varname{[floor1\_final\_Y]} and
Packit 06404a
\varname{[floor1\_step2\_flag]} vectors, as well as [floor1\_multiplier]
Packit 06404a
and [floor1\_values] values.
Packit 06404a
Packit 06404a
Decode begins by sorting the scalars from vectors
Packit 06404a
\varname{[floor1\_X\_list]}, \varname{[floor1\_final\_Y]} and
Packit 06404a
\varname{[floor1\_step2\_flag]} together into new vectors
Packit 06404a
\varname{[floor1\_X\_list]'}, \varname{[floor1\_final\_Y]'} and
Packit 06404a
\varname{[floor1\_step2\_flag]'} according to ascending sort order of the
Packit 06404a
values in \varname{[floor1\_X\_list]}.  That is, sort the values of
Packit 06404a
\varname{[floor1\_X\_list]} and then apply the same permutation to
Packit 06404a
elements of the other two vectors so that the X, Y and step2\_flag
Packit 06404a
values still match.
Packit 06404a
Packit 06404a
Then compute the final curve in one pass:
Packit 06404a
Packit 06404a
\begin{Verbatim}[commandchars=\\\{\}]
Packit 06404a
  1) [hx] = 0
Packit 06404a
  2) [lx] = 0
Packit 06404a
  3) [ly] = vector [floor1\_final\_Y]' element [0] * [floor1\_multiplier]
Packit 06404a
  4) iterate [i] over the range 1 ... [floor1\_values]-1 \{
Packit 06404a
Packit 06404a
       5) if ( [floor1\_step2\_flag]' element [i] is set ) \{
Packit 06404a
Packit 06404a
             6) [hy] = [floor1\_final\_Y]' element [i] * [floor1\_multiplier]
Packit 06404a
 	     7) [hx] = [floor1\_X\_list]' element [i]
Packit 06404a
             8) \link{vorbis:spec:render:line}{render\_line}( [lx], [ly], [hx], [hy], [floor] )
Packit 06404a
             9) [lx] = [hx]
Packit 06404a
	    10) [ly] = [hy]
Packit 06404a
          \}
Packit 06404a
     \}
Packit 06404a
Packit 06404a
 11) if ( [hx] is less than [n] ) \{
Packit 06404a
Packit 06404a
        12) \link{vorbis:spec:render:line}{render\_line}( [hx], [hy], [n], [hy], [floor] )
Packit 06404a
Packit 06404a
     \}
Packit 06404a
Packit 06404a
 13) if ( [hx] is greater than [n] ) \{
Packit 06404a
Packit 06404a
            14) truncate vector [floor] to [n] elements
Packit 06404a
Packit 06404a
     \}
Packit 06404a
Packit 06404a
 15) for each scalar in vector [floor], perform a lookup substitution using
Packit 06404a
     the scalar value from [floor] as an offset into the vector \link{vorbis:spec:floor1:inverse:dB:table}{[floor1\_inverse\_dB\_static\_table]}
Packit 06404a
Packit 06404a
 16) done
Packit 06404a
Packit 06404a
\end{Verbatim}
Packit 06404a
Packit 06404a
\end{description}