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