%Copyright (C) 2007-2015  Brian Langenberger
%This work is licensed under the
%Creative Commons Attribution-Share Alike 3.0 United States License.
%To view a copy of this license, visit
%http://creativecommons.org/licenses/by-sa/3.0/us/ or send a letter to
%Creative Commons,
%171 Second Street, Suite 300,
%San Francisco, California, 94105, USA.

\chapter{DVD-Audio}
DVD-Audio is a format for delivering hi-fidelity, multichannel
audio on DVD media.
A DVD-Audio's \texttt{AUDIO\_TS} directory contains the
relevant data needed for decoding, spread into a lot of files
whose names are more than a little cryptic at first glance.

Unlike CD audio, which is simply a set of 1 to 99 identically-formatted
audio tracks (in terms of channel count, sample rate and bits per sample),
a DVD-Audio disc contains one or more titlesets.
Each titleset contains one or more titles, and each
title contains one or more tracks.
\begin{figure}[h]
  \includegraphics{figures/dvda/layout.pdf}
\end{figure}
\par
\noindent
Typically, a DVD-Audio disc will contain two titlesets,
one for audio and the other for video - which we can ignore.
The first titleset will often contain two titles,
one for 2 channel audio and the other for 5.1 channel audio.
Each title will usually contain a consistent number of tracks
as MLP or PCM encoded audio.
\par
With this in mind, we can now make some sense of
the \texttt{AUDIO\_TS} directory's contents:
\vskip .25in
$\texttt{\huge{AUDIO\_TS.IFO}}$
\hfill
information about the disc, including the number of titlesets
\vskip .25in
$\texttt{\huge{ATS\_}}\underbrace{\texttt{\huge{01}}}_{Titleset}\texttt{\huge{\_0.IFO}}$
\hfill
information about all the titles in a given titleset
\vskip .25in
$\texttt{\huge{ATS\_}}\underbrace{\texttt{\huge{01}}}_{Titleset}\texttt{\huge{\_}}\underbrace{\texttt{\huge{1}}}_{AOB~\#}\texttt{\huge{.AOB}}$
\hfill
audio data for one or more tracks in a given titleset
\vskip .25in
\par
All are binary files containing one or more, 2048 byte sectors.

\clearpage

\section{AUDIO\_TS.IFO}
Known as the ``Audio Manager'' or ``AMG'',
this is primarily a container of pointers to
other files on disc.
However, for our purposes, we're only interested
in the \VAR{Audio Titleset Count} value.
\begin{figure}[h]
  \includegraphics{figures/dvda/audio_ts_ifo.pdf}
\end{figure}

\clearpage

\section{ATS\_XX\_0.IFO}
{\relsize{-1}
  \input{dvda/algorithms/ats_xx_ifo}
}

\clearpage

\subsubsection{ATS\_XX\_0.IFO Second Sector}
\begin{figure}[h]
\includegraphics{figures/dvda/ats_xx_0.pdf}
\end{figure}

\subsubsection{Title Table}
\begin{figure}[h]
  \includegraphics{figures/dvda/ats_title.pdf}
\end{figure}

\subsubsection{Sector Pointers Table}
\begin{figure}[h]
  \includegraphics{figures/dvda/ats_sectors.pdf}
\end{figure}

\clearpage

\section{ATS\_XX\_X.AOB}

All of a titleset's AOB files can be considered part of a
single, contiguous collection of sectors, each 2048 bytes long.
Thus, it's possible for the start and end sectors for a given track
(as indicated in the sector pointers table) to span two or more
AOB files.
Each sector contains one or more packets as part of a
``Packetized Elementary Stream''.

\begin{figure}[h]
  \includegraphics{figures/dvda/ats_xx_x.pdf}
\end{figure}
\par
\noindent
Packets with a \VAR{stream ID} of \texttt{0xBD} contain encoded audio data.
\VAR{Packet data length} is the length of all data after
the \VAR{packet data length} field to the end of the packet.
\par
\noindent
Each sector within an AOB file is prefixed by a \VAR{Pack Header},
as follows:
\begin{figure}[h]
  \includegraphics{figures/dvda/aob_pack_header.pdf}
\end{figure}
\par
\noindent
The three \VAR{Current PTS} values (3 bits, 15 bits and 15 bits, respectively)
combine to indicate the current position within the stream, in PTS ticks.
There are 90,000 PTS ticks per second.

\clearpage

\subsection{Packet Payload Extraction}

\begin{figure}[h]
  \includegraphics{figures/dvda/audio_packet.pdf}
\end{figure}
\par
\noindent
MLP frame boundaries need not align with packet boundaries.
That is, a single MLP frame may span 2 or more AOB packets.

\clearpage

\section{MLP Decoding}
{\relsize{-1}
  \input{dvda/algorithms/mlp_decoding}
}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_stream.pdf}
\end{figure}

\clearpage

\subsubsection{Frame Decoding}
\label{mlp:framedecoding}
{\relsize{-3}
  \input{dvda/algorithms/decode_frame}
}

\clearpage

\subsubsection{Reading Major Sync}
\label{mlp:readmajorsync}
This is a collection of information about the MLP stream
which occurs occasionally at the start of MLP frames.
Its values are consistent throughout the stream for any given track.
\par
\noindent
{\relsize{0}
  \input{dvda/algorithms/read_major_sync}
}
\begin{tiny}
  \begin{tabular}{|c|r|r|r|l|}
    \hline
    value & \texttt{bps} & \texttt{rate} & channels & channel assignment \\
    \hline
    \texttt{00000} & 16 & 48000 & 1 & front center \\
    \texttt{00001} & 20 & 96000 & 2 & front left, front right\\
    \texttt{00010} & 24 & 192000 & 3 & front left, front right, back center \\
    \texttt{00011} & & & 4 & front left, front right, back left, back right\\
    \texttt{00100} & & & 3 & front left, front right, LFE \\
    \texttt{00101} & & & 4 & front left, front right, LFE, back center \\
    \texttt{00110} & & & 5 & front left, front right, LFE, back left, back right \\
    \texttt{00111} & & & 3 & front left, front right, front center \\
    \texttt{01000} & & 44100 & 4 & front left, front right, front center, back center \\
    \texttt{01001} & & 88200 & 5 & front left, front right, front center, back left, back right \\
    \texttt{01010} & & 176400 & 4 & front left, front right, front center, LFE\\
    \texttt{01011} & & & 5 & front left, front right, front center, LFE, back center \\
    \texttt{01100} & & & 6 & front left, front right, front center, LFE back left, back right \\
    \texttt{01101} & & & 4 & front left, front right, front center, back center \\
    \texttt{01110} & & & 5 & front left, front right, front center, back left, back right \\
    \texttt{01111} & & & 4 & front left, front right, front center, LFE \\
    \texttt{10000} & & & 5 & front left, front right, front center, LFE, back center \\
    \texttt{10001} & & & 6 & front left, front right, front center, LFE, back left, back right \\
    \texttt{10010} & & & 5 & front left, front right, back left, back right, LFE \\
    \texttt{10011} & & & 5 & front left, front right, back left, back right, front center \\
    \texttt{10100} & & & 6 & front left, front right, back left, back right, front center, LFE \\
    \hline
  \end{tabular}
\end{tiny}

\clearpage

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_major_sync.pdf}
\end{figure}
\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_major_sync_parse.pdf}
\end{figure}
{\relsize{-1}
\begin{tabular}{rl}
  $\text{group}_0$ bits-per-sample & 24 \\
  $\text{group}_1$ bits-per-sample & 24 \\
  $\text{group}_0$ sample rate & 96000 Hz \\
  $\text{group}_1$ sample rate & 96000 Hz \\
  channel count & 5 \\
  channel assignment & front left, front right, LFE, back left, back right \\
  is VBR & yes \\
  peak bitrate & 1600 \\
  substream count & 2 \\
\end{tabular}
}

\clearpage

\subsubsection{Substream Info}
\label{mlp:read_substream_info}
{\relsize{-1}
  \input{dvda/algorithms/read_substream_info}
}
\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_substream_info.pdf}
\end{figure}
\par
\noindent
For example, given a frame with 2 substreams
and 2 substream info fields:
\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_substream_info_parse.pdf}
\end{figure}
\begin{table}[h]
\begin{tabular}{rrr}
& $\text{substream}_0$ & $\text{substream}_1$ \\
\hline
extra word present & 0 & 0 \\
nonrestart substream & 0 & 0 \\
checkdata present & 1 & 1 \\
pad & 1 & 0 \\
substream end & $72 \times 2 = 148$ & $159 \times 2 = 318$ \\
\end{tabular}
\end{table}
\par
\noindent
$\text{Substream Data}_0$ contains
the next 148 bytes following the $\text{Substream Info}_1$ field,
and $\text{Substream Data}_1$ contains 170 bytes
following $\text{Substream Data}_0$.
In addition, \VAR{checkdata present} values of 1
means both substreams will be followed by 8 bit parity and CRC-8 values.

\clearpage

\subsection{Decoding Substream}
\label{mlp:decode_substream}
{\relsize{-1}
  \input{dvda/algorithms/decode_substream}
}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_frame.pdf}
\end{figure}


\clearpage

\subsection{Decoding Block}
\label{mlp:decode_block}
{\relsize{-1}
  \input{dvda/algorithms/decode_block}
}


\clearpage

\subsection{Reading Restart Header}
\label{mlp:readrestartheader}
{\relsize{-1}
  \input{dvda/algorithms/read_restart_header}
}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_restart_header.pdf}
\end{figure}

\clearpage

\subsubsection{Reading Restart Header Example}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_restart_header_parse1.pdf}
\end{figure}
\begin{table}[h]
{\relsize{-1}
  \begin{tabular}{rl}
    header sync & \texttt{0x18F5} \\
    noise type & 0 \\
    output timestamp & 0 \\
    min channel & 0 \\
    max channel & 1 \\
    max matrix channel & 1 \\
    noise shift & 0 \\
    noise gen seed & 1 \\
    check data present & 0 \\
    lossless check & 0 \\
    $\text{channel assignment}_0$ & 0 \\
    $\text{channel assignment}_1$ & 1 \\
    checksum & \texttt{0x11} \\
  \end{tabular}
}
\end{table}

\clearpage

\subsection{Reading Decoding Parameters}
\label{mlp:readdecodingparams}
{\relsize{-2}
  \input{dvda/algorithms/read_decoding_parameters}
}

\clearpage

\begin{figure}[h]
  \centering
  \includegraphics{figures/dvda/mlp_decoding_params.pdf}
\end{figure}


\clearpage

\subsubsection{Reading Matrix Parameters}
\label{mlp:readmatrixparams}
{\relsize{-1}
  \input{dvda/algorithms/read_matrix_parameters}
}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_matrix_params.pdf}
\end{figure}

\clearpage

\subsubsection{Reading Channel Parameters}
\label{mlp:readchannelparams}
{\relsize{-2}
  \input{dvda/algorithms/read_channel_parameters}
}

\begin{figure}[h]
  \centering
  \includegraphics[height=1.75in,keepaspectratio]{figures/dvda/mlp_channel_params.pdf}
\end{figure}

\clearpage

\subsubsection{Reading FIR Filter Parameters}
\label{mlp:readfirfilterparams}
{\relsize{-1}
  \input{dvda/algorithms/read_fir_parameters}
}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_fir_filter_params.pdf}
\end{figure}

\clearpage

\subsubsection{Reading IIR Filter Parameters}
\label{mlp:readiirfilterparams}
{\relsize{-1}
  \input{dvda/algorithms/read_iir_parameters}
}

\begin{figure}[h]
  \centering
  \includegraphics[height=2.5in,keepaspectratio]{figures/dvda/mlp_iir_filter_params.pdf}
\end{figure}

\clearpage

\subsubsection{Reading Decoding Parameters Example}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_decoding_params_parse.pdf}
\end{figure}

\clearpage

For example, given that a restart header is present with the values:
\begin{table}[h]
  {\relsize{-1}
    \begin{tabular}{rl}
      min channel & 0 \\
      max channel & 1 \\
      max matrix channel & 1 \\
    \end{tabular}
  }
\end{table}
\par
\noindent
our decoding parameters for a given substream are:
\begin{table}[h]
{\relsize{-1}
  \begin{tabular}{rlrl}
    \hline
    \textsf{flags present} & 0 \\
    \textsf{flags} & \texttt{[1, 1, 1, 1, 1, 1, 1, 1]} \\
    \hline
    \textsf{block size present} & 0 \\
    \textsf{block size} & 8 PCM frames \\
    \hline
    \textsf{matrix parameters present} & 1 \\
    \textsf{matrix count} & 2 \\
    $\textsf{matrix out channel}_0$ & 1 &
    $\textsf{matrix out channel}_1$ & 0 \\
    $\textsf{fractional bits}_0$ & 13 &
    $\textsf{fractional bits}_1$ & 13 \\
    $\textsf{LSB bypass}_0$ & 0 &
    $\textsf{LSB bypass}_1$ & 0 \\
    $\textsf{matrix coeff. present}_{0~0}$ & 0 &
    $\textsf{matrix coeff. present}_{1~0}$ & 1 \\
    $\textsf{matrix coeff.}_{0~0}$ & 0 &
    $\textsf{matrix coeff.}_{1~0}$ & -2053 \\
    $\textsf{matrix coeff. present}_{0~1}$ & 1 &
    $\textsf{matrix coeff. present}_{1~1}$ & 0 \\
    $\textsf{matrix coeff.}_{0~1}$ & -2053 &
    $\textsf{matrix coeff.}_{1~1}$ & 0 \\
    $\textsf{matrix coeff. present}_{0~2}$ & 1 &
    $\textsf{matrix coeff. present}_{1~2}$ & 1 \\
    $\textsf{matrix coeff.}_{0~2}$ & -32 &
    $\textsf{matrix coeff.}_{1~2}$ & 32 \\
    $\textsf{matrix coeff. present}_{0~3}$ & 1 &
    $\textsf{matrix coeff. present}_{1~3}$ & 1 \\
    $\textsf{matrix coeff.}_{0~3}$ & 32 &
    $\textsf{matrix coeff.}_{1~3}$ & 32 \\
    \hline
    \textsf{output shift present} & 1 \\
    $\textsf{output shift}_0$ & 1 &
    $\textsf{output shift}_1$ & 1 \\
    \hline
    \textsf{quantum step size present} & 0 \\
    \hline
    $\textsf{channel parameters present}_0$ & 1 &
    $\textsf{channel parameters present}_1$ & 1 \\
    $\textsf{FIR parameters present}_0$ & 0 &
    $\textsf{FIR parameters present}_1$ & 0 \\
    $\textsf{IIR parameters present}_0$ & 0 &
    $\textsf{IIR parameters present}_1$ & 0 \\
    $\textsf{Huffman offset present}_0$ & 0 &
    $\textsf{Huffman offset present}_1$ & 0 \\
    $\textsf{codebook}_0$ & 0 &
    $\textsf{codebook}_1$ & 0 \\
    $\textsf{Huffman LSB}_0$ & 1 &
    $\textsf{Huffman LSB}_1$ & 1 \\
    \hline
  \end{tabular}
}
\end{table}

\clearpage

\subsubsection{Default Channel Parameters}
\label{mlp:default_channel_parameters}
\input{dvda/algorithms/default_channel_parameters}

\clearpage

\subsection{Reading Residual Data}
\label{mlp:read_residuals}
{\relsize{-1}
  \input{dvda/algorithms/read_residual}
}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_residuals.pdf}
\end{figure}

\clearpage

\begin{figure}[h]
  \label{mlp_codebooks}
  \includegraphics{figures/dvda/mlp_codebook1.pdf}
  \caption{Codebook 1}
  \vskip 2em
  \includegraphics{figures/dvda/mlp_codebook2.pdf}
  \caption{Codebook 2}
  \vskip 2em
  \includegraphics{figures/dvda/mlp_codebook3.pdf}
  \caption{Codebook 3}
\end{figure}

\clearpage

\subsubsection{Reading Residuals Example}
Given the channel parameters:
\begin{table}[h]
{\relsize{-1}
\begin{tabular}{rrr}
& channel 0 & channel 1 \\
\hline
$\textsf{Huffman offset}_c$ & 0 & 0 \\
$\textsf{codebook}_c$ & 1 & 2 \\
$\textsf{Huffman LSBs}_c$ & 2 & 2 \\
\hline
$\textsf{LSB bits}_c$ & 2 & 2 \\
$\textsf{sign shift}_c$ & $3$ & $2$ \\
$\textsf{signed Huffman offset}_c$ & $0 - 7 \times 2 ^ 2 - 2 ^ 3 = -36$ & $0 - 7 \times 2 ^ 2 - 2 ^ 2 = -32$ \\
\end{tabular}
}
\end{table}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_block_parse.pdf}
\end{figure}
{\relsize{-1}
  \begin{tabular}{r||rr>{$}r<{$}|rr>{$}r<{$}}
    $i$ & $\text{MSB}_{0~i}$ & $\text{LSB}_{0~i}$ & \text{residual}_{0~i} &
    $\text{MSB}_{1~i}$ & $\text{LSB}_{1~i}$ & \text{residual}_{1~i} \\
    \hline
    0 & 9 & 3 & 9 \times 2 ^ 2 + 3 - 36 = 3 &
    7 & 1 & 7 \times 2 ^ 2 + 1 - 32 = -3 \\
    1 & 11 & 2 & 11 \times 2 ^ 2 + 2 - 36 = 10 &
    7 & 2 & 7 \times 2 ^ 2 + 2 - 32 = -2 \\
    2 & 11 & 0 & 11 \times 2 ^ 2 + 0 - 36 = 8 &
    8 & 0 & 8 \times 2 ^ 2 + 0 - 32 = 0 \\
    3 & 8 & 3 & 8 \times 2 ^ 2 + 3 - 36 = -1 &
    9 & 3 & 9 \times 2 ^ 2 + 3 - 32 = 7 \\
    4 & 8 & 3 & 8 \times 2 ^ 2 + 3 - 36 = -1 &
    3 & 3 & 3 \times 2 ^ 2 + 3 - 32 = -17 \\
    5 & 11 & 0 & 11 \times 2 ^ 2 + 0 - 36 = 8 &
    4 & 1 & 4 \times 2 ^ 2 + 1 - 32 = -15 \\
    6 & 12 & 3 & 12 \times 2 ^ 2 + 3 - 36 = 15 &
    6 & 0 & 6 \times 2 ^ 2 + 0 - 32 = -8 \\
    7 & 11 & 1 & 11 \times 2 ^ 2 + 1 - 36 = 9 &
    6 & 3 & 6 \times 2 ^ 2 + 3 - 32 = -5 \\
    8 & 5 & 0 & 5 \times 2 ^ 2 + 0 - 36 = -16 &
    8 & 0 & 8 \times 2 ^ 2 + 0 - 32 = 0 \\
    9 & 7 & 0 & 7 \times 2 ^ 2 + 0 - 36 = -8 &
    8 & 3 & 8 \times 2 ^ 2 + 3 - 32 = 3 \\
  \end{tabular}
}

\clearpage

\subsection{Channel Filtering}
\label{mlp:channel_filtering}
{\relsize{-1}
  \input{dvda/algorithms/filter_channels}
}

%%FIXME - add residual filtering example

\clearpage

\subsection{Rematrixing Channels}
\label{mlp:rematrixing}
{\relsize{-1}
  \input{dvda/algorithms/rematrix_channels}
}
\vskip .25in
\par
\noindent
where \texttt{crop} is defined as:
\begin{align*}
  \texttt{crop}(x) &=
  \begin{cases}
    x \bmod{2 ^ 8} & \text{if } \lfloor (x \bmod{2 ^ 8}) \div 2 ^ 7\rfloor = 0 \\
    (x \bmod{2 ^ 7}) - 2 ^ 7 & \text{if } \lfloor (x \bmod{2 ^ 8}) \div 2 ^ 7\rfloor \neq 0
  \end{cases}
\end{align*}

Because each channel may be rematrixed zero or more times,
filtered channels are rematrixed in-place
and the final result is output.

%%FIXME - add rematrixing example

\clearpage

\subsection{Applying Output Shifts}
\label{mlp:output_shifts}
\input{dvda/algorithms/apply_output_shifts}

\clearpage

\subsection{Verifying Parity}
\label{mlp:verify_parity}
If \VAR{checkdata present} is indicated in the \VAR{Restart Header},
each substream is followed by a parity and CRC-8 byte.
Calculating the parity value is a simple matter of performing
\xor on all the substream's bytes including the parity byte itself.
If successful, the result should be \texttt{0xA9}.
\par
For example, given the substream bytes:
\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_parity_parse.pdf}
\end{figure}
\begin{align*}
  \text{parity} &= \texttt{0x95} \xor \texttt{0x00} \xor \texttt{0x20} \xor \texttt{0x00} \xor \texttt{0x1C} = \texttt{0xA9}
\end{align*}

\begin{figure}[h]
  \includegraphics{figures/dvda/mlp_frame.pdf}
\end{figure}

\clearpage

\subsection{Verifying CRC-8}
\label{mlp:verify_crc}
Given a substream byte and previous CRC-8 checksum,
or \texttt{0x3C} as an initial value:
\begin{equation*}
\text{CRC-8}_i = \texttt{crc8}(byte~\xor~\text{CRC-8}_{i - 1});
\end{equation*}
CRC-8 calculation skips the parity and CRC-8 bytes.
\par
\noindent
\texttt{crc8} is taken from the following base-16 table:
\begin{table}[h]
  {\relsize{-1}\ttfamily
    \begin{tabular}{|r||r|r|r|r|r|r|r|r|r|r|r|r|r|r|r|r|r|}
      \hline
      & ?0 & ?1 & ?2 & ?3 & ?4 & ?5 & ?6 & ?7 & ?8 & ?9 & ?A & ?B & ?C & ?D & ?E & ?F \\
      \hline
      0? & 00 & 63 & C6 & A5 & EF & 8C & 29 & 4A & BD & DE & 7B & 18 & 52 & 31 & 94 & F7 \\
      1? & 19 & 7A & DF & BC & F6 & 95 & 30 & 53 & A4 & C7 & 62 & 01 & 4B & 28 & 8D & EE \\
      2? & 32 & 51 & F4 & 97 & DD & BE & 1B & 78 & 8F & EC & 49 & 2A & 60 & 03 & A6 & C5 \\
      3? & 2B & 48 & ED & 8E & C4 & A7 & 02 & 61 & 96 & F5 & 50 & 33 & 79 & 1A & BF & DC \\
      4? & 64 & 07 & A2 & C1 & 8B & E8 & 4D & 2E & D9 & BA & 1F & 7C & 36 & 55 & F0 & 93 \\
      5? & 7D & 1E & BB & D8 & 92 & F1 & 54 & 37 & C0 & A3 & 06 & 65 & 2F & 4C & E9 & 8A \\
      6? & 56 & 35 & 90 & F3 & B9 & DA & 7F & 1C & EB & 88 & 2D & 4E & 04 & 67 & C2 & A1 \\
      7? & 4F & 2C & 89 & EA & A0 & C3 & 66 & 05 & F2 & 91 & 34 & 57 & 1D & 7E & DB & B8 \\
      8? & C8 & AB & 0E & 6D & 27 & 44 & E1 & 82 & 75 & 16 & B3 & D0 & 9A & F9 & 5C & 3F \\
      9? & D1 & B2 & 17 & 74 & 3E & 5D & F8 & 9B & 6C & 0F & AA & C9 & 83 & E0 & 45 & 26 \\
      A? & FA & 99 & 3C & 5F & 15 & 76 & D3 & B0 & 47 & 24 & 81 & E2 & A8 & CB & 6E & 0D \\
      B? & E3 & 80 & 25 & 46 & 0C & 6F & CA & A9 & 5E & 3D & 98 & FB & B1 & D2 & 77 & 14 \\
      C? & AC & CF & 6A & 09 & 43 & 20 & 85 & E6 & 11 & 72 & D7 & B4 & FE & 9D & 38 & 5B \\
      D? & B5 & D6 & 73 & 10 & 5A & 39 & 9C & FF & 08 & 6B & CE & AD & E7 & 84 & 21 & 42 \\
      E? & 9E & FD & 58 & 3B & 71 & 12 & B7 & D4 & 23 & 40 & E5 & 86 & CC & AF & 0A & 69 \\
      F? & 87 & E4 & 41 & 22 & 68 & 0B & AE & CD & 3A & 59 & FC & 9F & D5 & B6 & 13 & 70 \\
      \hline
    \end{tabular}
  }
\end{table}

Continuing the 6 byte substream example from the previous page,
our CRC-8 calculation is as follows:
\begin{align*}
  \texttt{crc8}(\texttt{0x95} \xor \texttt{0x3C}) = \texttt{crc8}(\texttt{0xA9}) &= \texttt{0x24} \\
  \texttt{crc8}(\texttt{0x00} \xor \texttt{0x24}) = \texttt{crc8}(\texttt{0x24}) &= \texttt{0xDD} \\
  \texttt{crc8}(\texttt{0x20} \xor \texttt{0xDD}) = \texttt{crc8}(\texttt{0xFD}) &= \texttt{0xB6} \\
  \texttt{0x00} \xor \texttt{0xB6} &= \texttt{0xB6}
\end{align*}
which matches the substream's CRC-8 value
and indicates the substream data has been read correctly.

\clearpage

\subsection{Unifying Substreams}
\label{mlp:unify_substreams}
\input{dvda/algorithms/unify_substreams}
