2012年3月23日金曜日

閉村観光


これは、以前に紹介したPythonのサウンドライブラリPyoで、どのように自作クラス(ヴォコーダー)を作るかを説明した文章の翻訳です。

>>>以下本文

原文 http://code.google.com/p/pyo/wiki/createYourOwnAudioObject

自作オーディオ・オブジェクト

これは、小さいチュートリアル。サウンド処理のために、君自身のオブジェクトのつくりかた。

序文

この例では、ヴォコーダーを製作していくことにする。とてもシンプルなクラスから始めて、より洗練されたクラスを作るために、徐々に機能を加えていく。できあがったクラスはホンモノのpyoオブジェクトのように振る舞うだろう。

なにはともあれ、メインのスクリプトが読み込む、クラスの置き場所に"vocoder_lib.py"というファイルをつくろう。

ファイル"vocoder_lib.py"と"vocoder_main.py"はpyoのソースコードのexampleフォルダの中にある。

シンプルなヴォコーダー

自作クラスに、妙な振る舞いをさせないように覚えておくべきことがひとつある。すべてのpyoオブジェクトは、オーディオサンプルの計算に要する時間まで、生存させておかなければならない。initメソットの終了時に自作クラスが破壊されるのを防ぐために、常にpyoオブジェクトに接頭辞"self"をつけることをこころがけて。

自作クラス(最低でもPyo)にある、君が必要とするモジュールすべてが読み込まれることで開始する。

 import math from pyo import * 

そして、ここにクラスSimpleVocoderがある。

 class SimpleVocoder:     def __init__(self, in1, in2, num=32, base=50, spread=1.5, q=5):         self._in1 = in1         self._in2 = in2         self._num = num         self._base = base         self._spread = spread         self._q = q         self._freqs = Sig([self._base * math.pow(i+1, self._spread) for i in range(self._num)])         self._clipped_freqs = Clip(self._freqs, 20, 200000)          self._src = Biquadx(self._in1, freq=self._clipped_freqs, q=self._q, type=2, stages=4)         self.envelope = Follower(self._src, freq=5, mul=self._q*30)         self._exc = Biquadx(self._in2, freq=self._clipped_freqs, q=self._q, type=2, stages=4, mul=self._envelope) 

おわかりのように、非常にシンプルなクラスですが、準備ができた。

ここで、なにが起こったのか確認してみよう。はじめに、あとで使うために、入力で与えられたpyoオブジェクトの参照を保持する。そのとき、フィルタの周波数を計算し、リストをシンプルなSig()オブジェクトに渡す。そこでは、フィルタ周波数をClip()されたオーディオ信号を浮動小数点に変更するために、Sig()オブジェクトを利用する(フィルタはナイキスト周波数によって一定ではない)。いったんこれがされると、最初の信号の帯域ごとに、エンベロープフォローワーを適用し、そして二番目の信号で、このエンベロープをフィルタの振幅として使うことによって、ヴォコーダーを作れる。

これで、われわれのメインのスクリプトで、このクラスを利用できる(vocoder.pyファイルをメインのスクリプトと同じフォルダに置くことを忘れないで)。

 from pyo import * from vocoder_lib import SimpleVocoder s = Server(sr=44100, nchnls=2, buffersize=1024, duplex=0).boot() a = SFPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=3).play() b = Noise() voc = SimpleVocoder(in1=a, in2=2, num=32, base=50, spread=1.2, q=5) s.gui(locals()) 

これでいいでしょう、ただ扱いづらい、だって実行中にいろいろ変更するのがとっても面倒。

Vocoderをコントロールするためにメソッドを加えてみよう。


ガス価格はカナダで何ですか
     def setBase(self, x):         self._base = x         self._freq.value = [self._base * math.pow(i+1, self._spread) for i in range(self._num)]          def setSpread(self, x):         self._spread = x         self._freqs.value = [self._base * math.pow(i+1, self._spread) for i in range(self._num)]      def setQ(self, x):         self._q = x         self._envelope.mul = self._q * 30         self._src.q = self._exc.q = self._q 

これで、再生中には、インタプリターで以下のように呼び出すことができる。

 voc.setBase(60) voc.setSpread(1.5) voc.setQ(10) 

また、自作クラスに以下の行を加えることで、タイプ量を減らすのに属性を利用することもできる。

     @property     def base(self): return self._base     @base.setter     def base(self, x): self.setBase(x)      @property     def spread(self): return self._spread     @spread.setter     def spread(self, x): self.setSpread(x)      @property     def q(self): return self._q     @q.setter     def q(self, x): self.setQ(x) 

SimpleVocoderの親クラスとして"object"をあたえること忘れないで。

 class SimpleVocoder(object): 

属性を利用することで、このように呼び出しを置き換えることができる。

 voc.base = 60 voc.spread = 1.5 voc.q = 10 

以上です!。いま、われわれのプログラムで使用するヴォコーダの準備が整いました。

ヴォコーダ(さらなるpyo機能を加えて)

SimpleVocoderが、プロセスチェーンの最後の要素のときには役立つのだが。ふつうのpyoオブジェクトのように使えない。例えば、もしリバーブオブジェクトのサウンドを渡したいなら、クラスそれ自身にリバーブユニットをくわえて修正しないといけない。ライブラリにある、どんなオブジェクトでも他のオブジェクトに渡せるならとても便利だ。少しの工夫で、すべてのpyoの機能をもったクラスを作れる。今からこのようなことをしていく。

考慮する事項

・親のクラスはPyoObjectでなければならない

・PyoObjectはべつのPyoObjectを受けるときに、"self.base_objs"と名付けられたオブジェクトのリストを探す。

・"mul"や"add"の引数を加える(self._base_objsのオブジェクトを変更する)

・すべてのPyoObjectは"リストの展開"をサポートする。

・入力時のサウンドをもったPyoObjectは新旧のソースのクロスフェードをサポートする。

・おそらく.play()、.out()、そして.stop()メソッドを上書きしたくなるだろう。

・すべての関数ために、パラメータを修正する属性がある。

・__dir__メソッドは、使用可能な属性のリストを文字列のようにして返す。

・パラメータをコントロールするためのポップアップGUIを.ctrl()メソッドで定義できる。

クラスの宣言

PyoObjectを親クラスとするヴォコーダと呼ばれる新しいクラスを作っていく。もうひとつ習慣づけたほうが良いのは、クラスを作る際に __doc__ 文字列を置くことだ。そうすることで、標準のPythonのhelp()関数で、君以外にオブジェクトのドキュメントを検索できるようにする。


金属はpewtarを構成するもの
 class Vocoder(PyoObject):     """     ヴォコーダのエフェクト      ヴォコーダは、分析とシンセシスのシステムだ。エンコードの際に、入力はマルチ・バンドフィルタを通過させられ、バンドごとにエンベロープフィルタを通過させ、そしてエンベロープフォロワーから作ったコントロール信号は、デコーダとして機能する。デコーダは、これら(音量)のコントロール信号を(再)シンセシスに応じるフィルタに使用する。      親クラス: PyoObject      パラメータ      in1: PyoObject       スペクトルエンベロープを生じさせる音源     in2: PyoObject       フィルタバンクを刺激する音源     base: 浮動小数点またはPyoObject、どちらでも良い       基本周波数は、ノッチフィルタの周波数を計算するのに使う       標準は50     spread: 浮動小数点とPyoObject       ノッチフィルタの周波数の拡散。標準は1.5     q: 浮動小数点とPyoObject       フィルタのQ(バンド帯域幅の逆数)。標準は5     num: 整数、オプション       ヴォコーダのバンド(ノッチフィルタ)の数、初期化時のみ利用可能。標準は20      メソッド:      setIn1(x): "in1"属性をかえる     setIn2(x): "in2"属性をかえる     setBase(x): "base"属性をかえる     setSpread(x): "spread"属性をかえる     serQ(x): "q"属性をかえる      属性      in1: PyoObject。スペクトルペンべロープを生じさせる音源     in2: PyoObject。フィルタバンクを刺激する音源     base: 浮動小数点とPyoObject、基本周波数     spread: 浮動小数点またはPyoObject、ノッチフィルタの周波数を拡散     q: 浮動小数点とPyoObject、フィルタのQ          こちらも参照して:BandSplit、Phaser      例:      >>>s = Server().boot()     >>>s.start()     >>>z = SFPlayer(SNDS_PATH + "/transparent.aif", loop=True)     >>>b=Noise()     >>>lfo = Sine(freq=.05, mul=50, add=100)     >>>voc = Vocoder(in1=a, in2=b, num=20, base=lfo, sprea=[1,2,1.22]).out()     """ 

__init__ メソッド

これが、pyoの一般的なふるまいを注意深く見ていかなければならないところだ。これだけは覚えておかなければいけない、PyoObjectが別のPyoObjectを入力として受け入れるとき、self._base_objsという属性をさがすこと。この属性はオブジェクトの基本クラスのリストで、オブジェクト(内部では、Sine_baseオブジェクトして利用されるSineオブジェクト)のオーディオ出力信号と考えられる。getBaseObject()メソッドは、あたえられたPyoObjecttのために基本クラスのリストを返す。われわれは、処理の出力信号を生成するオブジェクトでgetBaseObject()を呼ぶだろう。

またオブジェクトの定義に2つの属性を加えなければならない。そう"mul"と"add"だ。属性"self._mul"と"self._add"は、親クラスによってハンドルされ、自動的に"self._base_objs"のオブジェクトに当てられる。

最終的に、"リストの展開"という機能を考えなければならない、引数にあたえられたリストに、オブジェクトの複数のインスタンスを作成させることができ、複数のオーディオストリームを管理する。2つの関数が、これを成し遂げるのに役立つ。

・convertArgsToLists(*args):リストに変えられた引数とリストの最大サイズを返す

・wrap(list, i):len(list)でラップアラウンドした"list"のポジション"i"の値を返す

コードはこうなる。


我々は超えてどのように行くのですか?
 def __init__(self, in1, in2, base=50, spread=1.5, q=5, num=20, mul=1, add=0):     #すべての未処理の引数の参照を保持する     self._in1 = in1     self._in2 = in2     self._base = base     self._spread = spread     self._q = q     self._num = num     self._mul = mul     self._add = add      #ノッチフィルタの周波数のリスト     self._patrials = [i+1 for i in range(self._num)]      #サウンド入力のためにInputFaderを使って、音源を交換するときにクロスフェードさせる     self._in1_fader = InputFader(in1)     self._in2_fader = InputFader(in2)      #"リストの展開"で、すべての引数をリストに変換する     #convertArgToListは、引数の内の変数をリストのように、リストの最大サイズを加えて返す     in1_fader, in2_fader, base, spread, q, mul, add, lmax = convertArgToLists(self._in1_fader, self._in2_fader, base, spread, q, mul, add)      #Initのリストは、生成されたオブジェクトを絶えず見失わないようにする     self._pows = []     self._bases = []     self._freqs = []     self._srcs = []     self._amps = []     self._excs = []     self._outs = []      #self._base_objsは外側から見れるオーディオ出力     #.play()、.out()、.stop()、そして.mix()メソッドはこのリスト上でふるまう。     #"mul"や"add"属性は、またリストのオブジェクトに適用される。     self._base_objs = []      #ループの各サイクルは、サウンドのモノラルのストリームをつくる。     for i in range(lmax):         self._pows.append(Pow(self._partials, wrap(spread,i)))         self._bases.append(Sig(wrap(base,i)))         self._freqs.append(Clip(self._pows[-1] * self._bases[-1], 20, 20000))         self._srcs.append(Biquadx(wrap(in1_fader,i), freq=self._freqs[-1], q=wrap(q,i), type=2, stages=2))         self._amps.append(Follower(self._srcs[-1], freq=5, mul=wrap(q,i)*30))         self._excs.append(Biquadx(wrap(in2_fader,i), freq=self._freqs[-1], q=wrap(q,i), type=2, stages=2, mul=self._amps[-1]))         #ここで、ヴォコーダの"num"個の帯域によって作られた、モノラルのすべてのサブストリームをミックスする         self._outs.append(Mix(input=self._excs[-1], voices=1, mul=wrap(mul,i), add=wrap(add,i)))         # getBaseObjects()メソッドは、Object_Baseのリストを返し、self._base_objsのリストを要求した。         self._base_objs.extend(self._outs[-1].getBaseObjects()) 

メソッドと属性の設定

さあ、すべての制御可能なパラメータのために、メソッドと属性を加えてゆこう。気をつけなければいけないのは、入力ソース(setIn1とsetIn2)を交換するのに、InputFaderオブジェクトのsetInput()メソッドを使うこと。このオブジェクトは、クロスフェード時間の引数を伴って、古いソースと新しいソースの間をクロスフェードを実装する。


     def setIn1(self, x, fadetime=0.05):         """         "in1"属性を置き換える          パラメータ:          x : PyoObject             処理するための新しい信号         fadetime : float, オプション             古い入力から新しい入力の間をクロスフェードする時間。標準は0.05          """         self._in1 = x         self._in1_fader.setInput(x, fadetime)      def setIn2(self, x, fadetime=0.05):         """         "in2"属性を置き換える          パラメータ:          x : PyoObject             処理するための新しい信号         fadetime : float, オプション             古い入力から新しい入力の間をクロスフェードする時間。標準は0.05          """         self._in2 = x         self._in2_fader.setInput(x, fadetime)          def setBase(self, x):         """         "base"属性を置き換える          パラメータ:          x : float or PyoObject             新しい`base`属性          """         self._base = x         x, lmax = convertArgsToLists(x)         [obj.setValue(wrap(x,i)) for i, obj in enumerate(self._bases)]      def setSpread(self, x):         """         "spread"属性を置き換える          Parameters:          x : float or PyoObject             新しい"spread"属性          """         self._spread = x         x, lmax = convertArgsToLists(x)         [obj.setExponent(wrap(x,i)) for i, obj in enumerate(self._pows)]      def setQ(self, x):         """         "q"属性を置き換える          Parameters:          x : float or PyoObject             新しい"q"属性          """         self._q = x         x, lmax = convertArgsToLists(x)         [obj.setMul(wrap(x,i)*30) for i, obj in enumerate(self._amps)]         [obj.setQ(wrap(x,i)) for i, obj in enumerate(self._srcs)]         [obj.setQ(wrap(x,i)) for i, obj in enumerate(self._excs)]      @property     def in1(self): return self._in1     @in1.setter     def in1(self, x): self.setIn1(x)      @property     def in2(self): return self._in2     @in2.setter     def in2(self, x): self.setIn2(x)      @property     def base(self): return self._base     @base.setter     def base(self, x): self.setBase(x)      @property     def spread(self): return self._spread     @spread.setter     def spread(self, x): self.setSpread(x)      @property     def q(self): return self._q     @q.setter     def q(self, x): self.setQ(x) 

__dir__ メソッド

オブジェクトのすべての制御可能な属性のリストを返すには、__dir__をオーバーライドすることになる。ユーザーはdir(obj)を呼び出すことで、この値を取得できる。

     def __dir__(self):         return ["in1", "in2", "base", "spread", "q", "mul", "add"] 

ctrl() メソッド

PyoObjectのctrl()メソッドは、オブジェクトのパラメータをコントロールするために、ポップアップGUIを使用する。スライダーの初期化は、SLMapオブジェクトのリストで行う。そこで、スライダーの範囲、スケールの種類、スライダーに連結された属性の名前、初期値を設定できる。ユーザーが書き忘れた場合に備え、標準で"map_list"を定義している。

     def ctrl(self, map_list=None, title=None, wxnoserver=False):         # PyoObjectに何も渡されなかった場合、オブジェクトに標準のmap_listを定義する         # map_listは、コントロールウィンドウで利用可能な属性ごとに、         # 定義されたSLMapオブジェクトのリスト         self._map_list = [SLMap(20., 250., "lin", "base", self._base),                           SLMap(0.5, 2., "lin", "spread", self._spread),                           SLMap(1., 50., "log", "q", self._q),                           SLMapMul(self._mul)]         PyoObject.ctrl(self, map_list, title, wxnoserver) 

.play()、.stop()、 そして.output()メソッドをオーバーライド

最後に、カレントオブジェクトにあるような、すべての内部PyoObjectsが結果的に、self._base_objにリストしたオブジェクトだけを管理させるように.play()、.stop()、そして.out()メソッドを上書きしたほうがいいかもしれない。引数の意味を理解したいなら、マニュアルにあるPyoObjectのこれらのメソッドの定義を参照して。


 def play(self, dur=0, delay=0):     dur, delay, lmax = convertArgsToLists(dur, delay)     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._pows)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._bases)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._freqs)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._srcs)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._amps)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._excs)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._outs)]     self._base_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]     return self  def stop(self):     [obj.stop() for obj in self._pows]     [obj.stop() for obj in self._bases]     [obj.stop() for obj in self._freqs]     [obj.stop() for obj in self._srcs]     [obj.stop() for obj in self._amps]     [obj.stop() for obj in self._excs]     [obj.stop() for obj in self._outs]     [obj.stop() for obj in self._base_objs]     return self  def out(self, chnl=0, inc=1, dur=0, delay=0):     dur, delay, lmax = convertArgsToLists(dur, delay)     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._pows)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._bases)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._freqs)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._srcs)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._amps)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._excs)]     [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._outs)]     if type(chnl) == ListType:         self._base_objs = [obj.out(wrap(chnl,i), wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]     else:         if chnl < 0:                 self._base_objs = [obj.out(i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(random.sample(self._base_objs, len(self._base_objs)))]         else:             self._base_objs = [obj.out(chnl+i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]     return self 

以上で完成です。サウンド処理のためホンモノのオブジェクトができました。もちろんピュアpythonで書いたオブジェクトでは、CPU使用率に若干のスパイクがかかってしまうかもしれない、だから次のステップではC言語で書くことにする。Cでのpyoオブジェクトの作り方チュートリアルはもうじき公開するよ。



These are our most popular posts:

電子レンジ - Wikipedia

電磁波の周波数は、2.45GHzでISMバンドのひとつであり、周波数を共用している無線 LANや直下の2.4GHz帯アマチュア無線などは、電子 ... 日本では調理完了を知らせる 合図音として、初期型では発条式タイマーと打ち子式ベルの組み合わせによる「チーン」 という音を多数の製品が ..... 食品用ラップフィルムでも成分が溶出する製品も存在する ので、電子レンジ対応品を選ぶ必要性がある。 ... 電子レンジ調理は通常の加熱調理 などとは異なり、特定部分だけが加熱されたり、食材の内部から加熱されるような動作を する。 read more

IEEE 802.11無線LANの PHYレイヤ(RF)の動作と測定

オプション. 注記:差分=差分変調エンコーディング. 802.11gにはミックスドCCK-OFDM のオプションあり. 差分 差分. 周波数帯域 .... これはラップトップ・コンピュー. タに直接 ... 定のバーストに対してどの経路が用. いられる ..... イスが動作しない原因となる場合が ... read more

信和SC905GV-Ⅱ 1280SFX はじめてのGV SFX 本書はSFXを始めて ...

3、5分、1分の通話制限はタイマーカットの動作にかかわらずありません。 ... 4、リセット 、モニター、レディ、送信中のどの状態から出も、メモリー、群番号の打ち変えが出来 ます。 ..... なお、くれぐれも、悪用しないでください。 ..... マイクの"PTT"でスタート、 ストップ、"REMOTE"でラップ、クリアです。 .... 秘話装置には、音声を、その周波数を 反転させて、内容が判別出来ないようにするものが良く使用されていましたが、最近に なってデジタル ... read more

Voice over Wireless LAN 4.1 デザイン ガイド Cisco Validated Design

一般に、5GHz 帯はノイズや干渉が少ないので、搬送周波数を高くすることによって キャパシティを増大できます。 ... 前の項目で説明したように、米国の 2.4GHz 帯では、 オーバーラップしないチャネルは 3 つだけです。 .... 一般に、(KeepAlive タイムアウトを 必要とする)カスタム アプリケーションが影響を受ける可能性が高く、タイマーを調整する 必要がないことを新しい環境で検証する必要 .... IEEE 802.11a は、6 ~ 54Mbps の データ レートで 5 GHz UNII 周波数帯で動作する、物理レイヤ(OSI モデル)の要件を 定義します。 read more

Related Posts



0 コメント:

コメントを投稿