14.1 audioop -- 生の音声データを操作する

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

このモジュールは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() の説明を 参照して下さい。(sample, newstate) からなる タプルを返し、サンプルはwidth に指定した幅になります。

adpcm32lin( adpcmfragment, width, state)
3 ビット符号を使う別の ADPCM で符号化されているデータをデコードします。 詳しくはlin2adpcm3()を参照して下さい。

avg( fragment, width)
データ中の全サンプルの平均値を返します。

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

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)
reference を可能な限り fragment に一致させようとします (fragmentreference より長くなければなりません)。 この処理は (概念的には) 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アルゴリズムは IMA (国際MIDI協会) に採用されているので、おそらく標準になるはずです。

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

lin2adpcm3( fragment, width, state)
サンプル当たり 3 ビットだけしか使わない別の ADPCM 符号化方式の エンコーダです。 Intel/DVI ADPCM 形式との互換性はなく、 (作者の怠慢から) 出力はパックされていません。このエンコーダの 使用は推奨しません。

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

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

max( fragment, width)
音声データ全サンプルの絶対値 の最大値を返します。

maxpp( fragment, width)
音声データの最大 peak-peak 振幅を返します。

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

ratecv( fragment, width, nchannels, inrate, outrate, state[, weightA[, weightB]])
入力したデータのフレームレートを変換します。

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

引数weightAweightB は単純なデジタルフィルタの パラメタで、デフォルト値はそれぞれ10です。

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

rms( fragment, width)
データの自乗平均根 (root-mean-square) 、すなわち


を返します。これはオーディオ信号の強度 (power) を測る一つの目安です。

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

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

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

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

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

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

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

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