工 - みる会図書館


検索対象: Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-
104件見つかりました。

1. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

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. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

2.3 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 ala—predictor. c リスト 2.11 プリエンファシスフィルター処理 ( ala ー p て edicto て . c ) / * プリエンファシス ( t32 , マ ce ) */ ALAPredictorApiResu1t ALAEmphasisFi1ter—PreEmphasisInt32 ( int32—t* data, uint32—t num—samples , int32—t coef—shift) uint32—t smpl ; int32-t prev—int32, tmp-int32; const int32—t coef—numer = (int32-t) ( ( 1 くく coef-shift) / * 引数チェック * / if (data = = NULL) { return ALAPRED 工 CTOR—AP 工 RESULT—INVAL 工 D-ARGUMENT ; / * フィルタ適用 * / prev—int32 0 ; smpl く num-samples ; smpl + + ) { for (smpl tmp—int32 = data Csmp1] ; (int32—t) ALAUTIL 工 TY-SHIFT—RIGHT—AR 工 T}NET 工 C (prev—int32 * data [smpl] coef—numer, coef—shift) ; prev—int32 tmp—int32 ; return ALAPRED 工 CTOR—APIRESULT—OK ; 63 入力データ data をその場で ( ⅲ - place で ) 書き換える関数である。フィルター計算は固 定小数乗算を使用しており、式 2.7 の″に該当する係数との乗算を、 ( 1 くく coef-shift) 1 との乗算処理と、 coef-shift の右シフト処理に分けて実現している。 ALA バージョ ン 1.0.0 では、 coef-shift は 5 に設定されているため、フィルター係数″の値は ″ = ( 25 ー 1 ) / 25 = 31 / 32 = 0.96875 に相当する。 デ工ンファシスフィルター処理 デ工ンファシスフィルター処理の実装をリスト 2.12 に示す。 408 409 410 411 412 413 414 415 416 417 418 419 リスト 2.12 デ工ンファシスフィルター処理 (ala_predictor. c) / * デ工ンファシス ( をれ t32 , をれマ乙 ace ) * / ALAPredictorApiResu1t ALAEmphasisFilter—DeEmphasisInt32 ( int32—t* data, uint32—t num—samples , int32—t coef—shift) uint32—t smpl ; const int32-t coef—numer = (int32-t) ( ( 1 くく coef-shift) / * 引数チェック */ if (data = = NULL) { return ALAPRED 工 CTOR_AP 工 RESULT_ 工 NVAL 工 D—ARGUMENT ;

3. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

62 return ALAPRED 工 CTOR_AP 工 RESULT_OK ; 変換処理部分の実装をリスト 2.10 に示す。 528 529 } 第 2 章 実装編 522 523 524 525 リスト 2.10 LR 復元処理部分 (ala-predictor. c) side = data[l] [smpl] ; mid = (dataC0] [smpl] くく 1 ) ー (side & 1 ) ; (int32-t) ALAUT 工 L 工 TY-SH 工 FT—RIGHT—AR 工 THMET 工 C (mid ー side data[l] [smpl] (int32—t) ALAUTIL 工 TY—SH 工 FT—RIGHT—AR 工 THMET 工 C (mid + side data [ 0 ] Csmp1] まず S チャンネル成分の下位 lbit の情報を使って MS 成分を復元してから、後は式 2.5 , 2.6 によって LR チャンネル成分を復元している。 2.3.5 プリエンファシス / デ工ンファシス 線形予測の前処理として、プリエンファシスという処理が行われる事が多い [ 1 , 11 ] 。プ リエンファシスは、音声の高周波数成分を強調する処理であり、しばしばタップ数 1 の FIR フィルターで実現される。具体的に処理を式に起こしてみると、時刻〃における出 カリ ( れ ) は、現在の入力ェ ( れ ) と直前時刻の入力ェ ( れ一 1 ) を用いて式 2.7 で定義される。 ( 2.7 ) はプリエンファシスとは逆に低周波数成分を強調する処理であり、次の式 2.12 で定義さ プリエンファシス処理を施したデータを元に戻す処理にデ工ンファシスがある。これ ため、直流成分を完全に打ち消す効果を持つ。 ″ 1 の範囲に設定される。もし″ = 1 ならば式 2.7 は入力データの差分計算に該当する こでは FIR フィルターの係数であり、プリエンファシス処理においては 0.9 れる。 ( 2 ・ 8 ) プリエンファシスフィルター処理の実装をリスト 2.11 に示す。 プリエンファシスフィルター処理 予測で得られる係数が安定 ( 発散しにくい状態 ) になりやすいとの結果を示している。 いう説明が多くなされる。 [ 11 ] では実験的に、プリエンファシスを使用した場合は、線形 数成分が相対的に持ち上がり、スペクトラムが平坦になるのが良い分析結果をもたらすと なされていない。一般に、プリエンファシス処理によって、収録時に失われがちな高周波 何故プリエンファシス処理が上手くいくのか、筆者が調べた限り、その定性的な説明は

4. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

60 第 2 章実装編 と、 M は L チャンネルと R チャンネルの符号が同一 ( 同相 ) の成分が強められ、符号が Ⅳ , S はそれぞれ中心、側面成分を示している。一方、相関除去の立場から考えてみる 逆 ( 逆相 ) が弱められた成分、 S は M と逆の性質を持った成分と考えられる。 M , S は以下の式 2.5 , 2.6 によってなに戻すことができる。 MS 処理の実装解説 MS 処理の実装をリスト 2.7 に示す。 リスト 2.7 LR 信号を MS 信号に変換 (ala_predictor. c) ( 2.5 ) ( 2 ・ 6 ) 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 ALAPredictorApiResu1t ALAChanne1Decorre1ator_LRtoMS 工Ⅱt32 (int32_t **data, uint32—t num—channels , uint32_t num_samples) uint32—t smpl ; int32_t mid, side ; / * 引数チェック * / if ( (data ! = NULL) Ⅱ (data[0] ! = NULL) Ⅱ (data[l] ! = NULL) Ⅱ (num-channels く 2 ) ) { return ALAPRED 工 CTOR-APIRESULT_INVALID_ARGUMENT ; / * サンプル単位でー > 処理 * / f0 て (smpl 0 ; smpl く num—samples ; smpl + + ) { / * 注意 : 除算は右シフト必須 ( / 2 ではだめ。 0 方向に丸められる ) * / mid = (int32—t ) ALAUT 工 LITY—SH 工 FT—R 工 GHT-ARITHMET 工 C (data [ 0 ] [smpl] + data [ 1 ] [smpl] , 1 ) ; side = data[0] [smpl] ー dataC1] Csmp1] ; dataCO] [smpl] = mid; dataC1] [smpl] Side ; return ALAPRED 工 CTOR-AP 工 RESULT_OK ; 単純な MS 処理の式 2.3 , 2.4 とは異なり、以下のコードにより変換を行っている。 496 497 498 リスト 2.8 MS 変換処理部分 (ala_predictor. c) / * 注意 : 除算は右シフト必須 ( / 2 ではだめ。 0 方向に丸められる ) * / mid = (int32-t) ALAUTILITY_SH 工 FT_RIGHT_ARITHMET 工 C (data [ 0 ] [smpl] + data [ 1 ] Csmp1] , side = data[0] [smpl] ー dataC1] Csmp1] ;

5. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

実装編 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 = 8 ; tmp ト BITSTREAM_GETLOWERBITS (stream—>bit_count , stream—>bit—count ; n_bits while (n—bits > stream—>bit—count) { * 2 回目以降は 8 t 単位で入力し t にセット */ * 初回ループでは t の上位ビットにセット / * 最上位ビットからデータを埋めていく return BITSTREAM_APIRESULT_ 工 NVALID_ARGUMENT ; if (n—bits > sizeof (uint64_t) * 8 ) { / * 入力可能な最大ビット数を越えている * / return BITSTREAM_AP 工 RESULT_INVAL 工 D_MODE ; 第 2 章 n—bits , uint64—t *val) int32_t ch; uint64—t tmp = 0 ; / * 引数チェック * / if (stream = = NULL Ⅱ val = = NULL) { return BITSTREAM_APIRESULT_INVAL 工 D_ARGUMENT ; / * 読み込みモードでない場合は即時リターン */ if ( ! (stream—>flags & BITSTREAM_FLAGS-F 工 LEOPENMODE READ) ) { stream—>bit—buffer) くく n_bits; / * プバイト読み込みとエラー処理 */ if ( ()h = fgetc (stream->fp) ) = EOF) { if (feof (stream->fp) ) { / * 途中でファイル終端に達していたら、ループを抜ける * / goto END-OF_STREAM; } else { / * それ以外のエラー * / return BITSTREAM_APIRESULT_ 工 OERROR ; END_OF_STREAM : / * 端数ビットの処理 stream—>bit—buffer stream—>bit_count (uint8—t) ch ; * 残ったビット分を t の最下位ビットにセット * / stream—>bit—count n_bits; tmp ト (uint64-t) BITSTREAM_GETLOWERB 工 TS (n_bits , bit—buffer > > stream—>bit_count) ) ; / * 正常終了 */ *val tmp ; return B 工 TSTREAM_APIRESULT_OK ; (uint32—t) (stream—>

6. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

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] ) ;

7. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

2.3 ala—predictor. c 整数の乗算時にオーバーフローが発生する可能性があるため * 6 ) 。このソースに対して幾 固定小数演算を行うにあたり、小数部の bit 幅は 15 としている (16bit とすると、 32bit の bit 幅が 15 のため、 0.5 は 1 を 14bit 左シフトして得ることができる。 乗算時の右シフトによる切り捨てに対策するための定数 half を定義している。小数部 294 const 土Ⅱ t32 ー t half = (IUL くく 14 ) ; 293 / * 丸め誤差軽減のための加算定数 = 0.5 * / リスト 2.2 乗算時の定数 (ala-predictor ・ c) 乗算時の右シフト対策の定数 つか補足を入れる。 前向き誤差計算 57 313 314 315 316 317 318 319 320 前向き誤差計算 (ala-predictor ・ c) data [samp] ; mul—temp for ( 0 て d = 1 ; 0 て d く = order; ord + + ) { / * 前向き誤差計算 */ forward—residual [ 0 ] / * 格子型フィルタにデータ入力 */ リスト 2.3 forward—residual [ 0 て d ] forward—residual [ord ー 1 ] ー mul—temp ; backward—residual [ 0 て d ー 1 ] + half , 15 ) ; (int32-t) ALAUT 工 LITY-SHIFT-R 工 GHT-AR 工 THMET 工 C (parcor-coef [ 0 て d ] * 式 1.21 に従って低次の前向き誤差から順次前向き計算を行っている。途中、固定小数乗 算を行い変数 mul_temp に代入している。注目すべきは ALAUT 工 L 工 TY-SHIFT-RIGHT-AR 工 THMET 工 C マクロである。これは算術右シフト演算を確実に行うためのマクロであり、 ala-utility. h に定義がある。 リスト 2.4 算術右シフトマクロ (ala-utility. 五) #define ALAUTIL 工 TY—SHIFT—RIGHT_ARITHMETIC (sint32 , 17 / * 注意 ) 有効範囲 : 0 ←”れ叮 t ← 32 */ 16 / * 算術右シフトが無効な環境では、自分で定義するハッカーのたのしみのより引用 * / #else rshift) ) #define ALAUT 工 L 工 TY—SHIFT—RIGHT—ARITHMETIC (sint32 , 13 / * 算術右シフトが有効な環境では、そのまま右シフト * / #if ( ( ( ( 土 nt32 ー t ) ー 1 ) > > 1 ) ( ( 土Ⅱ t32 ー t ) ー 1 ) ) / * 算術右シフト */ 11 12 14 15 18 19 rshift) ((sint32) > > ( rshift) \ ( 0X80000000UL > > ( ( ( ( (uint64-t) (sint32) + 0X80000000UL ) > > (rshift) ) rshift) ) ) * 6 例えば、 16bit 整数の最大値 65535 どうしの乗算は 65535 x 65535 = 4294836225 。 32bit 整数の最大値を超えておりオーバーフローしている。 これは、符号付き

8. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

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) ;

9. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

2.4 bit_stream. c 71 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 } / * 読み込みモードでは実行不可能 * / stream—>bit—buffer ー = (uint8—t)BITSTREAM—GETLOWERBITS (stream¯> n_bits = n_bits stream—>bit_count ; whi1e (n—bits > = stream—>bit—count) { * 2 回目以降は 8 し概単位で出力 */ * 初回ループでは端数 ( 出力に必要なビット数 ) 分を埋め出力 / * 乙の上位ビットから順次出力 return B 工 TSTREAM_APIRESULT—OK ; if (n—bits / * 0 ビット出力では何もしない * / return BITSTREAM_APIRESULT—工 NVALID—ARGUMENT ; if (n-bits > sizeof (uint64—t) * 8 ) { / * 出力可能な最大ビット数を越えている * / return B 工 TSTREAM_APIRESULT_ 工 NVALID—MODE ; if (stream->flags & B 工 TSTREAM-FLAGS-FILEOPENMODE—READ) { = EOF) { return BITSTREAM-AP 工 RESULT—IOERROR ; if (fputc (stream—>bit—buffer, stream—>fp) bit—count , va1 > > n—bits) ; / * 端数ビットの処理 : stream—>bit_count stream—>bit—buffer = 0 ; 8 ; * 残った分をバッフアの上位ビットにセット */ assert(n—bits く = 8 ) ; stream—>bit_count n_bits ; stream—>bit—buffer ー = (uint8—t) (BITSTREAM—GETLOWERB 工 TS (n—bits , stream—>bit—count) ; return BITSTREAM_AP 工 RESULT-OK ; val) くく コメントにもあるようにアプリケーション側で出力対象の値を lbit 単位に分けて出力 を行えばリスト 2.14 に相当する処理を実現できるが、その処理の簡略化のために本関数 リスト 2.15 上位 bit からの出力処理 (bit- ト 2.15 の while ループに表れている。 力する。即ち、出力対象の引数値 val の最上位 bit から順に出力を行う。この処理はリス 1 バイト (8bit) を超える数値出力の際には、本モジュールはビッグエンディアンで出 を用意している。 stream . C

10. Introduction to Lossless Audio Codec ロスレス音声コーデック -基本理論と実装-

2.4 bit_stream . c 73 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 } return B 工 TSTREAM_APIRESULT_ 工 NVALID_ARGUMENT ; / * 読み込みモードでない場合は即時リターン * / if ( ! (stream->flags & BITSTREAM—FLAGS—F 工 LEOPENMODE—READ) ) { return B 工 TSTREAM_APIRESULT_ 工 NVALID_MODE ; / * 入力ビットカウントをプ減らし、バッフアの対象ビットを出力 * / if (stream—>bit—count > 0 ) { stream—>bit_count— (*bit) (stream—>bit—buffer > > stream—>bit—count) & 1 ; return B 工 TSTREAM—APIRESULT_OK ; / * プバイト読み込みとエラー処理 * / if ( ()h = fgetc (stream->fp) ) if (feof(stream → (p)) { / * ファイル終端に達した * / return BITSTREAM_APIRESULT_EOS ; } else { / * それ以外のエラー * / return BITSTREAM_AP 工 RESULT_IOERROR ; / * カウンタとバッフアの更新 * / stream—>bit_count = 7 ; (uint8-t) ch; stream—>bit_buffer / * 取得したバッフアの最上位ビットを出力 * / (*bit) (stream->bit—buffer > > 7 ) & 1 ; return BITSTREAM—APIRESULT_OK ; = EOF) { 常に読み込み予定の bit を含むデータ 1 バイト分をバッファ stream->bit-buffer に 取得しておき、バッフアに残っている bit 数のカウンタ stream->bit_count が残って いる限りはそこから lbit 取り出す。カウンタ stream → bit-count が 0 になったら次の データを fgetc 関数によって 1 バイト取得してバッファ stream->bit-buffer とカウ ンタ stream → bit-count を補充し、 lbit を取り出す。 複数 bit 取得処理 最後に複数 bit 取得を行う処理をリスト 2.18 に示す。 リスト 2.18 複数 bit 取得処理 (bit-stream. c) 302 / * n-bits 取得 ( 最大 6 イい t ) し、その値を右詰めして出力 */ 303 BitStreamApiResu1t BitStream_GetBits(struct BitStream* stream, uint32—t