56 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 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 第 2 章 int32—t* residual) 実装編 const int32—t* data, uint32—t num—samples , const int32—t* parcor—coef , uint32—t order, uint32—t samp , 0 て d ; int32—t* forward—residual ; int32_t* backward_residual ; int32—t mul—temp ; / * 丸め誤差軽減のための加算定数 = 0.5 * / (IUL くく 14 ) ; const int32_t half / * 引数チェック * / if (lpc = = NULL Ⅱ data = = NULL Ⅱ parcor—coef = = NULL Ⅱ residual = = NULL) { return ALAPRED 工 CTOR—APIRESULT_INVAL 工 D—ARGUMENT ; / * 次数チェック * / if ( 0 て de て > lpc—>max-order) { return ALAPRED 工 CTOR_APIRESULT-EXCEED_MAX—ORDER; / * オート変数にポインタをコピー * / lpc—>forward—residual ; forward_residual lpc—>backward—residual ; backward_residual / * 誤差計算 * / fo て (samp = 0 ; samp く num—samples ; samp + + ) { / * 格子型フィルタにデータ入力 * / forward—residual [ 0 ] data Csamp] ; / * 前向き誤差計算 * / for (ord = 1 ; 0 て d く = order; 0 て d + + ) { mul—temp return ALAPRED 工 CTOR-APIRESULT_OK ; residual Csamp] forward—residual [ 0 て de て ] ; / * 残差信号 * / backward—residual [ 0 ] = data Csamp] ; / * 後ろ向き誤差計算部にデータ入力 */ backward—residual [ 0 て d ] backward—residual [ord ー 1 ] ー mul—temp ; forward—residual [ 0 て d ー 1 ] + half , 15 ) ; (int32—t) ALAUTILITY—SHIFT_RIGHT_ARITHMETIC (parcor—coef Cord] * mul—temp for ( 0 て d = 0 て de て ; ord > = 1 ; ord——) { / * 後ろ向き誤差計算 * / forward—residual [ 0 て d ] forward—residual [ 0 て d ー 1 ] ー mul—temp ; backward—residual [ 0 て d ー 1 ] + half , 15 ) ; (int32—t) ALAUTIL 工 TY-SHIFT-R 工 GHT—AR 工 THMETIC (parcor-coef [ 0 て d ] *
58 20 #endif 第 2 章 実装編 一般に整数型に対する右シフト演算 ( > > ) は、算術右シフト演算になるとは限らない [ 17 ] ため、符号なし整数を用いた算術右シフト演算を定義している。 後ろ向き誤差計算 321 322 323 324 325 326 327 328 リスト 2.5 後ろ向き誤差計算 (ala_predictor. c) / * 後ろ向き誤差計算 * / fO て ( 0 て d = order; 0 て d > = 1 ; ord——) { mul—temp (int32—t) ALAUTIL 工 TY-SHIFT_R 工 GHT_AR 工 THMETIC (parcor_coef [ord] * forward-residual [ord ー 1 ] + half , 15 ) ; backward—residual [ 0 て d ] = backward—residual [ord ー 1 ] ー mul_temp ; / * 後ろ向き誤差計算部にデータ入力 * / backward—residual [ 0 ] = data Csamp] ; 式 1.22 に従って後ろ向き誤差を更新している。前向き誤差とは異なり、変数 backward-residual[ord] は次のループで計算で使用するために、コウジィ・・・から低次 1.23 , 式 1.22 ) の実装を素直に行うだけである。式 1.5 、式 1.22 を再掲する。 PARCOR 係数による残差からの合成処理についても格子型フィルター ( 図 1.5 , 式 2.3.3 PARCOR 合成フィルター 後ろ向き誤差に向かって更新を行わなければならない。 し M ( れ ) = わ M ー 1 ( れ一 1 ) ーん一 1 ( れ ) ( 式 1.22 を再掲 ) ん一 1 ( れ ) = ん回 + わ M ー 1 ( れ一 1 ) ( 式 1.23 を再掲 ) また、 PARCOR 係数による格子型合成フィルターの図 ( 図 1.5 ) をここに再掲する。 十 格子型フィルターの連結 ( 図 1.5 を再掲 ) 十 十 ーア 2 と 1 ( れ ) 十 十 fM(n) y(n) 図 2.3 好れ ) と M ー 1 ( れ )
している。 88 実装の説明に移る。 ALA は性能の良さと処理の単純さから、式 2.12 のサイン窓を使用 W れ S111 ルー 1 第 2 章実装編 ( 2.12 ) プロック単位で窓関数を適用する処理をリスト 2.41 に示す。 151 152 153 154 155 156 リスト 2.41 窓関数の適用処理 (main. c) / * 窓の作成 */ ALAUti1ity—MakeSinWindow (window, num—encode—samples) ; / * 窓掛け * / for ()h = 0 ; ch く num—channels ; - c 五 + + ) { ALAUti1ity-App1yWindow (window , input—ptr [ch] , num—encode—samples) ; ALAUti1ity-MakeSinWindow 関数は式 2.12 の定義式に従って窓関数係数 '( のを生 成し、 ALAUti1ity-App1yWindow 関数は式 2.11 に従って、 1 チャンネル分のデータに対 して窓関数を適用している。 PARCOR 係数の量子化 double 精度で求めた PARCOR 係数を、リスト 2.42 に示す処理で小数部が 15bit の固 定小数点数へ変換 ( 量子化 ) する。 171 172 173 174 175 176 177 178 179 180 181 182 183 リスト 2.42 PARCOR 係数の量子化 (main ・ c) / * c 係数量子化 * / fo て ()h = 0 ; ch く num—channels ; c 五 + + ) { / * 月 c 砒係数の 0 次成分は 0.0 のはずなので処理をスキップ * / parcor—coef—int32 [ch] [ 0 ] fo て ( 0 て d = 0 ; ord く ALA-PARCOR—ORDER ; ord + + ) { / * 整数へ丸める * / parcor—coef—int32 [ch] [ 0 て d ] (int32—t)ALAUti1ity-Round(parcor—coef Cch] [ord] * po ( 2. Of , 15 ) ) ; / * 0 d による丸めによりビット幅をはみ出てしまうことがあるので範囲制限 parcor—coef—int32 Cch] [ord] ー ALAUT 工 LITY-INNER_VALUE (parcor_coef_int32 [ch] [ord] , INT16—MIN , INT16_MAX) ; 1.1.2 節で見たように、 PARCOR 係数の値域は理論的に最小ー 1 、最大 1 に制限されて いる。この数値を小数部が 15bit の固定小数に変換するには、式 2.2 で見たように を乗じて丸めれば良い。ただし、 C89 準拠の環境では round 関数が存在しないため、 ALA では独自実装 (ALAUti1ity-Round 関数 ) を使用している。
2.3 ala—predictor. c 合成処理部分の実装をリスト 2.6 に示す。 59 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 リスト 2.6 PARCOR 合成フィルター実装 (ala-predictor. c) / * 格子型フィルタによる音声合成 */ for (samp = 0 ; samp く num-samples ; samp + + ) { / * 誤差入力 * / forward—residual = residual [samp] ; for ( 0 て d = order; 0 て d > = 1 ; ord——) { / * 前向き誤差計算 * / forward_residual + = (int32-t) ALAUTILITY—SH 工 FT-R 工 GHT-ARITHMET 工 C (parcor—coef [ord] * backward-residual [ord ー 1 ] + half , 15 ) ; / * 後ろ向き誤差計算 */ mul—temp (int32_t) ALAUT 工 LITY-SHIFT—R 工 GHT-AR 工 THMETIC (parcor-coef [ 0 て d ] * forward-residual + half , 15 ) ; backward—residual [ 0 て d ] = backward—residual [ 0 て d ー 1 ] ー mul—temp ; / * 合成信号 * / output Csamp] forward_residual ; / * 後ろ向き誤差計算部にデータ入力 * / backward—residual [ 0 ] forward_residual ・ 残差計算の時とは異なり、前向き誤差と後ろ向き誤差は両方とも高次から低次の残差に 向かって計算するため、前向き誤差と後ろ向き誤差をそれぞれ個別の f 。 r 文によって更新 する必要がない。また、式 1.23 に注目すると、前向き誤差は次のサンプルの計算で使わ れることは無いので配列に記録する必要がなく、単一の変数 forward-residual への積 和演算を行えば良い。これにより合成処理は予測時よりもわずかに早く計算を行える。 2.3.4 MS 処理 CD 等に収録されたステレオ音源は、収録環境 ( マイクの配置、マスタリング等 ) に依 存するが L ( 左 ) チャンネルと R ( 右 ) チャンネルは互いに相関を持っていることが多い。 チャンネル間の相関 ( 他チャンネルの影響 ) を除去できれば、よりチャンネルの独立性 を高めた信号処理を行いやすくなる。チャンネル間の相関を除去する手法の 1 つに MS 処理がある。 MS 処理は多数のコーデックで有効性が認められている [ 26 , 28 ] 。本節では MS 処理について概要と実装を説明する。 MS 処理は、ある時刻における L チャンネル信号力と R チャンネル信号を次の式 2.3 , 2.4 によって M (Mid, ミッド ) チャンネル信号 M と S (Side, サイド ) チャンネル 信号 S に変換する。 M = 十 ( 2 ・ 3 ) ( 2.4 )
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 のデコード処理手順は、次のように要約される。
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 整数の最大値を超えておりオーバーフローしている。 これは、符号付き