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