# 14.1 `audioop` -- 生のオーディオデータの操作

`audioop`モジュールにはサウンドデータに対する便利な操作が定義されています。

このモジュールは、Python文字列で保存された、8、16、32ビットサイズの符合付き整数型からなるサウンドデータを処理します。

このデータは`al`と`sunaudiodev`モジュールで使用されるのと同じフォーマットです。

特に断わらない限り数値項目は整数です。

このモジュールはu-LAWとIntel/DVI ADPCMエンコードをサポートしています。

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

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

exception `error`
  この例外はサウンドサンプルの未知のバイト数など、全てのエラーに対して発生します。

`add`( | fragment1, fragment2, width)

  パラメータとして渡された2つのサンプルの和のデータを返します。

  widthはサンプルサイズのバイト数で、`1`、`2`、`4`のうちのどれかです。 2つのデータは同じサンプルサイズでなければなりません。

`adpcm2lin`( | adpcmfragment, width, state)

  Intel/DVI ADPCMフォーマットのデータをlinearフォーマットにデコードします。 ADPCMフォーマットについての詳細は`lin2adpcm()`の説明を参照して下さい。 widthで指定したサイズで`(sample, newstate)`のタプルを返します。

`adpcm32lin`( | adpcmfragment, width, state)

  3ビットの新しいADPCMフォーマットのデータをデコードします。 詳しくは`lin2adpcm3()`を参照して下さい。

`avg`( | fragment, width)

  データ内の全サンプルの平均値を返します。

`avgpp`( | fragment, width)

  データ内の全サンプルの最大振幅の平均値を返します。 フィルタリングされていないなら、このルーチンが役立つかどうか疑問です。

`bias`( | fragment, width, bias)

  もとのデータのサンプル一つ一つにバイアスを加えたデータを返します。

`cross`( | fragment, width)

  引数として渡されたデータ内のゼロ-クロスポイントの数を返します。

`findfactor`( | fragment, reference)

  `rms(add(fragment, mul(reference, -F)))`が最小となるようなFを返します。つまり、referenceに掛けるとfragmentにできるだけ一致するような値を返します。 fragmentとreferenceは両方とも2バイトのサンプルでなければなりません。

  このルーチンの実行に要する時間は`len(fragment)`に比例します。

`findfit`( | fragment, reference)

  referenceがfragment（より長いデータ）の一部に一致するか確かめます。 これは（概念的には）fragmentから断片を切り出して、`findfactor()`を使って一番ふさわしいものを計算し、結果を最小にすることで実現しています。 fragmentとreferenceは両方とも2バイトのサンプルでなければなりません。 `(offset, factor)`のタプルを返します。offsetは最適な一致箇所が始まるfragmentのオフセット値（整数）で、factorは`findfactor()`で返される数値（浮動小数点数）です。

`findmax`( | fragment, length)

  fragmentを長さlengthのサンプル（バイトではありません！）にスライスして、最大レベルをもつサンプルを探します。つまり、`rms(fragment[i*2:(i+length)*2])`が最大となるようなiを返します。 データは2バイトのサンプルでなければなりません。

  このルーチンの実行に要する時間は`len(fragment)`に比例します。

`getsample`( | fragment, width, index)

  データからindexのサンプルの値を返します。

`lin2lin`( | fragment, width, newwidth)

  サンプルサイズを1、2、4バイトフォーマットの間で変換します。

`lin2adpcm`( | fragment, width, state)

  サンプルを4ビットのIntel/DVI ADPCMフォーマットにエンコードします。 ADPCMフォーマットは、（さまざまな）あるステップで区切られたサンプルと次のサンプルとの差である4ビットの数値を利用したコード化スキームです。 Intel/DVI ADPCMアルゴリズムは国際MIDI協会に採用されているので、標準に なると言っていいでしょう。

  stateはエンコードの情報を含んだタプルです。 `(adpcmfrag, newstate)`のタプルを返します。newstateは次に`lin2adpcm()`を呼び出す時に渡さなければなりません。 最初の呼び出しではstateとして`None`を渡します。 adpcmfragはADPCMでコード化された、バイト当たり2つの4ビット値です。

`lin2adpcm3`( | fragment, width, state)

  これはサンプル当たり3ビットのみを使う新しいADPCMフォーマットです。 これはIntel/DVI ADPCMフォーマットと互換性がなく、出力は提供されていません（作者の怠慢によるものです）。 使うとがっかりします。

`lin2ulaw`( | fragment, width)

  オーディオデータのサンプルをu-LAWフォーマットにエンコードし、Python文字列として返します。 u-LAWはオーディオエンコードフォーマットで、8ビットのみのサンプルで約14ビットのダイナミックレンジが得られます。 他でも使われていますが、Sunのオーディオハードウェアで使われています。

`minmax`( | fragment, width)

  サウンドデータ内の全サンプルの最小値と最大値からなるタプルを返します。

`max`( | fragment, width)

  データ内の全サンプルの絶対値の最大値を返します。

`maxpp`( | fragment, width)

  サウンドデータの最大振幅の最大値を返します。

`mul`( | fragment, width, factor)

  元のデータ内の全サンプルに浮動小数点数factorを掛けたデータを返します。 オーバーフローした分は無視します。

`ratecv`( | fragment, width, nchannels, inrate, outrate, state[, weightA[, weightB]])

  入力したデータのフレームレートを変換します。

  stateは変換の情報を含むタプルです。 `(newfragment, newstate)`を返します。 newstateは次に`ratecv()`を呼び出す時に渡さなければなりません。

  最初の呼び出しではstateとして`None`を渡します。

  引数weightAとweightBはシンプルなデジタルフィルターのためのパラメータで、デフォルトではそれぞれ`1`、`0`です。

`reverse`( | fragment, width)

  データ内のサンプルの順序を逆転したデータを返します。

`rms`( | fragment, width)

  データの標準偏差を返します。つまり、

  これはオーディオ信号の大きさを示します。

`tomono`( | fragment, width, lfactor, rfactor)

  ステレオデータをモノラルデータに変換します。 2つのチャンネルを足してモノラルの信号にする前に、左チャンネルはlfactor倍、右チャンネルはrfactor倍されます。

`tostereo`( | fragment, width, lfactor, rfactor)

  モノラルのデータからステレオのデータを作ります。 左チャンネルのサンプルはモノラルのサンプルをlfactor倍、右チャンネルはrfactor倍して、ステレオデータのサンプルを算出します。

`ulaw2lin`( | fragment, width)

  u-LAWフォーマットのサウンドデータをlinearフォーマットのサウンドデータにエンコードします。 u-LAWフォーマットは常に8ビットのサンプルを使うので、widthは出力データのサンプルサイズを示します。

`mul()`や`max()`はモノラルとステレオの区別をつけずに、全サンプルを等しく扱います。 これが問題なら、初めにステレオデータを2つのモノラルデータに分割して、あとで結合するといいでしょう。 どうしたらいいか、例を挙げます。

    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)

もしネットワークパケットを構築してADPCMフォーマットを使って、プロトコールの説明なしにしたいなら（つまりパケットの損失を我慢できるなら）、データだけでなくstateも送信するべきです。 注意してほしいのは、（コーダーによって返される）最後のstateでなく、initialのstate（`lin2adpcm()`に渡す引数）をコーダーに渡すことです。 もしバイナリでstateを保存するのに`struct.struct()`を使いたいなら、最初の要素（最初の値）を16ビットで、2番目の要素（前のサンプルとの差）を8ビットでコード化します。

ここのADPCMコーダーは他のADPCMコーダーに対しては試していません。 それぞれの標準のものとの間で操作できない場合は、私が仕様を誤解していることも十分あり得ます。

`find*()`ルーチンは、一見、滑稽に見えるかもしれません。 これらは最初、エコーを取り消すためのものでした。 これを合理的に速く実行するには、出力サンプルのレベルの一番大きい部分を取り出し、その場所の入力サンプル内での位置をみつけ、入力サンプルから出力サンプル全体を減算します：

    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)