音声にしろ動画にしろ,おおくのコーデックの処理は複雑で,ライブラリのお世話にならなければならない. しかし,電話などでつかわれる G.711 という ITU-T 標準のコーデックは非常にかんたんであり,ほとんどテーブル引きだけで実現することができる. ここでは Perl による G.711 の変換・逆変換のプログラムをしめす. もちろん,Perl の特殊機能はつかっていないので,他の言語に容易にかきかえることができる.
G.711 は対数圧縮によって 16 bit の音声を 8 bit に圧縮するコーデックである. G.711 には u-Law (正確には μ-Law) と a-Law という 2 種類があるが,変換のてまはあまりかわらない. ここでは u-Law だけをあつかう.
基本的には,あらかじめつぎのようなテーブルを用意しておけば,これらのテーブルをひくだけで uLaw から線形への変換ができる (ただし,添字の範囲が 0..255 からはずれないようにクリップする必要がある).
# ULAW-to-linear conversion table for upper digit my @ULAW_H = (130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 126, 121, 117, 113, 109, 105, 101, 97, 93, 89, 85, 81, 77, 73, 69, 65, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); # ULAW-to-linear conversion table for lower digit my @ULAW_L = (0, 4, 8, 12, 17, 21, 25, 29, 33, 38, 42, 46, 50, 55, 59, 63, 66, 68, 71, 73, 75, 77, 79, 81, 83, 85, 88, 90, 92, 94, 96, 98, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 243, 244, 180, 53, 181, 54, 182, 55, 184, 56, 185, 57, 186, 58, 187, 59, 188, 60, 157, 221, 29, 94, 158, 222, 30, 95, 159, 223, 31, 96, 160, 224, 32, 97, 145, 177, 209, 241, 17, 50, 82, 114, 146, 178, 210, 242, 18, 51, 83, 115, 139, 155, 171, 187, 203, 219, 235, 251, 11, 28, 44, 60, 76, 92, 108, 124, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 0, 0, 252, 248, 244, 239, 235, 231, 227, 223, 218, 214, 210, 206, 201, 197, 193, 190, 188, 185, 183, 181, 179, 177, 175, 173, 171, 168, 166, 164, 162, 160, 158, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 13, 12, 76, 203, 75, 202, 74, 201, 72, 200, 71, 199, 70, 198, 69, 197, 68, 196, 99, 35, 227, 162, 98, 34, 226, 161, 97, 33, 225, 160, 96, 32, 224, 159, 111, 79, 47, 15, 239, 206, 174, 142, 110, 78, 46, 14, 238, 205, 173, 141, 117, 101, 85, 69, 53, 37, 21, 5, 245, 228, 212, 196, 180, 164, 148, 132, 120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0);
しかし,テーブルの数値をいれなくても,プログラムでそれを生成することができる. つぎにしめすのは初期設定時につぎの 2 つのサブルーティンをよびだすことによってテーブルを生成し,それをつかって変換をおこなうプログラムである.
- gen_u2l() (uLaw から線形への変換 (デコード) テーブルを生成)
- gen_l2u() (線形から uLaw への変換 (エンコード) テーブルを生成)
#============================================================================= # ulaw <-> linear conversion table generator #============================================================================= my $QUANT_MASK = 0xf; my $BIAS = 0x84; my $SEG_MASK = 0x70; my $SEG_SHIFT = 4; my $SIGN_BIT = 0x80; my (@l2u, @u2l); ### u2l($uval) # convert ulaw value to linear value. # sub u2l($) { my ($uval) = @_; $uval = ~$uval; my $t = (($uval & $QUANT_MASK) << 3) + $BIAS; $t <<= ($uval & $SEG_MASK) >> $SEG_SHIFT; return ($uval & $SIGN_BIT) ? ($BIAS - $t) : ($t - $BIAS); } ### gen_u2l() # generate ulaw-to-linear conversion table (@u2l) # sub gen_u2l() { for (my $i = 0; $i < 256; $i++) { $u2l[$i] = u2l($i); }; } ### gen_l2u() # generate linear-to-ulaw conversion table (@l2u) # (This method might not generate an optimum converter.) # sub gen_l2u() { for (my $i = 0; $i < 256; $i++) { my $j = $u2l[$i]; if ($j < 0) { $j += 65536; }; $l2u[$j] = $i; }; for (my $i = 1; $i < 65536; $i++) { if ($l2u[$i] == 0) { $l2u[$i] = $l2u[$i-1]; }; }; }