owned this note
owned this note
Published
Linked with GitHub
TODO:
- how are the 8 coefficents mapped to 16?
- what is the initial state?
---
# N64 ADPCM format (v1)
`tabledesign -s` creates $2^s$ sets of 8 coefficients known as the **codebook**. Each set of 8 coefficients somehow maps to an entry in a table loaded in the rcp with 16 coefficients (yet to be determined). This set then makes up a 8x10 matrix as follows (numbers are the coefficient index out of the 16 coefficients set as a table entry):
$$
A_n =
\begin{bmatrix}
c_{0} & c_{8} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & d_{n} \\
c_{1} & c_{9} & c_{8} & 0 & 0 & 0 & 0 & 0 & 0 & d_{n+1} \\
c_{2} & c_{10} & c_{9} & c_{8} & 0 & 0 & 0 & 0 & 0 & d_{n+2} \\
c_{3} & c_{11} & c_{10} & c_{9} & c_{8} & 0 & 0 & 0 & 0 & d_{n+3} \\
c_{4} & c_{12} & c_{11} & c_{10} & c_{9} & c_{8} & 0 & 0 & 0 & d_{n+4} \\
c_{5} & c_{13} & c_{12} & c_{11} & c_{10} & c_{9} & c_{8} & 0 & 0 & d_{n+5} \\
c_{6} & c_{14} & c_{13} & c_{12} & c_{11} & c_{10} & c_{9} & c_{8} & 0 & d_{n+6} \\
c_{7} & c_{15} & c_{14} & c_{13} & c_{12} & c_{11} & c_{10} & c_{9} & c_{8} & d_{n+7} \\
\end{bmatrix}
$$
($d$ coefficents are the coefficents from `data` below)
A frame makes up 16 samples in total, that is, $s_{n}..s_{n+15}$. 9 bytes represent an encoded frame. The first byte is header data. The first nibble of that byte is a scaling factor $a$ where $0 \le a \le 12$ (explained later). The second nibble is an index to the table entry to use (which is the set of 16 coefficients used for the matrix above). From here each nibble of the 8 bytes are put into two vectors each of size 8, sequentially, $d_{n..n+7}$ and $d_{n+8..n+15}$. The data is then scaled by $d_n' = 2^a d_n$.
The matrix above is multiplied by a vector of size 10:
$$
x_n =
\begin{bmatrix}
s_{n-2}, s_{n-1}, d_n, ..., d_{n+6}, 1
\end{bmatrix}^T
$$
to get a vector of 8 samples. use $A_n$ for the first 8 samples, use $A_{n+8}$ for the next samples. $s_{n-2}$ and $s_{n-1}$ are the previous two samples. For the first 8 samples these are the 15th and 16th sample from the previous frame or initial state. For the second 8 samples, they are the 7th and 8th samples from the first 8 samples.
The two matrix-vector multiplication results in the next frame.
$$
s_{n..n+7} = A_n x_n
\hspace{10mm}
s_{n+8..n+15} = A_{n+8} x_{n+8}
$$
Each coefficient $c_n$ is in the format `Q4.11`. This is one signed bit, 4 integer bits, and 11 fractional bits. The $1$ used in the $x_n$ vector is also a `Q4.11`, that is, `0x0800`. Each $d_n$ is a signed 16-bit integer. This then means each element-element multiplication in the matrix multiplication is between a signed 16-bit integer and a `Q4.11`. The result of the matrix multiplication is a `Q4.11` assumed to be in the range $-1.0 \le x < 1.0$. This is then converted to a 16-bit signed integer by using only the fractional portion. This is done by multiplying it by $2^5 = 32$, which is equivalent to a left shift of 5.
Note: code says that the `Q3.12` format is used, however, this doesn't quite add up as evident by $1$'s representation as `0x800` and the conversion to a signed 16-bit number.
## Explanation
If we consider the first two samples:
$$
s_{n} = d_n + c_0 s_{n-2} + c_8 s_{n-1}
$$
$$
s_{n+1} = d_{n+1} + c_1 s_{n-2} + c_9 s_{n-1} + c_8 d_{n+1}
$$
If we then let $d_{n+1}' = d_{n+1} - c_9 d_n - c_9 c_8 s_{n-1}$ and $c_1' = c_1 - c_9 c_0$
$$
s_{n+1} = d_{n+1}' + c_1' s_{n-2} + c_9 s_{n}
$$
We can then write each subsequent sample for $0 < k < 8$ as:
$$
s_{n+k} = d_{n+k}' + c_{k}' s_{n-2} + c_{k+8} s_{n+k-1}
$$
where:
$$d_{n+k}' = d_{n+k} - c_{k+8} d_{n + k - 1}' - c_{k + 8} c_{k + 7} s_{n+k-1}
\hspace{10mm}
c_k' = c_k - c_{k+8} c_{k-1}'$$
This means for each group of 8 samples, each sample is composed of a linear combination of the the reference sample $s_{n-2}$, the previous sample $s_{n+k-1}$, then a differential factor (the delta in adpcm) is added.
Example:
![](https://i.imgur.com/VOyuJRe.png)
To create the target point (red), first a linear combination of the previous sample (orange) and the reference sample (green) is needed. The picture above has two examples of linear combinations represented in purple (the horizontal position of this point is arbitrary). the first is a 60% previous + 40% reference interpolation, the next is a 100% previous 0% next. From here an offset (red) is added to create the final sample. Note: the linear combination does not need to add up to 100%. The linear comination is chosen from the coefficient table entry that has the highest precision towards the 16 target samples in a frame.