2.5 ala—coder . c 352 } 37 { 54 } Rice 符号化を行う処理をリスト 2.19 に示す。 Rice 符号化処理 に実装している。 考えればよい。 ala-coder. c では、 Rice 符号化と復号処理を 1.2.3 節で示した定義通り ALA では Golomb 符号化のパラメータを 2 の冪数に限定している為、 Rice 符号のみを 2.5.1 Rice 符号 入出力は bit 単位で行う必要があるため、 bit-stream . c に依存している。 理と、ファイルから残差を復号する処理を分担している。なお、本モジュールのファイル このモジュールは、予測によって得られた残差信号を符号化してファイルに書き出す処 2.5 ala_coder . c Ⅱー bits が少なくなるまで while ループを回し、ループの度に 1 バイト取得を行う。 反映される。処理の構造としては BitStream-PutBits とほぼ同様であり、取得 bit 数 取得データは一時変数 tmp に対して上位 bit から順に書き込まれ、最後に引数 val に 75 35 36 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 リスト 2.19 Rice 符号化処理 (ala-coder. c) static void ALACoder—PutRiceCode ( struct BitStream* strm, uint32—t rice—parameter, uint32—t val) uint32—t i , quot , rest ; assert (strm ! = NULL) ; / * 商と剰余の計算 * / quot = va1 > > ALAUti1ity—Log2CeiI(rice—parameter) ; rest = va1 & (rice—parameter ー 1 ) ; / * 商部分の出力 * / 0 ; 土く quot ; i + + ) { for (i BitStream—PutBit (strm, 0 ) ; BitStream—PutBit (strm, 1 ) ; / * 剰余部分の出力 * / BitStream-PutBits (strm, ALAUti1ity-Log2Cei1(rice—parameter) , rest) ; 符号化対象の数値 val と Rice 符号のパラメータ rice_parameter を用いて商 quot と
2.5 ala_coder . c 77 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 } / * 商部分を取得 * / quot BitStream—GetBit (strm, &bit) ; while (bit quot 十十 ; BitStream—GetBit (strm, &bit) ; } else { rest / * 1 の剰余は 0 */ if (rice—parameter / * 剰余部分を取得 * / return (rice—parameter * quot + rest) ; rest (uint32—t) bitsbuf ; BitStream—GetBits (strm, ALAUti1ity—Log2Cei1(rice—parameter) , uint64_t bitsbuf ; / * ライス符号の剰余部分取得 * / &bitsbuf 符号化処理 ( リスト 2.19 ) の逆の操作を行っているだけである。まず商 quot を住符号 の定義 ( 1 が出現するまでの bit 数 ) に従って取得し、次に Rice 符号のパラメータを元に 剰余 rest を取得する。 2.5.2 残差の符号化と復号 残差の符号化と復号処理は、 Rice 符号のパラメータを入力データに適応しながら変更 し、残差を出力、あるいは取得する処理に要約される。 Rice 符号のパラメータの更新処理 は式 1.54 で見たように平均値の更新処理に帰着される。平均値は有限のサンプル数では 厳密に計算できないので、替わりに推定平均値の計算を行う。符号化と復号処理で全く同 じ様に推定平均値を更新することで、パラメータを適応的に変更しながらでも、可逆な符 号化が実現できる。 残差の符号化 残差の符号化処理をリスト 2.22 に示す。 110 111 112 113 リスト 2.22 残差の符号化処理 (ala-coder ・ c) / * 符号付き整数配列の符号化 * / ALACoderApiResu1t ALACoder-PutDataArray ( struct ALACoder* coder, struct BitStream* strm, const 土Ⅱ t32 ー t * * data, uint32_t num—channels , uint32_t num—samples)
81 2.5 ala—coder . c ALACODER_UPDATE-ESTIMATED-MEAN マクロは、推定平均値を更新するマクロであり、 リスト 2.28 に示す形で定義される。 リスト 2.28 ALACODER—UPDATE-ESTIMATED-MEAN マクロ (ala—coder. c 17 / * 推定平均値の更新マクロ ( 指数移動平均により推定平均値を更新 ) * / 18 #define ALACODER-UPDATE—ESTIMATED-MEAN (mean, uint) { \ (mean) = (ALAC0derFixedF10at) ( 119 * (mean) + 9 * 19 ALACODER_U 工 NT32—TO—F 工 XED—FLOAT (uint) + (IUL くく 6 ) ) > > 7 ; \ リスト 2.28 は、現在の推定平均値 E 国と新しい入力値ェに対して、更新後の推定平均 値 E / 国を以下の式 2.10 によって計算している。 119E 岡十 9 一 119 128 128 128 右シフトによる切り捨て誤差の影響を緩和するため、小数の 0.5 に相当する (IUL くく 6 ) を加算している。 式 2.10 は指数移動平均による平均値の推定式に他ならない。音声信号は画像に比べイ 号の bit 幅 ( ダイナミックレンジ ) が広いため、信号の変化が急激になりやすい。筆者は、 単純な移動平均を用いていると、信号変化の傾向についていけなくなる可能性を踏まえ、 応答性の高い平均を求める意図で更新式 2.10 を使用している。 残差の復号 残差の復号処理をリスト 2.29 に示す。 リスト 2.29 残差の復号処理 (ala-coder ・ c) / * 符号付き整数配列の復号 * / 150 ALAC0derApiResu1t ALAC0der—GetDataArray ( 151 struct ALACoder* coder , struct BitStream* strm, 152 int32—t** data, uint32—t num—channels , uint32—t num—samples) 153 154 uint32—t ch , smpl , uint ; 155 156 / * 引数チェック * / 157 = NULL) ) { if ( (strm = = NULL) Ⅱ (data = = NULL) Ⅱ (coder 158 return ALACODER— AP 工 RESULT—工 NVAL 工 D ー ARGUMENT ; 159 160 161 / * 平均値初期値の取得 */ 162 fo て ()h = 0 ; ch く num—channels ; c 五 + + ) { 163 uint64_t bitsbuf ; 164 BitStream-GetBits (strm, 16 , &bitsbuf) ; 165 = ALACODER_UINT32_TO_FIXED_FLOAT (bitsbuf) ; coder—>estimated—mean [ch] 166 167 168 20 } ( 2.10 )
78 114 { 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 第 2 章 = NULL) ) { 実装編 uint32—t smpl , ch , uint ; / * 引数チェック */ for (smpl = 0 ; smpl く num—samples ; smpl + + ) { uint64—t mean_uint for ()h = 0 ; ch く num_channels ; ch + + ) { / * 各チャンネルの平均値をセット庵己録 */ return ALACODER—APIRESULT_INVALID_ARGUMENT ; if ( (strm = = NULL) Ⅱ (data = NULL) Ⅱ (coder mean—uint + = ALAUTILITY_S 工 NT32—TO—U 工 NT32 (data Cch] [smpl] ) ; mean_uint / = num_samples ; / * 平均の最大は符号無し 16 い t 整数の最大値に制限 * / mean-uint = ALAUTIL 工 TY-MIN (mean—uint , UINT16_MAX) ; BitStream—PutBits(strm, 16 , mean_uint) ; return ALACODER—APIRESULT_OK ; ALACODER_UPDATE_ESTIMATED_MEAN (coder->estimated_mean [ch] , uint) ; / * 推定平均値を更新 * / —>estimated—mean [ch] ) , uint ) ; ALACoder—PutRiceC0de (strm , ALACODER_CALCULATE-R 工 CE_PARAMETER(coder / * ライス符号化 */ uint = ALAUT 工 LITY-SINT32_TO_UINT32 (data [ch] [smpl] ) ; / * 符号なし整数に変換 * / 0 ; smpl く num-samples ; smpl + + ) { for (smpl for ()h = 0 ; ch く num_channels; ch + + ) { / * 各チャンネル毎に符号化 * / ALACODER_U 工 NT32_TO_FIXED_FLOAT (mean_uint) coder—>estimated—mean [ch] 148 } 符号化処理の前に、推定平均値の初期値を決める必要がある。推定平均値の初期値を設 定する処理をリスト 2.23 に示す。 122 123 124 125 126 127 128 129 130 リスト 2.23 推定平均値の初期化 (ala_coder. c) / * 各チャンネルの平均値をセット庵己録 */ fO て ()h = 0 ; ch く num_channels ; ch + + ) { uint64_t mean_uint for (smpl 0 ; smpl く num-samples ; smpl + + ) { mean-uint + = ALAUTILITY-S 工 NT32-TO-U 工 NT32 (data Cch] [smpl] ) ; mean_uint / = num_samples ; / * 平均の最大は符号無し 16 t 整数の最大値に制限 * / mean-uint = ALAUTIL 工 TY—M 工 N (mean—uint , UINT16_MAX) ;
2.7 malll . C 89 PARCOR 係数のエンコード 量子化した PARCOR 係数は、リスト 2.43 に示す処理でエンコードする。 207 208 209 210 211 212 213 リスト 2.43 PARCOR 係数のエンコード (main ・ c) / * 各チャンネルの c 係数 * / for ()h = 0 ; ch く num—channels; ch + + ) { / * 0 次係数は 0 だから飛ばす * / for ( 0 て d = 1 ; ord く ALA-PARCOR-ORDER + 1 ; ord + + ) { BitStream—PutBits (out—strm , 16 , ALAUTIL 工 TY—SINT32—TO—UINT32 ( parcor—coef—int32 [ch] [ 0 て d ] ) ) ; PARCOR 係数をチャンネルごとに 16bit の列で書き出す。小数部が 15bit の固定小数 ロックのバイナリデータ終端をバイト単位に揃えている ( リスト 2.44 ) 。 1 プロックの残差のエンコードが終わった後、 BitStream-FIush 関数を実行して、 プロック末尾のバイト境界揃え 点数を記録するためには、符号 bit を付け加えると 16bit 必要になる。 218 219 リスト 2.44 プロック末尾のバイト境界揃え (main ・ c) / * バイト境界に揃える * / BitStream—F1ush(out—strm) ; この処理は必須ではないが、プロックがバイト境界に揃っていれば標準ライプラリ関数 を用いたバイト単位の読み取りがしやすくなり、また、同期コードがバイナリエデイタで 視認しやすくなる。 2.7.2 ALA のデコード処理 ALA のデコード処理手順は、次のように要約される。
90 第 2 章 ALA のデコード処理手順 (main. c の do-decode 関数 ) 1. 入力のバイナリデータを開く。 2. ヘッダ情報を取得する。 実装編 3. プロックのデコード処理を行う。以下の処理をへッダから取得したサンプル 数に達するまで繰り返す。 (a) 同期コードをチェックし、 PARCOR 係数を取得する。 (b) 残差をデコードする。 (c) PARCOR 格子型フィルターによる合成を行う。 (d) デ工ンファシスを適用する。 (e) チャンネル数がステレオ ( 2 ) 以上であれば、 MS を LR に戻す。 4. 復元した波形データから wav ファイルを出力する。 ヘッダを取得した後、各プロックのデコード処理は、エンコードの処理手順を逆転した ものであると言える。工ンコード処理の説明 ( 2.7.1 節 ) と同じく、以下では補足説明を バージョンのチェックを行う。 ヘッダ情報の取得の際に、同時にリスト 2.45 に示す処理でシグネチャとフォーマット シグネチャとフォーマットバージョンのチェック 入れる。 リスト 2.45 シグネチャとフォーマットバージョンのチェック (main. c 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 / * シグネチャ * / BitStream-GetBits (in-strm, 32 , &bitsbuf) ; / * シグネチャの確認 * / if ( (((bitsbuf > > 24 ) & 0xFF) ! = ーション * / " lnvalid 凵 signature . 凵 \ Ⅱ " ) ; Ⅱ (((bitsbuf > > 8 ) & OxFF) ! = 'A') Ⅱ (((bitsbuf > > 16 ) & OxFF) ! = / * フォーマットバ return 1 ; fprintf (stderr , Ⅱ ( ( (bitsbuf return 1 ; fprintf (stderr , "Unsupported 凵 format 凵 version : % d 凵 \ が if (bitsbuf ! = ALA—FORMAT—VERSION) { / * シグネチャの確認 */ BitStream—GetBits (in-strm, 16 , &bitsbuf) ; (uint16-t)bitsbuf BitStream-GetBits 関数で 32bit のシグネチャを一気に読み取り、 1 バイトずっ シグネチャ文字との一致を確認する。得られるバイナリデータはビッグエンディア ンのため、上位 bit から順に調べる。また、取得したフォーマットバージョン番号が
59 { 73 { 76 59 { static uint32—t nIz10(uint32-t x) 57 / * ハッカーのたのしみ参照 * / 56 / * z ( 最上位ビットから 1 に当たるまでのビット数 ) を計算する黒魔術 */ リスト 2.20 ALAUti1ity_Log2Cei1 関数 (ala_utility. c) 第 2 章実装編 剰余 rest を計算し、商は。符号 ( 1.2.3 節 ) 、剰余は 2 進数で出力を行っている。 剰余 rest の計算においては rice-parameter は 2 の冪乗数であることを用いて、 AND 演算 (&) によって剰余計算を行っている、 8 。 ALAUti1ity-Log2Cei1 関数は引数の整数ェに対して卩。g2@) ] を高速に計算する関 数であり、 ala-utility. c に定義がある ( リスト 2.20 ) 。 58 60 61 62 63 64 65 66 67 68 69 70 71 72 74 75 76 X X X (x くく 9 ) ー x; (x くく 11 ) ー x ; (x くく 14 ) ー x ; return n1z10—tab1e [x > > 26 ] ; / * ce れ ( 乙。 92 ( ) ) を計算する * / uint32-t ALAUti1ity—Log2Cei1 (uint32_t val) assert(val ! = 0 ) ; return 32U ーⅡ 1N10 ( val 実装は [ 37 ] を引用したものであるが、筆者の力量不足により、このコードが上手く動く理 由を説明できない。 [ 17 , 36 ] に解説とソースコードがあるため、参考にしていただきたい。 Rice 符号化されたデータの復号処理 Rice 符号化されたデータの復号を行う処理をリスト 2.21 に示す。 57 58 60 61 62 63 リスト 2.21 Rice 復号処理 (ala_coder. c) static uint32—t ALACoder—GetRiceCode ( struct BitStream* strm, uint32_t rice_parameter) uint32—t quot , rest ; uint8_t bit ; assert (strm ! = NULL) ; 、 8 整数 val と 2 の冪数 p に対して、 val & (p-l) は val % p に等しい。直感的には、 p-l との AND を 行うことは下位 1 。 g2 ( p ) bit のマスクを取る演算と考えられ、それがまさに剰余演算に相当している。 p = 2 , 4 あたりで試しに計算を行ってみると良い。
80 140 141 142 143 144 145 第 2 章実装編 / * ライス符号化 */ ALACODER_UPDATE_ESTIMATED_MEAN ( coder—>estimated_mean [ch] , uint) ; / * 推定平均値を更新 * / —>estimated-mean [ch] ) , uint) ; ALACoder—PutRiceC0de (strm , ALACODER—CALCULATE—R 工 CE—PARAMETER (coder 1 サンプル毎にサンプルを符号なし整数に変換し、 Rice 符号としての出力と、推 定平均値の更新処理が行われる。こで、推定平均値を Rice 符号パラメータに変換 する処理は ALACODER-CALCULATE-R 工 CE_PARAMETER マクロが、推定平均値の更新は ALACODER-UPDATE-EST 工 MATED-MEAN がその役割を果たす。以下、それらのマクロの説 明を行う。 ALACODER-CALCULATE_R 工 CE-PARAMETER マクロは、式 1.54 に基づいて Rice 符号のパ ラメータを計算するマクロであり、リスト 2.27 に示す形で定義される。 リスト 2.27 ALACODER_CALCULATE_RICE_PARAMETER マクロ (ala_coder. c) ALACODER_FIXED_FLOAT_TO_U 工 NT32 ( (mean) > > 1 ) , 23 ALAUti1ity—RoundUp2Powered (ALAUTILITY—MAX ( 22 #define ALACODER—CALCULATE—RICE—PARAMETER (mean) \ げ * / 21 / * ce 符号のパラメータ計算 2 * * ce れ ( 乙。 92 ( E ( の / 2 ) ) = E 朝 ) / 2 の 2 の冪乗切り上 1 乢 ) ) 式 1.54 をここに再掲する。 ん = max 0 , log2 2 ( 式 1.54 を再掲 ) 両辺の 2 の冪を取った 2 んが計算すべき Rice 符号パラメータとなる。んは単純には式 1.54 を使えばよいが、 2 の対数の切り上げを行う関数 ALAUti1ity-Log2CeiI は負荷が 高い * 9 。そこで、 2 んを以下の式 2.9 によって計算している。 2 ん = max 20 , 2 =clp max 1 , 2 = max l,clp 2 ( 2 ・ 9 ) こで、 clp@) = 2 卩。 ( , ) ] はェを 2 の冪乗数に切り上げる関数である [ 17 ] 。卩 og2 ( ェ ) ] はを 2 進数表示するのに十分な bit 数であり、 2 卩。 g2 ( 工月によりエよりも大きい最小の 2 の冪数が得られる。 clp@) は卩 og2 ( ェ ) ] の計算を介さずに直接計算ができるため、若干 の速度向上が期待できる。 * 9 パラメータ更新処理は符号化対象の全てのサンプルで 1 回ずっ実行されるため、負荷へのインパクトが大
82 169 170 171 172 173 174 175 176 177 178 179 180 181 第 2 章 / * 各チャンネル毎に復号 */ for ()h = 0 ; ch く num_channels; ch + + ) { for (smpl 0 ; smpl く num-samples ; smpl + + ) { / * ライス符号を復号 */ 実装編 uint = ALACoder-GetRiceCode (strm , ALACODER—CALCULATE_RICE_PARAMETER (coder—>estimated—mean Cch] ) ) ; / * 推定平均値を更新 */ ALACODER-UPDATE_EST 工 MATED_MEAN (coder—>estimated_mean [ch] , uint) ; / * 符号付き整数に変換 * / data [ch] [smpl] = ALAUTIL 工 TY_U 工 NT32_TO_SINT32 (uint ) ; return ALACODER-APIRESULT_OK ; 182 } 先頭に記録された平均値の初期値を取得し、残差を復号しながら推定平均値を符号 化の時と同様に更新する。大まかな処理内容について難しい点はないため省略する が、一点 ALAUTIL 工 TY-U 工 NT32_T0-S 工 NT32 マクロは補足が必要である。このマクロは ALAUT 工 LITY-S 工 NT32-TO_U 工 NT32 マクロで変換された符号なし整数を符号付き整数に戻 土Ⅱ t32 ー t ) ( (uint) & 1 ) ) 30 #define ALAUTIL 工 TY-U 工 NT32_TO—S 工 NT32(uint) ( (int32_t) ( (uint) > > 1 ) 29 / * 符号なし 32 t 数値を符号付き 32 t 数値に一意変換 */ リスト 2.30 ALAUTIL 工 TY_UINT32_TO_S 工 NT32 マクロ (ala_utility. h) すマクロであり、 ala_utility. h のリスト 2.30 で定義される。 場合 -((uint > > 1 ) + 1 ) と等しくなる。一方、 ui Ⅱ t が偶数のときは (uint > > 1 ) がそ (uint > > 1 ) を bit 反転した数値が得られ、これは負数を 2 の補数表現に従って表現した 0 と評価される。この値と ((uint) > > 1 ) の A(XOR) を取ると、 uint が奇数のときは -(int32-t) ((uint) & 1 ) は uint が奇数のときに -1(0xFFFFFFFF) 、偶数のときに のまま得られる。この結果に従うと uint = 0 , 1 , 2 , 3 , 4 , . をマクロに適用する と順次 0 , . という結果が得られ、 ALAUT 工 L 工 TY_S 工 NT32_TO_U 工 NT32 マクロの逆の変換が得られていることが分かる。 2.6 wav . c 本モジュールは wav ファイルの入出力を行う機能を提供する。 bit 単位の入出力処理を 行っているが、 bit ー stream. c を使用しておらず独自の入出力処理を実装している。これ は、他の用途で転用できるようにするためである。 本稿では wav ファイルと本モジュールの詳細な解説は省略し、 wav. h で宣言されてい る構造体と API ( 関数 ) の機能についての説明に留める。本モジュールは簡易実装に過ぎ ず、全ての wav ファイルの入出力には対応していないことに注意されたい。本モジュー
2.5 ala_coder . c 131 132 133 BitStream—PutBits (strm, 16 , coder—>estimated—mean [ch] 79 me an_uint ) ; ALACODER_UINT32_TO_F 工 XED—FLOAT (mean—uint) 初期値は適当に 1 等で決め打ちしても処理としては問題ないが、推定平均値の収束を早 くするために、入力データの平均値を推定値の初期値に設定している。また、初期値は残 差の直前に記録しておく。 処理マクロについて補足する。 ALAUTIL 工 TY-S 工 NT32-T0_UINT32 マクロは符号付き整 数を符号無し整数に変換する処理を行う。 Rice 符号は正整数を対象にしているため、符 号化にあたってこの変換は必須である。マクロは ala ー utility. h において次のように定 義される。 リスト 2.24 ALAUTIL 工 TY_SINT32-TO-U 工 NT32 マクロ (ala—utility. h) 27 / * 符号付き 32 とれ数値を符号なし 32 と概数値に一意変換 * / 28 #define ALAUT 工 L 工 TY-SINT32-TO-UINT32(sint) ( ( (int32—t) (sint) く 0 ) ? ( ( ((uint32-t)(((sint) くく 1 ) ) ) ) uint32-t)((-((sint) くく 1 ) ) ー 1 ) ) ・ このマクロによって、正整数は正偶数に、負整数は正奇数に変換される。この変換は絶 対値の小さい方から大きい順に変換後の数値が並ぶため、 Rice 符号のような符号化対象 の数値の絶対値の大きさに追従して出力符号長が長くなる符号にとって都合が良い。符号 付き整数を符号なし整数に変換する手法は他にも幾つか存在し、 [ 9 ] によると、整数を符 号 bit とその絶対値に分けて符号化する方法や、符号を負数に対応させる方法が挙げられ ている。 ALACODER-UINT32-T0-F 工 XED-FLOAT マクロは整数値を固定小数化するマクロである。 マクロの定義をリスト 2.25 に示す。 リスト 2.25 整数値の固定小数化 (ala-coder. c) 13 / * 符号なし整数を固定小数に変換 * / 14 #define ALACODER-U 工 NT32—TO—F 工 XED-FLOAT ( u32 ) ( ( u32 ) くく ( ALACODER_NUM_FRACT 工 ON—PART-BITS) ) 左シフト演算によって、小数部を 0 にした状態の固定小数点数を作成している。固定小 数化する理由としては、平均推定値を更新する際、率直に整数を使うと切り捨てによる精 度落ちが無視できないためである。 符号化と推定平均値の更新処理をリスト 2.26 に示す。 135 136 137 138 139 リスト 2.26 符号化処理コア部分 (ala-coder ・ c) / * 各チャンネル毎に符号化 * / for ()h = 0 ; ch く num—channels ; c + + ) { 0 ; smpl く num—samples ; smpl + + ) { f0 て (smpl / * 符号なし整数に変換 */ uint = ALAUTIL 工 TY-S 工 NT32—TO—UINT32 (data [ch] [smpl] ) ;