# 1フレームを詳しく追う
他の文書はコーデックを一般論として説明しています。この文書では、同梱サンプルから
実際の1フレームを取り出し、そこに何が入っているかを見ます。
対象は **`examples/male.mcelp` の11番目のフレーム**——75フレーム中で最も音量が
大きく、したがって明確な有声フレームなので標本として適しています。以下の値は
すべてデコーダが実際に計算するもので、公開 API から再現できます。
## 18バイト
```
8bc0e96cbdf270a68e6723e8b575c7a6bb80
```
14フィールドに展開すると:
| 0 | 139 | `008b` | LSF:予測器モード1、第1段索引11 |
| 1 | 3086 | `0c0e` | LSF:第2段、前半14、後半48 |
| 2 | 150 | `0096` | サブフレーム0 — ピッチラグ |
| 3 | −13345 | `cbdf` | サブフレーム0 — コードブック索引 |
| 4 | 19 | `0013` | サブフレーム0 — 利得索引 |
| 5 | 16 | `0010` | サブフレーム1 — ラグ差分 |
| 6 | −22898 | `a68e` | サブフレーム1 — コードブック索引 |
| 7 | 51 | `0033` | サブフレーム1 — 利得索引 |
| 8 | 145 | `0091` | サブフレーム2 — ピッチラグ |
| 9 | −2982 | `f45a` | サブフレーム2 — コードブック索引 |
| 10 | 93 | `005d` | サブフレーム2 — 利得索引 |
| 11 | 14 | `000e` | サブフレーム3 — ラグ差分 |
| 12 | 15669 | `3d35` | サブフレーム3 — コードブック索引 |
| 13 | 110 | `006e` | サブフレーム3 — 利得索引 |
抑圧フラグは立っていないので、通常のフレームです。
コードブック索引が負の数として表示される点に注意してください。16ビットの
フィールドを `i16` に入れているためで、符号なしで読めば `0xcbdf`、`0xa68e`、
`0xf45a`、`0x3d35` です。クラスを選ぶのは符号なしの値の方です。
## スペクトル
フィールド0と1が量子化器の索引を与えます。
```
mode = 1, stage1 = 11, stage2_low = 14, stage2_high = 48
```
逆量子化して線スペクトル周波数に変換すると、Q13 ラジアンとヘルツで:
| Q13 | 2813 | 3549 | 7166 | 9497 | 10438 | 12433 | 15565 | 16477 | 19464 | 20408 |
| Hz | 437 | 552 | 1114 | 1476 | 1622 | 1932 | 2419 | 2561 | 3025 | 3172 |
表現が要求するとおり厳密に昇順です。この数列が読めるものになるのは、**近接した
対が共振を示す**からです。
| 437 / 552 | 114 Hz | 494 Hz 付近 |
| 2419 / 2561 | 142 Hz | 2490 Hz 付近 |
| 3025 / 3172 | 147 Hz | 3099 Hz 付近 |
一方、間隔の広い対(362 Hz、310 Hz)はその間の平坦な領域を表しています。第1
フォルマントが 500 Hz 付近、第2が 1300–1800 Hz 帯にあるのは、男声の後舌母音に
典型的な配置です。
これこそ量子化器の重み付けが利用している性質です。密集した線こそ正確に符号化
すべきもので、動かすとフォルマントが動いてしまうからです。
## ピッチ
| 0 | 150(絶対) | 69 + ⅓ | 115 Hz |
| 1 | 16(相対) | 69 − ⅓ | 116 Hz |
| 2 | 145(絶対) | 68 − ⅓ | 118 Hz |
| 3 | 14(相対) | 67 + 0 | 119 Hz |
8 kHz でラグ約69標本は基本周波数 116 Hz 付近——男声です——そしてフレームの
40 ms の間に2標本ぶん上昇しています。通常の発話でのピッチ変化として普通の速さ
です。
第2・第4のラグがいかに安価かに注目してください。それぞれ8ビットではなく5ビット
で、しかも直前のラグから1〜2標本以内に着地しています。差分符号化が拠って立つ
仮定そのものです。
## 励振
| 0 | `0xcbdf` | 5 | 双子5パルス |
| 1 | `0xa68e` | 3 | 2パルス、40 × 40 の位置 |
| 2 | `0xf45a` | 5 | 双子5パルス |
| 3 | `0x3d35` | 0 | 3パルス、8 × 16 × 16 |
1フレームの中に3種類の構造が現れています。6種類を持つ意味はここにあります。
探索はサブフレームごとに選び、有声フレームだからといって始めから終わりまで
一様にパルス的なわけではありません。
同梱2例の全体——600サブフレーム——でのクラス使用率:
| 0 | 33.0 % |
| 1 | 15.3 % |
| 2 | 8.8 % |
| 3 | 7.7 % |
| 4 | 4.3 % |
| 5 | 30.8 % |
両極が支配的です。クラス0(最も細かいトラック配置に3パルス)とクラス5(密な
双子コードブック)で3分の2近くを占めます。中間のクラスは、その間に落ちるものの
ために存在しています。
## 利得
| 0 | 19 | 1 | 3 |
| 1 | 51 | 3 | 3 |
| 2 | 93 | 5 | 13 |
| 3 | 110 | 6 | 14 |
各索引は第1段の3ビットの行と第2段の4ビットの行に分かれ、2つの行を成分ごとに
加算してピッチ利得と符号利得の補正係数を得ます。フレーム内で索引が上昇して
いるのは信号が大きくなっていることを表します——これはファイル中で最も音量の
大きいフレームですが、その末尾でもまだ上昇中です。
## デコーダはこれをどう使うか
4つのサブフレームそれぞれについて、順に:
1. 線スペクトルを補間してこのサブフレームの `1/A(z)` を得る;
2. 過去の励振をラグ位置で読み、適応寄与を得る;
3. 16ビット索引から励振波形を再構成する;
4. ピッチ利得を逆量子化し、符号利得を予測して補正する;
5. スケールした2つの寄与を足して励振とする;
6. `1/A(z)` を通して80標本の音声を得る;
7. ポストフィルタを掛けて出力する。
18バイトが入り、320バイトの μ-law が出ます。
## 再現方法
```rust
use mcelp::{bitstream, lsp};
let text = std::fs::read_to_string("examples/male.mcelp")?;
let frame = text.lines().nth(11).and_then(bitstream::parse_hex_line).unwrap();
let params = bitstream::unpack(&bitstream::canonicalize(&frame));
println!("{:?}", params.field);
println!("{:?}", lsp::LsfIndices::unpack(params.field[0], params.field[1]));
for half in 0..2 {
for sub in 0..2 {
println!("{:?}", params.subframe(half, sub));
}
}
```
ラグのフィールドは、各半フレームの第1サブフレームには `pitch::decode_absolute`、
第2サブフレームには `pitch::decode_relative` が必要です。コードブック索引の
クラスは、その索引が超えている `tables::FCB_CLASS_BASE` の最大の要素です。