\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... このモジュールは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()}の説明を参照して下さい。 \var{width}で指定したサイズで\code{(\var{sample}, \var{newstate})}のタプルを返します。 \end{funcdesc} \begin{funcdesc}{adpcm32lin}{adpcmfragment, width, state} 3ビットの新しいADPCMフォーマットのデータをデコードします。 詳しくは\function{lin2adpcm3()}を参照して下さい。 \end{funcdesc} \begin{funcdesc}{avg}{fragment, width} データ内の全サンプルの平均値を返します。 \end{funcdesc} \begin{funcdesc}{avgpp}{fragment, width} データ内の全サンプルの最大振幅の平均値を返します。 フィルタリングされていないなら、このルーチンが役立つかどうか疑問です。 \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}から断片を切り出して、\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}{lin2lin}{fragment, width, newwidth} サンプルサイズを1、2、4バイトフォーマットの間で変換します。 \end{funcdesc} \begin{funcdesc}{lin2adpcm}{fragment, width, state} サンプルを4ビットのIntel/DVI ADPCMフォーマットにエンコードします。 ADPCMフォーマットは、(さまざまな)あるステップで区切られたサンプルと次のサンプルとの差である4ビットの数値を利用したコード化スキームです。 Intel/DVI ADPCMアルゴリズムは国際MIDI協会に採用されているので、標準に なると言っていいでしょう。 \var{state}はエンコードの情報を含んだタプルです。 \code{(\var{adpcmfrag}, \var{newstate})}のタプルを返します。\var{newstate}は次に\function{lin2adpcm()}を呼び出す時に渡さなければなりません。 最初の呼び出しでは\var{state}として\code{None}を渡します。 \var{adpcmfrag}はADPCMでコード化された、バイト当たり2つの4ビット値です。 \end{funcdesc} \begin{funcdesc}{lin2adpcm3}{fragment, width, state} これはサンプル当たり3ビットのみを使う新しいADPCMフォーマットです。 これはIntel/DVI ADPCMフォーマットと互換性がなく、出力は提供されていません(作者の怠慢によるものです)。 使うとがっかりします。 \end{funcdesc} \begin{funcdesc}{lin2ulaw}{fragment, width} オーディオデータのサンプルをu-LAWフォーマットにエンコードし、Python文字列として返します。 u-LAWはオーディオエンコードフォーマットで、8ビットのみのサンプルで約14ビットのダイナミックレンジが得られます。 他でも使われていますが、Sunのオーディオハードウェアで使われています。 \end{funcdesc} \begin{funcdesc}{minmax}{fragment, width} サウンドデータ内の全サンプルの最小値と最大値からなるタプルを返します。 \end{funcdesc} \begin{funcdesc}{max}{fragment, width} データ内の全サンプルの\emph{絶対値}の最大値を返します。 \end{funcdesc} \begin{funcdesc}{maxpp}{fragment, width} サウンドデータの最大振幅の最大値を返します。 \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})}を返します。 \var{newstate}は次に\function{ratecv()}を呼び出す時に渡さなければなりません。 最初の呼び出しでは\var{state}として\code{None}を渡します。 引数\var{weightA}と\var{weightB}はシンプルなデジタルフィルターのためのパラメータで、デフォルトではそれぞれ\code{1}、\code{0}です。 \end{funcdesc} \begin{funcdesc}{reverse}{fragment, width} データ内のサンプルの順序を逆転したデータを返します。 \end{funcdesc} \begin{funcdesc}{rms}{fragment, width} データの標準偏差を返します。つまり、 \begin{displaymath} \catcode`_=8 \sqrt{\frac{\sum{{S_{i}}^{2}}}{n}} \end{displaymath} これはオーディオ信号の大きさを示します。 \end{funcdesc} \begin{funcdesc}{tomono}{fragment, width, lfactor, rfactor} ステレオデータをモノラルデータに変換します。 2つのチャンネルを足してモノラルの信号にする前に、左チャンネルは\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フォーマットのサウンドデータをlinearフォーマットのサウンドデータにエンコードします。 u-LAWフォーマットは常に8ビットのサンプルを使うので、\var{width}は出力データのサンプルサイズを示します。 \end{funcdesc} \function{mul()}や\function{max()}はモノラルとステレオの区別をつけずに、全サンプルを等しく扱います。 これが問題なら、初めにステレオデータを2つのモノラルデータに分割して、あとで結合するといいでしょう。 どうしたらいいか、例を挙げます。 \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フォーマットを使って、プロトコールの説明なしにしたいなら(つまりパケットの損失を我慢できるなら)、データだけでなくstateも送信するべきです。 注意してほしいのは、(コーダーによって返される)最後のstateでなく、\var{initial}のstate(\function{lin2adpcm()}に渡す引数)をコーダーに渡すことです。 もしバイナリでstateを保存するのに\function{struct.struct()}を使いたいなら、最初の要素(最初の値)を16ビットで、2番目の要素(前のサンプルとの差)を8ビットでコード化します。 ここのADPCMコーダーは他のADPCMコーダーに対しては試していません。 それぞれの標準のものとの間で操作できない場合は、私が仕様を誤解していることも十分あり得ます。 \function{find*()}ルーチンは、一見、滑稽に見えるかもしれません。 これらは最初、エコーを取り消すためのものでした。 これを合理的に速く実行するには、出力サンプルのレベルの一番大きい部分を取り出し、その場所の入力サンプル内での位置をみつけ、入力サンプルから出力サンプル全体を減算します: \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}