examples/sfexamples/oggvorbiscodec/src/libvorbis/doc/xml/07-floor1.xml

00001 <?xml version="1.0" standalone="no"?>
00002 <!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
00003                 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
00004 
00005 ]>
00006 
00007 <section id="vorbis-spec-floor1">
00008 <sectioninfo>
00009 <releaseinfo>
00010  $Id: 07-floor1.xml 10466 2005-11-28 00:34:44Z giles $
00011 </releaseinfo>
00012 </sectioninfo>
00013 <title>Floor type 1 setup and decode</title>
00014 
00015 <section>
00016 <title>Overview</title>
00017 
00018 <para>
00019 Vorbis floor type one uses a piecewise straight-line representation to
00020 encode a spectral envelope curve. The representation plots this curve
00021 mechanically on a linear frequency axis and a logarithmic (dB)
00022 amplitude axis. The integer plotting algorithm used is similar to
00023 Bresenham's algorithm.</para>
00024 
00025 </section>
00026 
00027 <section>
00028 <title>Floor 1 format</title>
00029 
00030 <section><title>model</title>
00031 
00032 <para>
00033 Floor type one represents a spectral curve as a series of
00034 line segments.  Synthesis constructs a floor curve using iterative
00035 prediction in a process roughly equivalent to the following simplified
00036 description:</para>
00037 
00038 <para>
00039 <itemizedlist>
00040  <listitem><simpara> the first line segment (base case) is a logical line spanning
00041 from x_0,y_0 to x_1,y_1 where in the base case x_0=0 and x_1=[n], the
00042 full range of the spectral floor to be computed.</simpara></listitem>
00043 
00044 <listitem><simpara>the induction step chooses a point x_new within an existing
00045 logical line segment and produces a y_new value at that point computed
00046 from the existing line's y value at x_new (as plotted by the line) and
00047 a difference value decoded from the bitstream packet.</simpara></listitem>
00048 
00049 <listitem><simpara>floor computation produces two new line segments, one running from
00050 x_0,y_0 to x_new,y_new and from x_new,y_new to x_1,y_1. This step is
00051 performed logically even if y_new represents no change to the
00052 amplitude value at x_new so that later refinement is additionally
00053 bounded at x_new.</simpara></listitem>
00054 
00055 <listitem><simpara>the induction step repeats, using a list of x values specified in
00056 the codec setup header at floor 1 initialization time.  Computation
00057 is completed at the end of the x value list.</simpara></listitem>
00058 
00059 </itemizedlist>
00060 </para>
00061 
00062 <para>
00063 Consider the following example, with values chosen for ease of
00064 understanding rather than representing typical configuration:</para>
00065 
00066 <para>
00067 For the below example, we assume a floor setup with an [n] of 128.
00068 The list of selected X values in increasing order is
00069 0,16,32,48,64,80,96,112 and 128.  In list order, the values interleave
00070 as 0, 128, 64, 32, 96, 16, 48, 80 and 112.  The corresponding
00071 list-order Y values as decoded from an example packet are 110, 20, -5,
00072 -45, 0, -25, -10, 30 and -10.  We compute the floor in the following
00073 way, beginning with the first line:</para>
00074 
00075 <mediaobject>
00076 <imageobject>
00077  <imagedata fileref="floor1-1.png" format="PNG"/>
00078 </imageobject>
00079 <textobject>
00080  <phrase>[graph of example floor]</phrase>
00081 </textobject>
00082 </mediaobject>
00083 
00084 <para>
00085 We now draw new logical lines to reflect the correction to new_Y, and
00086 iterate for X positions 32 and 96:</para>
00087 
00088 <mediaobject>
00089 <imageobject>
00090  <imagedata fileref="floor1-2.png" format="PNG"/> 
00091  </imageobject>
00092  <textobject>
00093   <phrase>[graph of example floor]</phrase>
00094  </textobject>
00095 </mediaobject>
00096   
00097 <para>
00098 Although the new Y value at X position 96 is unchanged, it is still
00099 used later as an endpoint for further refinement.  From here on, the
00100 pattern should be clear; we complete the floor computation as follows:</para>
00101 
00102 <mediaobject>
00103 <imageobject>
00104  <imagedata fileref="floor1-3.png" format="PNG"/> 
00105  </imageobject>
00106  <textobject>
00107   <phrase>[graph of example floor]</phrase>
00108  </textobject>
00109 </mediaobject>
00110   
00111 <mediaobject>
00112 <imageobject>
00113  <imagedata fileref="floor1-4.png" format="PNG"/> 
00114  </imageobject>
00115  <textobject>
00116   <phrase>[graph of example floor]</phrase>
00117  </textobject>
00118 </mediaobject>
00119   
00120 
00121 <para>
00122 A more efficient algorithm with carefully defined integer rounding
00123 behavior is used for actual decode, as described later.  The actual
00124 algorithm splits Y value computation and line plotting into two steps
00125 with modifications to the above algorithm to eliminate noise
00126 accumulation through integer roundoff/truncation. </para>
00127 
00128 </section>
00129 
00130 <section><title>header decode</title>
00131 
00132 <para>
00133 A list of floor X values is stored in the packet header in interleaved
00134 format (used in list order during packet decode and synthesis).  This
00135 list is split into partitions, and each partition is assigned to a
00136 partition class.  X positions 0 and [n] are implicit and do not belong
00137 to an explicit partition or partition class.</para>
00138 
00139 <para>
00140 A partition class consists of a representation vector width (the
00141 number of Y values which the partition class encodes at once), a
00142 'subclass' value representing the number of alternate entropy books
00143 the partition class may use in representing Y values, the list of
00144 [subclass] books and a master book used to encode which alternate
00145 books were chosen for representation in a given packet.  The
00146 master/subclass mechanism is meant to be used as a flexible
00147 representation cascade while still using codebooks only in a scalar
00148 context.</para>
00149 
00150 <screen>
00151 
00152   1) [floor1_partitions] = read 5 bits as unsigned integer
00153   2) [maximum_class] = -1
00154   3) iterate [i] over the range 0 ... [floor1_partitions]-1 {
00155        
00156         4) vector [floor1_partition_class_list] element [i] = read 4 bits as unsigned integer
00157 
00158      }
00159 
00160   5) [maximum_class] = largest integer scalar value in vector [floor1_partition_class_list]
00161   6) iterate [i] over the range 0 ... [maximum_class] {
00162 
00163         7) vector [floor1_class_dimensions] element [i] = read 3 bits as unsigned integer and add 1
00164         8) vector [floor1_class_subclasses] element [i] = read 2 bits as unsigned integer
00165         9) if ( vector [floor1_class_subclasses] element [i] is nonzero ) {
00166             
00167              10) vector [floor1_class_masterbooks] element [i] = read 8 bits as unsigned integer
00168            
00169            }
00170 
00171        11) iterate [j] over the range 0 ... (2 exponent [floor1_class_subclasses] element [i]) - 1  {
00172 
00173              12) array [floor1_subclass_books] element [i],[j] = 
00174                  read 8 bits as unsigned integer and subtract one
00175            }
00176       }
00177 
00178  13) [floor1_multiplier] = read 2 bits as unsigned integer and add one
00179  14) [rangebits] = read 4 bits as unsigned integer
00180  15) vector [floor1_X_list] element [0] = 0
00181  16) vector [floor1_X_list] element [1] = 2 exponent [rangebits];
00182  17) [floor1_values] = 2
00183  18) iterate [i] over the range 0 ... [floor1_partitions]-1 {
00184 
00185        19) [current_class_number] = vector [floor1_partition_class_list] element [i]
00186        20) iterate [j] over the range 0 ... ([floor1_class_dimensions] element [current_class_number])-1 {
00187              21) vector [floor1_X_list] element ([floor1_values]) = 
00188                  read [rangebits] bits as unsigned integer
00189              22) increment [floor1_values] by one
00190            }
00191      }
00192  
00193  23) done
00194 </screen>
00195 
00196 <para>
00197 An end-of-packet condition while reading any aspect of a floor 1
00198 configuration during setup renders a stream undecodable.  In
00199 addition, a <varname>[floor1_class_masterbooks]</varname> or
00200 <varname>[floor1_subclass_books]</varname> scalar element greater than the
00201 highest numbered codebook configured in this stream is an error
00202 condition that renders the stream undecodable.</para>
00203 
00204 <section id="vorbis-spec-floor1-decode">
00205 <title>packet decode</title>
00206 
00207 <para>
00208 Packet decode begins by checking the <varname>[nonzero]</varname> flag:</para>
00209 
00210 <screen>
00211   1) [nonzero] = read 1 bit as boolean
00212 </screen>
00213 
00214 <para>
00215 If <varname>[nonzero]</varname> is unset, that indicates this channel contained
00216 no audio energy in this frame.  Decode immediately returns a status
00217 indicating this floor curve (and thus this channel) is unused this
00218 frame.  (A return status of 'unused' is different from decoding a
00219 floor that has all points set to minimum representation amplitude,
00220 which happens to be approximately -140dB).
00221 </para>
00222 
00223 <para>
00224 Assuming <varname>[nonzero]</varname> is set, decode proceeds as follows:</para>
00225 
00226 <screen>
00227   1) [range] = vector { 256, 128, 86, 64 } element ([floor1_multiplier]-1)
00228   2) vector [floor1_Y] element [0] = read <link linkend="vorbis-spec-ilog">ilog</link>([range]-1) bits as unsigned integer
00229   3) vector [floor1_Y] element [1] = read <link linkend="vorbis-spec-ilog">ilog</link>([range]-1) bits as unsigned integer
00230   4) [offset] = 2;
00231   5) iterate [i] over the range 0 ... [floor1_partitions]-1 {
00232 
00233        6) [class] = vector [floor1_partition_class]  element [i]
00234        7) [cdim]  = vector [floor1_class_dimensions] element [class]
00235        8) [cbits] = vector [floor1_class_subclasses] element [class]
00236        9) [csub]  = (2 exponent [cbits])-1
00237       10) [cval]  = 0
00238       11) if ( [cbits] is greater than zero ) {
00239  
00240              12) [cval] = read from packet using codebook number
00241                  (vector [floor1_class_masterbooks] element [class]) in scalar context
00242           }
00243       
00244       13) iterate [j] over the range 0 ... [cdim]-1 {
00245        
00246              14) [book] = array [floor1_subclass_books] element [class],([cval] bitwise AND [csub])
00247              15) [cval] = [cval] right shifted [cbits] bits
00248              16) if ( [book] is not less than zero ) {
00249              
00250                    17) vector [floor1_Y] element ([j]+[offset]) = read from packet using codebook 
00251                        [book] in scalar context
00252 
00253                  } else [book] is less than zero {
00254 
00255                    18) vector [floor1_Y] element ([j]+[offset]) = 0
00256 
00257                  }
00258           }
00259              
00260       19) [offset] = [offset] + [cdim]
00261          
00262      }
00263   
00264  20) done
00265 </screen>
00266 
00267 <para>
00268 An end-of-packet condition during curve decode should be considered a
00269 nominal occurrence; if end-of-packet is reached during any read
00270 operation above, floor decode is to return 'unused' status as if the
00271 <varname>[nonzero]</varname> flag had been unset at the beginning of decode.
00272 </para>
00273 
00274 <para>
00275 Vector <varname>[floor1_Y]</varname> contains the values from packet decode
00276 needed for floor 1 synthesis.</para>
00277 
00278 </section>
00279 
00280 <section id="vorbis-spec-floor1-synth">
00281 <title>curve computation</title>
00282 
00283 <para>
00284 Curve computation is split into two logical steps; the first step
00285 derives final Y amplitude values from the encoded, wrapped difference
00286 values taken from the bitstream.  The second step plots the curve
00287 lines.  Also, although zero-difference values are used in the
00288 iterative prediction to find final Y values, these points are
00289 conditionally skipped during final line computation in step two.
00290 Skipping zero-difference values allows a smoother line fit.  </para>
00291 
00292 <para>
00293 Although some aspects of the below algorithm look like inconsequential
00294 optimizations, implementors are warned to follow the details closely.
00295 Deviation from implementing a strictly equivalent algorithm can result
00296 in serious decoding errors.</para>
00297 
00298 <section>
00299 <title>step 1: amplitude value synthesis</title>
00300 
00301 <para>
00302 Unwrap the always-positive-or-zero values read from the packet into
00303 +/- difference values, then apply to line prediction.</para>
00304 
00305 <screen>
00306   1) [range] = vector { 256, 128, 86, 64 } element ([floor1_multiplier]-1)
00307   2) vector [floor1_step2_flag] element [0] = set
00308   3) vector [floor1_step2_flag] element [1] = set
00309   4) vector [floor1_final_Y] element [0] = vector [floor1_Y] element [0]
00310   5) vector [floor1_final_Y] element [1] = vector [floor1_Y] element [1]
00311   6) iterate [i] over the range 2 ... [floor1_values]-1 {
00312     
00313        7) [low_neighbor_offset] = <link linkend="vorbis-spec-low_neighbor">low_neighbor</link>([floor1_X_list],[i])
00314        8) [high_neighbor_offset] = <link linkend="vorbis-spec-high_neighbor">high_neighbor</link>([floor1_X_list],[i])
00315 
00316        9) [predicted] = <link linkend="vorbis-spec-render_point">render_point</link>( vector [floor1_X_list] element [low_neighbor_offset],
00317                                       vector [floor1_final_Y] element [low_neighbor_offset],
00318                                       vector [floor1_X_list] element [high_neighbor_offset],
00319                                       vector [floor1_final_Y] element [high_neighbor_offset],
00320                                       vector [floor1_X_list] element [i] )
00321 
00322       10) [val] = vector [floor1_Y] element [i]
00323       11) [highroom] = [range] - [predicted]
00324       12) [lowroom]  = [predicted]
00325       13) if ( [highroom] is less than [lowroom] ) {
00326 
00327             14) [room] = [highroom] * 2
00328          
00329           } else [highroom] is not less than [lowroom] {
00330                       
00331             15) [room] = [lowroom] * 2
00332         
00333           }
00334 
00335       16) if ( [val] is nonzero ) {
00336 
00337             17) vector [floor1_step2_flag] element [low_neighbor_offset] = set
00338             18) vector [floor1_step2_flag] element [high_neighbor_offset] = set
00339             19) vector [floor1_step2_flag] element [i] = set
00340             20) if ( [val] is greater than or equal to [room] ) {
00341  
00342                   21) if ( [highroom] is greater than [lowroom] ) {
00343 
00344                         22) vector [floor1_final_Y] element [i] = [val] - [lowroom] + [predicted]
00345                      
00346                       } else [highroom] is not greater than [lowroom] {
00347               
00348                         23) vector [floor1_final_Y] element [i] = [predicted] - [val] + [highroom] - 1
00349                    
00350                       }
00351                
00352                 } else [val] is less than [room] {
00353                  
00354                   24) if ([val] is odd) {
00355                  
00356                         25) vector [floor1_final_Y] element [i] = 
00357                             [predicted] - (([val] + 1) divided by  2 using integer division)
00358 
00359                       } else [val] is even {
00360 
00361                         26) vector [floor1_final_Y] element [i] = 
00362                             [predicted] + ([val] / 2 using integer division)
00363                           
00364                       }
00365 
00366                 }      
00367 
00368           } else [val] is zero {
00369 
00370             27) vector [floor1_step2_flag] element [i] = unset
00371             28) vector [floor1_final_Y] element [i] = [predicted]
00372 
00373           }
00374 
00375      }
00376 
00377  29) done
00378 
00379 </screen>
00380 
00381 </section>
00382 
00383 <section>
00384 <title>step 2: curve synthesis</title>
00385 
00386 <para>
00387 Curve synthesis generates a return vector <varname>[floor]</varname> of length
00388 <varname>[n]</varname> (where <varname>[n]</varname> is provided by the decode process
00389 calling to floor decode).  Floor 1 curve synthesis makes use of the
00390 <varname>[floor1_X_list]</varname>, <varname>[floor1_final_Y]</varname> and
00391 <varname>[floor1_step2_flag]</varname> vectors, as well as [floor1_multiplier]
00392 and [floor1_values] values.</para>
00393 
00394 <para>
00395 Decode begins by sorting the scalars from vectors
00396 <varname>[floor1_X_list]</varname>, <varname>[floor1_final_Y]</varname> and
00397 <varname>[floor1_step2_flag]</varname> together into new vectors
00398 <varname>[floor1_X_list]'</varname>, <varname>[floor1_final_Y]'</varname> and
00399 <varname>[floor1_step2_flag]'</varname> according to ascending sort order of the
00400 values in <varname>[floor1_X_list]</varname>.  That is, sort the values of
00401 <varname>[floor1_X_list]</varname> and then apply the same permutation to
00402 elements of the other two vectors so that the X, Y and step2_flag
00403 values still match.</para>
00404 
00405 <para>
00406 Then compute the final curve in one pass:</para>
00407 
00408 <screen>
00409   1) [hx] = 0
00410   2) [lx] = 0
00411   3) [ly] = vector [floor1_final_Y]' element [0] * [floor1_multiplier]
00412   4) iterate [i] over the range 1 ... [floor1_values]-1 {
00413 
00414        5) if ( [floor1_step2_flag]' element [i] is set ) {
00415 
00416              6) [hy] = [floor1_final_Y]' element [i] * [floor1_multiplier]
00417              7) [hx] = [floor1_X_list]' element [i]
00418              8) <link linkend="vorbis-spec-render_line">render_line</link>( [lx], [ly], [hx], [hy], [floor] )
00419              9) [lx] = [hx]
00420             10) [ly] = [hy]
00421           }
00422      }
00423  
00424  11) if ( [hx] is less than [n] ) {
00425 
00426         12) <link linkend="vorbis-spec-render_line">render_line</link>( [hx], [hy], [n], [hy], [floor] )
00427 
00428      }
00429 
00430  13) if ( [hx] is greater than [n] ) {
00431 
00432             14) truncate vector [floor] to [n] elements
00433 
00434      }
00435  
00436  15) for each scalar in vector [floor], perform a lookup substitution using 
00437      the scalar value from [floor] as an offset into the vector <link linkend="vorbis-spec-floor1_inverse_dB_table">[floor1_inverse_dB_static_table]</link>
00438 
00439  16) done
00440 
00441 </screen>
00442 
00443 </section>
00444 
00445 </section>
00446 
00447 </section>
00448 </section>
00449 </section>
00450 

Generated by  doxygen 1.6.2