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

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

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

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

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

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

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

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

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

add( fragment1, fragment2, width)
パラメータとして渡された2つのサンプルの和のデータを返します。

widthはサンプルサイズのバイト数で、124のうちのどれかです。 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にできるだけ一致するような値を返します。 fragmentreferenceは両方とも2バイトのサンプルでなければなりません。

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

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

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を渡します。

引数weightAweightBはシンプルなデジタルフィルターのためのパラメータで、デフォルトではそれぞれ10です。

reverse( fragment, width)
データ内のサンプルの順序を逆転したデータを返します。

rms( fragment, width)
データの標準偏差を返します。つまり、

\begin{displaymath}
\catcode\lq _=8
\sqrt{\frac{\sum{{S_{i}}^{2}}}{n}}
\end{displaymath}

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

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)
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。