annotate src/libvorbis-1.3.3/doc/07-floor1.tex @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 98c1576536ae
children
rev   line source
cannam@86 1 % -*- mode: latex; TeX-master: "Vorbis_I_spec"; -*-
cannam@86 2 %!TEX root = Vorbis_I_spec.tex
cannam@86 3 % $Id$
cannam@86 4 \section{Floor type 1 setup and decode} \label{vorbis:spec:floor1}
cannam@86 5
cannam@86 6 \subsection{Overview}
cannam@86 7
cannam@86 8 Vorbis floor type one uses a piecewise straight-line representation to
cannam@86 9 encode a spectral envelope curve. The representation plots this curve
cannam@86 10 mechanically on a linear frequency axis and a logarithmic (dB)
cannam@86 11 amplitude axis. The integer plotting algorithm used is similar to
cannam@86 12 Bresenham's algorithm.
cannam@86 13
cannam@86 14
cannam@86 15
cannam@86 16 \subsection{Floor 1 format}
cannam@86 17
cannam@86 18 \subsubsection{model}
cannam@86 19
cannam@86 20 Floor type one represents a spectral curve as a series of
cannam@86 21 line segments. Synthesis constructs a floor curve using iterative
cannam@86 22 prediction in a process roughly equivalent to the following simplified
cannam@86 23 description:
cannam@86 24
cannam@86 25 \begin{itemize}
cannam@86 26 \item the first line segment (base case) is a logical line spanning
cannam@86 27 from x_0,y_0 to x_1,y_1 where in the base case x_0=0 and x_1=[n], the
cannam@86 28 full range of the spectral floor to be computed.
cannam@86 29
cannam@86 30 \item the induction step chooses a point x_new within an existing
cannam@86 31 logical line segment and produces a y_new value at that point computed
cannam@86 32 from the existing line's y value at x_new (as plotted by the line) and
cannam@86 33 a difference value decoded from the bitstream packet.
cannam@86 34
cannam@86 35 \item floor computation produces two new line segments, one running from
cannam@86 36 x_0,y_0 to x_new,y_new and from x_new,y_new to x_1,y_1. This step is
cannam@86 37 performed logically even if y_new represents no change to the
cannam@86 38 amplitude value at x_new so that later refinement is additionally
cannam@86 39 bounded at x_new.
cannam@86 40
cannam@86 41 \item the induction step repeats, using a list of x values specified in
cannam@86 42 the codec setup header at floor 1 initialization time. Computation
cannam@86 43 is completed at the end of the x value list.
cannam@86 44
cannam@86 45 \end{itemize}
cannam@86 46
cannam@86 47
cannam@86 48 Consider the following example, with values chosen for ease of
cannam@86 49 understanding rather than representing typical configuration:
cannam@86 50
cannam@86 51 For the below example, we assume a floor setup with an [n] of 128.
cannam@86 52 The list of selected X values in increasing order is
cannam@86 53 0,16,32,48,64,80,96,112 and 128. In list order, the values interleave
cannam@86 54 as 0, 128, 64, 32, 96, 16, 48, 80 and 112. The corresponding
cannam@86 55 list-order Y values as decoded from an example packet are 110, 20, -5,
cannam@86 56 -45, 0, -25, -10, 30 and -10. We compute the floor in the following
cannam@86 57 way, beginning with the first line:
cannam@86 58
cannam@86 59 \begin{center}
cannam@86 60 \includegraphics[width=8cm]{floor1-1}
cannam@86 61 \captionof{figure}{graph of example floor}
cannam@86 62 \end{center}
cannam@86 63
cannam@86 64 We now draw new logical lines to reflect the correction to new_Y, and
cannam@86 65 iterate for X positions 32 and 96:
cannam@86 66
cannam@86 67 \begin{center}
cannam@86 68 \includegraphics[width=8cm]{floor1-2}
cannam@86 69 \captionof{figure}{graph of example floor}
cannam@86 70 \end{center}
cannam@86 71
cannam@86 72 Although the new Y value at X position 96 is unchanged, it is still
cannam@86 73 used later as an endpoint for further refinement. From here on, the
cannam@86 74 pattern should be clear; we complete the floor computation as follows:
cannam@86 75
cannam@86 76 \begin{center}
cannam@86 77 \includegraphics[width=8cm]{floor1-3}
cannam@86 78 \captionof{figure}{graph of example floor}
cannam@86 79 \end{center}
cannam@86 80
cannam@86 81 \begin{center}
cannam@86 82 \includegraphics[width=8cm]{floor1-4}
cannam@86 83 \captionof{figure}{graph of example floor}
cannam@86 84 \end{center}
cannam@86 85
cannam@86 86 A more efficient algorithm with carefully defined integer rounding
cannam@86 87 behavior is used for actual decode, as described later. The actual
cannam@86 88 algorithm splits Y value computation and line plotting into two steps
cannam@86 89 with modifications to the above algorithm to eliminate noise
cannam@86 90 accumulation through integer roundoff/truncation.
cannam@86 91
cannam@86 92
cannam@86 93
cannam@86 94 \subsubsection{header decode}
cannam@86 95
cannam@86 96 A list of floor X values is stored in the packet header in interleaved
cannam@86 97 format (used in list order during packet decode and synthesis). This
cannam@86 98 list is split into partitions, and each partition is assigned to a
cannam@86 99 partition class. X positions 0 and [n] are implicit and do not belong
cannam@86 100 to an explicit partition or partition class.
cannam@86 101
cannam@86 102 A partition class consists of a representation vector width (the
cannam@86 103 number of Y values which the partition class encodes at once), a
cannam@86 104 'subclass' value representing the number of alternate entropy books
cannam@86 105 the partition class may use in representing Y values, the list of
cannam@86 106 [subclass] books and a master book used to encode which alternate
cannam@86 107 books were chosen for representation in a given packet. The
cannam@86 108 master/subclass mechanism is meant to be used as a flexible
cannam@86 109 representation cascade while still using codebooks only in a scalar
cannam@86 110 context.
cannam@86 111
cannam@86 112 \begin{Verbatim}[commandchars=\\\{\}]
cannam@86 113
cannam@86 114 1) [floor1\_partitions] = read 5 bits as unsigned integer
cannam@86 115 2) [maximum\_class] = -1
cannam@86 116 3) iterate [i] over the range 0 ... [floor1\_partitions]-1 \{
cannam@86 117
cannam@86 118 4) vector [floor1\_partition\_class\_list] element [i] = read 4 bits as unsigned integer
cannam@86 119
cannam@86 120 \}
cannam@86 121
cannam@86 122 5) [maximum\_class] = largest integer scalar value in vector [floor1\_partition\_class\_list]
cannam@86 123 6) iterate [i] over the range 0 ... [maximum\_class] \{
cannam@86 124
cannam@86 125 7) vector [floor1\_class\_dimensions] element [i] = read 3 bits as unsigned integer and add 1
cannam@86 126 8) vector [floor1\_class\_subclasses] element [i] = read 2 bits as unsigned integer
cannam@86 127 9) if ( vector [floor1\_class\_subclasses] element [i] is nonzero ) \{
cannam@86 128
cannam@86 129 10) vector [floor1\_class\_masterbooks] element [i] = read 8 bits as unsigned integer
cannam@86 130
cannam@86 131 \}
cannam@86 132
cannam@86 133 11) iterate [j] over the range 0 ... (2 exponent [floor1\_class\_subclasses] element [i]) - 1 \{
cannam@86 134
cannam@86 135 12) array [floor1\_subclass\_books] element [i],[j] =
cannam@86 136 read 8 bits as unsigned integer and subtract one
cannam@86 137 \}
cannam@86 138 \}
cannam@86 139
cannam@86 140 13) [floor1\_multiplier] = read 2 bits as unsigned integer and add one
cannam@86 141 14) [rangebits] = read 4 bits as unsigned integer
cannam@86 142 15) vector [floor1\_X\_list] element [0] = 0
cannam@86 143 16) vector [floor1\_X\_list] element [1] = 2 exponent [rangebits];
cannam@86 144 17) [floor1\_values] = 2
cannam@86 145 18) iterate [i] over the range 0 ... [floor1\_partitions]-1 \{
cannam@86 146
cannam@86 147 19) [current\_class\_number] = vector [floor1\_partition\_class\_list] element [i]
cannam@86 148 20) iterate [j] over the range 0 ... ([floor1\_class\_dimensions] element [current\_class\_number])-1 \{
cannam@86 149 21) vector [floor1\_X\_list] element ([floor1\_values]) =
cannam@86 150 read [rangebits] bits as unsigned integer
cannam@86 151 22) increment [floor1\_values] by one
cannam@86 152 \}
cannam@86 153 \}
cannam@86 154
cannam@86 155 23) done
cannam@86 156 \end{Verbatim}
cannam@86 157
cannam@86 158 An end-of-packet condition while reading any aspect of a floor 1
cannam@86 159 configuration during setup renders a stream undecodable. In addition,
cannam@86 160 a \varname{[floor1\_class\_masterbooks]} or
cannam@86 161 \varname{[floor1\_subclass\_books]} scalar element greater than the
cannam@86 162 highest numbered codebook configured in this stream is an error
cannam@86 163 condition that renders the stream undecodable. Vector
cannam@86 164 [floor1\_x\_list] is limited to a maximum length of 65 elements; a
cannam@86 165 setup indicating more than 65 total elements (including elements 0 and
cannam@86 166 1 set prior to the read loop) renders the stream undecodable. All
cannam@86 167 vector [floor1\_x\_list] element values must be unique within the
cannam@86 168 vector; a non-unique value renders the stream undecodable.
cannam@86 169
cannam@86 170 \subsubsection{packet decode} \label{vorbis:spec:floor1-decode}
cannam@86 171
cannam@86 172 Packet decode begins by checking the \varname{[nonzero]} flag:
cannam@86 173
cannam@86 174 \begin{Verbatim}[commandchars=\\\{\}]
cannam@86 175 1) [nonzero] = read 1 bit as boolean
cannam@86 176 \end{Verbatim}
cannam@86 177
cannam@86 178 If \varname{[nonzero]} is unset, that indicates this channel contained
cannam@86 179 no audio energy in this frame. Decode immediately returns a status
cannam@86 180 indicating this floor curve (and thus this channel) is unused this
cannam@86 181 frame. (A return status of 'unused' is different from decoding a
cannam@86 182 floor that has all points set to minimum representation amplitude,
cannam@86 183 which happens to be approximately -140dB).
cannam@86 184
cannam@86 185
cannam@86 186 Assuming \varname{[nonzero]} is set, decode proceeds as follows:
cannam@86 187
cannam@86 188 \begin{Verbatim}[commandchars=\\\{\}]
cannam@86 189 1) [range] = vector \{ 256, 128, 86, 64 \} element ([floor1\_multiplier]-1)
cannam@86 190 2) vector [floor1\_Y] element [0] = read \link{vorbis:spec:ilog}{ilog}([range]-1) bits as unsigned integer
cannam@86 191 3) vector [floor1\_Y] element [1] = read \link{vorbis:spec:ilog}{ilog}([range]-1) bits as unsigned integer
cannam@86 192 4) [offset] = 2;
cannam@86 193 5) iterate [i] over the range 0 ... [floor1\_partitions]-1 \{
cannam@86 194
cannam@86 195 6) [class] = vector [floor1\_partition\_class] element [i]
cannam@86 196 7) [cdim] = vector [floor1\_class\_dimensions] element [class]
cannam@86 197 8) [cbits] = vector [floor1\_class\_subclasses] element [class]
cannam@86 198 9) [csub] = (2 exponent [cbits])-1
cannam@86 199 10) [cval] = 0
cannam@86 200 11) if ( [cbits] is greater than zero ) \{
cannam@86 201
cannam@86 202 12) [cval] = read from packet using codebook number
cannam@86 203 (vector [floor1\_class\_masterbooks] element [class]) in scalar context
cannam@86 204 \}
cannam@86 205
cannam@86 206 13) iterate [j] over the range 0 ... [cdim]-1 \{
cannam@86 207
cannam@86 208 14) [book] = array [floor1\_subclass\_books] element [class],([cval] bitwise AND [csub])
cannam@86 209 15) [cval] = [cval] right shifted [cbits] bits
cannam@86 210 16) if ( [book] is not less than zero ) \{
cannam@86 211
cannam@86 212 17) vector [floor1\_Y] element ([j]+[offset]) = read from packet using codebook
cannam@86 213 [book] in scalar context
cannam@86 214
cannam@86 215 \} else [book] is less than zero \{
cannam@86 216
cannam@86 217 18) vector [floor1\_Y] element ([j]+[offset]) = 0
cannam@86 218
cannam@86 219 \}
cannam@86 220 \}
cannam@86 221
cannam@86 222 19) [offset] = [offset] + [cdim]
cannam@86 223
cannam@86 224 \}
cannam@86 225
cannam@86 226 20) done
cannam@86 227 \end{Verbatim}
cannam@86 228
cannam@86 229 An end-of-packet condition during curve decode should be considered a
cannam@86 230 nominal occurrence; if end-of-packet is reached during any read
cannam@86 231 operation above, floor decode is to return 'unused' status as if the
cannam@86 232 \varname{[nonzero]} flag had been unset at the beginning of decode.
cannam@86 233
cannam@86 234
cannam@86 235 Vector \varname{[floor1\_Y]} contains the values from packet decode
cannam@86 236 needed for floor 1 synthesis.
cannam@86 237
cannam@86 238
cannam@86 239
cannam@86 240 \subsubsection{curve computation} \label{vorbis:spec:floor1-synth}
cannam@86 241
cannam@86 242 Curve computation is split into two logical steps; the first step
cannam@86 243 derives final Y amplitude values from the encoded, wrapped difference
cannam@86 244 values taken from the bitstream. The second step plots the curve
cannam@86 245 lines. Also, although zero-difference values are used in the
cannam@86 246 iterative prediction to find final Y values, these points are
cannam@86 247 conditionally skipped during final line computation in step two.
cannam@86 248 Skipping zero-difference values allows a smoother line fit.
cannam@86 249
cannam@86 250 Although some aspects of the below algorithm look like inconsequential
cannam@86 251 optimizations, implementors are warned to follow the details closely.
cannam@86 252 Deviation from implementing a strictly equivalent algorithm can result
cannam@86 253 in serious decoding errors.
cannam@86 254
cannam@86 255 {\em Additional note:} Although \varname{[floor1\_final\_Y]} values in
cannam@86 256 the prediction loop and at the end of step 1 are inherently limited by
cannam@86 257 the prediction algorithm to [0, \varname{[range]}), it is possible to
cannam@86 258 abuse the setup and codebook machinery to produce negative or
cannam@86 259 over-range results. We suggest that decoder implementations guard
cannam@86 260 the values in vector \varname{[floor1\_final\_Y]} by clamping each
cannam@86 261 element to [0, \varname{[range]}) after step 1. Variants of this
cannam@86 262 suggestion are acceptable as valid floor1 setups cannot produce
cannam@86 263 out of range values.
cannam@86 264
cannam@86 265 \begin{description}
cannam@86 266 \item[step 1: amplitude value synthesis]
cannam@86 267
cannam@86 268 Unwrap the always-positive-or-zero values read from the packet into
cannam@86 269 +/- difference values, then apply to line prediction.
cannam@86 270
cannam@86 271 \begin{Verbatim}[commandchars=\\\{\}]
cannam@86 272 1) [range] = vector \{ 256, 128, 86, 64 \} element ([floor1\_multiplier]-1)
cannam@86 273 2) vector [floor1\_step2\_flag] element [0] = set
cannam@86 274 3) vector [floor1\_step2\_flag] element [1] = set
cannam@86 275 4) vector [floor1\_final\_Y] element [0] = vector [floor1\_Y] element [0]
cannam@86 276 5) vector [floor1\_final\_Y] element [1] = vector [floor1\_Y] element [1]
cannam@86 277 6) iterate [i] over the range 2 ... [floor1\_values]-1 \{
cannam@86 278
cannam@86 279 7) [low\_neighbor\_offset] = \link{vorbis:spec:low:neighbor}{low\_neighbor}([floor1\_X\_list],[i])
cannam@86 280 8) [high\_neighbor\_offset] = \link{vorbis:spec:high:neighbor}{high\_neighbor}([floor1\_X\_list],[i])
cannam@86 281
cannam@86 282 9) [predicted] = \link{vorbis:spec:render:point}{render\_point}( vector [floor1\_X\_list] element [low\_neighbor\_offset],
cannam@86 283 vector [floor1\_final\_Y] element [low\_neighbor\_offset],
cannam@86 284 vector [floor1\_X\_list] element [high\_neighbor\_offset],
cannam@86 285 vector [floor1\_final\_Y] element [high\_neighbor\_offset],
cannam@86 286 vector [floor1\_X\_list] element [i] )
cannam@86 287
cannam@86 288 10) [val] = vector [floor1\_Y] element [i]
cannam@86 289 11) [highroom] = [range] - [predicted]
cannam@86 290 12) [lowroom] = [predicted]
cannam@86 291 13) if ( [highroom] is less than [lowroom] ) \{
cannam@86 292
cannam@86 293 14) [room] = [highroom] * 2
cannam@86 294
cannam@86 295 \} else [highroom] is not less than [lowroom] \{
cannam@86 296
cannam@86 297 15) [room] = [lowroom] * 2
cannam@86 298
cannam@86 299 \}
cannam@86 300
cannam@86 301 16) if ( [val] is nonzero ) \{
cannam@86 302
cannam@86 303 17) vector [floor1\_step2\_flag] element [low\_neighbor\_offset] = set
cannam@86 304 18) vector [floor1\_step2\_flag] element [high\_neighbor\_offset] = set
cannam@86 305 19) vector [floor1\_step2\_flag] element [i] = set
cannam@86 306 20) if ( [val] is greater than or equal to [room] ) \{
cannam@86 307
cannam@86 308 21) if ( [highroom] is greater than [lowroom] ) \{
cannam@86 309
cannam@86 310 22) vector [floor1\_final\_Y] element [i] = [val] - [lowroom] + [predicted]
cannam@86 311
cannam@86 312 \} else [highroom] is not greater than [lowroom] \{
cannam@86 313
cannam@86 314 23) vector [floor1\_final\_Y] element [i] = [predicted] - [val] + [highroom] - 1
cannam@86 315
cannam@86 316 \}
cannam@86 317
cannam@86 318 \} else [val] is less than [room] \{
cannam@86 319
cannam@86 320 24) if ([val] is odd) \{
cannam@86 321
cannam@86 322 25) vector [floor1\_final\_Y] element [i] =
cannam@86 323 [predicted] - (([val] + 1) divided by 2 using integer division)
cannam@86 324
cannam@86 325 \} else [val] is even \{
cannam@86 326
cannam@86 327 26) vector [floor1\_final\_Y] element [i] =
cannam@86 328 [predicted] + ([val] / 2 using integer division)
cannam@86 329
cannam@86 330 \}
cannam@86 331
cannam@86 332 \}
cannam@86 333
cannam@86 334 \} else [val] is zero \{
cannam@86 335
cannam@86 336 27) vector [floor1\_step2\_flag] element [i] = unset
cannam@86 337 28) vector [floor1\_final\_Y] element [i] = [predicted]
cannam@86 338
cannam@86 339 \}
cannam@86 340
cannam@86 341 \}
cannam@86 342
cannam@86 343 29) done
cannam@86 344
cannam@86 345 \end{Verbatim}
cannam@86 346
cannam@86 347
cannam@86 348
cannam@86 349 \item[step 2: curve synthesis]
cannam@86 350
cannam@86 351 Curve synthesis generates a return vector \varname{[floor]} of length
cannam@86 352 \varname{[n]} (where \varname{[n]} is provided by the decode process
cannam@86 353 calling to floor decode). Floor 1 curve synthesis makes use of the
cannam@86 354 \varname{[floor1\_X\_list]}, \varname{[floor1\_final\_Y]} and
cannam@86 355 \varname{[floor1\_step2\_flag]} vectors, as well as [floor1\_multiplier]
cannam@86 356 and [floor1\_values] values.
cannam@86 357
cannam@86 358 Decode begins by sorting the scalars from vectors
cannam@86 359 \varname{[floor1\_X\_list]}, \varname{[floor1\_final\_Y]} and
cannam@86 360 \varname{[floor1\_step2\_flag]} together into new vectors
cannam@86 361 \varname{[floor1\_X\_list]'}, \varname{[floor1\_final\_Y]'} and
cannam@86 362 \varname{[floor1\_step2\_flag]'} according to ascending sort order of the
cannam@86 363 values in \varname{[floor1\_X\_list]}. That is, sort the values of
cannam@86 364 \varname{[floor1\_X\_list]} and then apply the same permutation to
cannam@86 365 elements of the other two vectors so that the X, Y and step2\_flag
cannam@86 366 values still match.
cannam@86 367
cannam@86 368 Then compute the final curve in one pass:
cannam@86 369
cannam@86 370 \begin{Verbatim}[commandchars=\\\{\}]
cannam@86 371 1) [hx] = 0
cannam@86 372 2) [lx] = 0
cannam@86 373 3) [ly] = vector [floor1\_final\_Y]' element [0] * [floor1\_multiplier]
cannam@86 374 4) iterate [i] over the range 1 ... [floor1\_values]-1 \{
cannam@86 375
cannam@86 376 5) if ( [floor1\_step2\_flag]' element [i] is set ) \{
cannam@86 377
cannam@86 378 6) [hy] = [floor1\_final\_Y]' element [i] * [floor1\_multiplier]
cannam@86 379 7) [hx] = [floor1\_X\_list]' element [i]
cannam@86 380 8) \link{vorbis:spec:render:line}{render\_line}( [lx], [ly], [hx], [hy], [floor] )
cannam@86 381 9) [lx] = [hx]
cannam@86 382 10) [ly] = [hy]
cannam@86 383 \}
cannam@86 384 \}
cannam@86 385
cannam@86 386 11) if ( [hx] is less than [n] ) \{
cannam@86 387
cannam@86 388 12) \link{vorbis:spec:render:line}{render\_line}( [hx], [hy], [n], [hy], [floor] )
cannam@86 389
cannam@86 390 \}
cannam@86 391
cannam@86 392 13) if ( [hx] is greater than [n] ) \{
cannam@86 393
cannam@86 394 14) truncate vector [floor] to [n] elements
cannam@86 395
cannam@86 396 \}
cannam@86 397
cannam@86 398 15) for each scalar in vector [floor], perform a lookup substitution using
cannam@86 399 the scalar value from [floor] as an offset into the vector \link{vorbis:spec:floor1:inverse:dB:table}{[floor1\_inverse\_dB\_static\_table]}
cannam@86 400
cannam@86 401 16) done
cannam@86 402
cannam@86 403 \end{Verbatim}
cannam@86 404
cannam@86 405 \end{description}