\section{\module{audioop} --- 生の音声データを操作する}

\declaremodule{builtin}{audioop}
\modulesynopsis{
生の音声データを操作する}

\module{audioop} モジュールは音声データを操作する関数を収録しています。
このモジュールは、Python 文字列型中に入っている 8,  16, 32 ビットの
符号付き整数でできた音声データ、すなわち \refmodule{al} および
\refmodule{sunaudiodev} で使われているのと同じ形式の音声データを操作
します。特に指定の無いかぎり、スカラ量を表す要素はすべて整数型になって
います。

% This para is mostly here to provide an excuse for the index entries...

このモジュールはa-LAW、u-LAWそしてIntel/DVI ADPCMエンコードをサポートしています。
\index{Intel/DVI ADPCM}
\index{ADPCM, Intel/DVI}
\index{u-LAW}

複雑な操作のうちいくつかはサンプル幅が 16 ビットのデータに対して
のみ働きますが、
それ以外は常にサンプル幅を操作のパラメタとして (バイト単位で) 渡します。

このモジュールでは以下の変数と関数を定義しています：

\begin{excdesc}{error}
この例外は、未知のサンプル当たりのバイト数を指定した時など、
全般的なエラーに対して送出されます。
\end{excdesc}

\begin{funcdesc}{add}{fragment1, fragment2, width}
パラメタに渡した 2 つのデータを加算した結果を返します。
\var{width}はサンプル幅をバイトで表したもので、
\code{1}、\code{2}、\code{4}のうちいずれかです。
2 つのデータは同じサンプル幅でなければなりません。
\end{funcdesc}

\begin{funcdesc}{adpcm2lin}{adpcmfragment, width, state}
Intel/DVI ADPCM 形式のデータをリニア (linear) 形式にデコードします。
ADPCM 符号化方式の詳細については\function{lin2adpcm()} の説明を
参照して下さい。\code{(\var{sample}, \var{newstate})} からなる
タプルを返し、サンプルは\var{width} に指定した幅になります。
\end{funcdesc}

\begin{funcdesc}{alaw2lin}{fragment, width}
a-LAW形式のデータをリニア (linear) 形式に変換します。
a-LAW形式は常に 8 ビットのサンプルを使用するので、ここでは
\var{width} は単に出力データのサンプル幅となります。
\versionadded{2.5}
\end{funcdesc}

\begin{funcdesc}{avg}{fragment, width}
データ中の全サンプルの平均値を返します。
\end{funcdesc}

\begin{funcdesc}{avgpp}{fragment, width}
データ中の全サンプルの平均 peak-peak 振幅を返します。
フィルタリングを行っていない場合、このルーチンの有用性は疑問です。
\end{funcdesc}

\begin{funcdesc}{bias}{fragment, width, bias}
元データの各サンプルにバイアスを加えたデータを返します。
\end{funcdesc}

\begin{funcdesc}{cross}{fragment, width}
引数に渡したデータ中のゼロ交差回数を返します。
\end{funcdesc}

\begin{funcdesc}{findfactor}{fragment, reference}
\code{rms(add(\var{fragment}, mul(\var{reference}, -\var{F})))} を
最小にするような係数\var{F} 、すなわち、\var{reference} に乗算した
ときにもっとも \var{fragment} に近くなるような値を返します。
\var{fragment}と\var{reference} のサンプル幅はいずれも 2バイト
でなければなりません。

このルーチンの実行に要する時間は\code{len(\var{fragment})}に比例します。
\end{funcdesc}

\begin{funcdesc}{findfit}{fragment, reference}
\var{reference} を可能な限り \var{fragment} に一致させようとします
(\var{fragment} は \var{reference} より長くなければなりません)。
この処理は (概念的には) \var{fragment} からスライスをいくつか取り出し、
それぞれについて\function{findfactor()} を使って最良な一致を計算し、
誤差が最小の結果を選ぶことで実現します。
\var{fragment}と\var{reference}のサンプル幅は両方とも2バイトでなければな
りません。\code{(\var{offset}, \var{factor})} からなるタプルを返します。
\var{offset} は最適な一致箇所が始まる\var{fragment}のオフセット値（整
数）で、\var{factor}は\function{findfactor()} の返す係数
(浮動小数点数) です。
\end{funcdesc}

\begin{funcdesc}{findmax}{fragment, length}
\var{fragment} から、長さが\var{length} サンプル (バイトではありません!)
で最大のエネルギーを持つスライス、
すなわち、\code{rms(fragment[i*2:(i+length)*2])} を
最大にするようなスライスを探し、 \var{i} を返します。
データのはサンプル幅は 2バイトでなければなりません。

このルーチンの実行に要する時間は\code{len(\var{fragment})}に比例します。
\end{funcdesc}

\begin{funcdesc}{getsample}{fragment, width, index}
データ中の\var{index} サンプル目の値を返します。
\end{funcdesc}

\begin{funcdesc}{lin2adpcm}{fragment, width, state}
データを 4 ビットの Intel/DVI ADPCM 符号化方式に変換します。
ADPCM 符号化方式とは適応符号化方式の一つで、あるサンプルと
(可変の) ステップだけ離れたその次のサンプルとの差を 4 ビットの整数
で表現する方式です。 Intel/DVI ADPCMアルゴリズムは IMA 
(国際MIDI協会) に採用されているので、おそらく標準になるはずです。

\var{state} はエンコーダの内部状態が入ったタプルです。
エンコーダは\code{(\var{adpcmfrag}, \var{newstate})} のタプルを返し、
次に \function{lin2adpcm()}を呼び出す時に\var{newstate} を渡さねば
なりません。最初に呼び出す時には\var{state}に\code{None} を渡しても
かまいません。\var{adpcmfrag} は ADPCMで符号化されたデータで、バイト
当たり 2 つの4ビット値がパックされています。
\end{funcdesc}

\begin{funcdesc}{lin2alaw}{fragment, width}
音声データの各サンプルを a-LAW 符号でエンコードし、Python文字列として
返します。a-LAW とは音声符号化方式の一つで、約 13 ビットに相当する
ダイナミックレンジをわずか 8 ビットで実現できます。 Sun やその他の音声
ハードウェアで使われています。
\versionadded{2.5}
\end{funcdesc}

\begin{funcdesc}{lin2lin}{fragment, width, newwidth}
サンプル幅を 1、2、4 バイト形式の間で変換します。
\end{funcdesc}

\begin{funcdesc}{lin2ulaw}{fragment, width}
音声データの各サンプルを u-LAW 符号でエンコードし、Python文字列として
返します。 u-LAW とは音声符号化方式の一つで、約 14 ビットに相当する
ダイナミックレンジをわずか 8 ビットで実現できます。 Sun やその他の音声
ハードウェアで使われています。
\end{funcdesc}

\begin{funcdesc}{minmax}{fragment, width}
音声データ全サンプル中における最小値と最大値からなるタプルを返します。
\end{funcdesc}

\begin{funcdesc}{max}{fragment, width}
音声データ全サンプルの\emph{絶対値} の最大値を返します。
\end{funcdesc}

\begin{funcdesc}{maxpp}{fragment, width}
音声データの最大 peak-peak 振幅を返します。
\end{funcdesc}

\begin{funcdesc}{mul}{fragment, width, factor}
元のデータの全サンプルに浮動小数点数\var{factor}を掛けたデータを返します。
オーバフローが起きても例外を送出せず無視します。
\end{funcdesc}

\begin{funcdesc}{ratecv}{fragment, width, nchannels, inrate, outrate,
                         state\optional{, weightA\optional{, weightB}}}
入力したデータのフレームレートを変換します。

\var{state} は変換ルーチンの内部状態を入れたタプルです。
変換ルーチンは\code{(\var{newfragment}, \var{newstate})}
を返し、次に\function{ratecv()}を呼び出す時には\var{newstate}を
渡さなねばなりません。最初の呼び出しでは\code{None}を渡します。

引数\var{weightA}と\var{weightB} は単純なデジタルフィルタの
パラメタで、デフォルト値はそれぞれ\code{1} と\code{0}です。
\end{funcdesc}

\begin{funcdesc}{reverse}{fragment, width}
データ内のサンプルの順序を逆転し、変更されたデータを返します。
\end{funcdesc}

\begin{funcdesc}{rms}{fragment, width}
データの自乗平均根 (root-mean-square) 、すなわち
\begin{displaymath}
\catcode`_=8
\sqrt{\frac{\sum{{S_{i}}^{2}}}{n}}
\end{displaymath}
を返します。これはオーディオ信号の強度 (power) を測る一つの目安です。
\end{funcdesc}

\begin{funcdesc}{tomono}{fragment, width, lfactor, rfactor}
ステレオ音声データをモノラル音声データに変換します。
左チャネルのデータに \var{lfactor}、右チャネルのデータに \var{rfactor}
を掛けた後、二つのチャネルの値を加算して単一チャネルの信号を生成します。
\end{funcdesc}

\begin{funcdesc}{tostereo}{fragment, width, lfactor, rfactor}
モノラル音声データをステレオ音声データに変換します。
ステレオ音声データの各サンプル対は、モノラル音声データの各サンプルを
それぞれ左チャネルは \var{lfactor} 倍、右チャネルは \var{rfactor} 倍
して生成します。
\end{funcdesc}

\begin{funcdesc}{ulaw2lin}{fragment, width}
u-LAW で符号化されている音声データを線形に符号化された音声データに
変換します。 u-LAW 符号化は常にサンプル当たり 8 ビットを使うため、
\var{width} は出力音声データのサンプル幅にしか使われません。
\end{funcdesc}

\function{mul()} や\function{max()} といった操作はモノラルと
ステレオを区別しない、すなわち全てのデータを平等に扱うという
ことに注意してください。この仕様が問題になるようなら、あらかじめ
ステレオ音声データを二つのモノラル音声データに分割しておき、
操作後に再度統合してください。そのような例を以下に示します:

\begin{verbatim}
def mul_stereo(sample, width, lfactor, rfactor):
    lsample = audioop.tomono(sample, width, 1, 0)
    rsample = audioop.tomono(sample, width, 0, 1)
    lsample = audioop.mul(lsample, width, lfactor)
    rsample = audioop.mul(rsample, width, rfactor)
    lsample = audioop.tostereo(lsample, width, 1, 0)
    rsample = audioop.tostereo(rsample, width, 0, 1)
    return audioop.add(lsample, rsample, width)
\end{verbatim}

ADPCM エンコーダを使って音声データの入ったネットワークパケットを
構築する際、自分のプロトコルを (パケットロスに耐えられるように)
ステートレス (stateless) にしたいなら、データだけでなく状態変数 (state)
も伝送せねばなりません。このとき、伝送するのはエンコード後状態
(エンコーダの返す値) ではなく、エンコーダの初期状態 
(\function{lin2adpcm()} に渡した値) \var{initial} なので注意してください。
\function{struct.struct()}
を使って状態変数をバイナリ形式で保存したいなら、最初の要素 
(予測値) は 16 ビットで、次の値 (デルタ係数: delta index) は 8 ビット
で符号化できます。

このモジュールの ADPCM 符号のテストは自分自身に対してのみ行っており、
他の ADPCM 符号との間では行っていません。作者が仕様を誤解している
部分もあるかもしれず、それぞれの標準との間で相互運用できない場合も
あり得ます。

\function{find*()} ルーチンは一見滑稽に見えるかもしれません。
これらの関数の主な目的はエコー除去 (echo cancellation) にあります。
エコー除去を十分高速に行うには、出力サンプル中から最も大きな
エネルギーを持った部分を取り出し、この部分が入力サンプル中の
どこにあるかを調べ、入力サンプルから出力サンプル自体を減算します:

\begin{verbatim}
def echocancel(outputdata, inputdata):
    pos = audioop.findmax(outputdata, 800)    # 1/10秒
    out_test = outputdata[pos*2:]
    in_test = inputdata[pos*2:]
    ipos, factor = audioop.findfit(in_test, out_test)
    # Optional (for better cancellation):
    # factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)], 
    #              out_test)
    prefill = '\0'*(pos+ipos)*2
    postfill = '\0'*(len(inputdata)-len(prefill)-len(outputdata))
    outputdata = prefill + audioop.mul(outputdata,2,-factor) + postfill
    return audioop.add(inputdata, outputdata, 2)
\end{verbatim}