PySndObjを使ってPythonプログラミング

日本語訳(Junya Miura) Last Update-26 Oct 2006

PySndObjって何?

PySndObjとはSndObjというC++のコードを包むpythonモジュールで、Pythonでスクリプトするのにとても役立ちます。素早いアプリケーション開発、アプリケーションのプロトタイピング、一般的な"on-the fly"な音響合成処理を目的としたライブラリの洗練したインターフェイスを構築できよう考慮されている。

PySndObjを始めるには、(Linuxなら拡張子.so、OSXなら.dylib、Windowsなら.dll)ダイナミック・モジュールの_sndobjと(pythonに結び付けられた)sndobj.pyを(Pythonのドキュメンテーションを調べて)正しい場所に置くことから、そしてimportコマンドを打つ:

import sndobj

あなたのプラットホームで活用できるすべてのSndObjライブラリに加え、配列をサポートする拡張ユーティリティのクラスにアクセスできる。

PythonのSndObjクラスとオブジェクト

PythonのSndObjクラスはC++のに比べて非常によく似ているように思われる。おもなちがいはPythonのすべてのオブジェクトは動的に確保されるとこ、C++のポインタはオブジェクトと同等である。ライブラリはオブジェクトと接続するのにポインタを使っていたが(プログラミング・コンセプトを見てみて)、PythonでSndObjを使うのははっきりしてわかりやすい。オブジェクトと接続するのにとてもシンプル。それでは、正弦の波形テーブルを作ってオシレータとつなげてみましょう:

tab = sndobj.HarmTable()
osc = sndobj.Oscili(tab, 440, 16000)

ここでは変数がオブジェクトのポインタを保持し、この場合では'tab'はoscに直接渡すことができ、特段面倒な状態は生じない。 SndObjとSndIOをつなげるために同様な作業で、リアルタイム出力のオブジェクトをセットアップしていたのなら、それをオシレータとつなげる事ができる:

outp = sndobj.SndRTIO(1)
outp.SetOutput(1,osc)

これは我々が期待しているようなSndObj同士の間でも使えて、そうこう言ってる間に、モジュレータとオシレータをつなげられるんだよ:

mod = sndobj.Oscili(tab, 2, 44)
osc.SetFreq(440, mod)

SndThreadを使う

SndObjたちが音を産み出すシンプルな方法は合成をコントロールするためにSndThreadオブジェクトを使うことだ。我々はこのようにセットすることから始める:

thread = SndThread()
thread.AddObj(mod)
thread.AddObj(osc)
thread.AddObj(outp, sndobj.SNDIO_OUT)

これで音の出力を得るために処理をオン:

thread.ProcOn()

そして再生され、オフにする。

thread.ProcOff()

配列をサポートする

Cの配列を使う可能性のあるプログラミングを楽にするために、いくつかのユーティリティ・クラスが加えられ、intとfloatそしてdoubleの配列はそれぞれintArrayとfloatArrayそしてdoubleArrayと名付けられている:これらのクラスは以下の様に扱われる。

# 2つの要素の配列をつくる
f = floatArray(2)
# 配列のオブジェクトはCのようなインデックスで処理できる
f[0] = 2.5

それに加え、特別な配列の型も活用でき、それはsndobjArrayで、SndObjたち(C++でのSndObjのポインタ)を保持する。この型のオブジェクトは上の配列と同じように使用される:

objs = sndobj.sndobjArray(2)
objs[0] = mod
objs[1] = osc

しかしながら、SndObjのポインタ配列として使用するには、キャストする必要がある。望みどおりこのクラスは 申し分ない便利なメソッドを持っている:

objp = objs.cast()

SndObjの配列を入力に、SndThreadのような、オブジェクトで使用される:

thread = sndobj.SndThread(2, objp, outp)

このケースでは2つのSndObj(それは上記の例と同様である)を持ったスレッドをセットアップしている。SndObjの配列を除いた他のオブジェクトは例えばSndIOから派生したオブジェクトとミキサーなどのSndObjになる。しかし思い出して、SndObjの配列はsndobjArrayではないということを、だがsndobjArray.cast()を使うことでそうすることができる。

シンプルな例

2つのシンプルな例は音響合成処理のために提供された。

櫛形フィルタを使ったシンプルなエコー

from sndobj import *
import time
import sys

# OSXではSndCoreAudioクラスを使う
if sys.platform == 'darwin':
    outp = SndCoreAudio()
    inp = outp
# さもなくばSndRTIOを使う
else:
    inp = SndRTIO(2, SND_INPUT)
    outp = SndRTIO(2, SND_OUTPUT)

# SndObj セットアップ
ins = SndIn(inp,1)
comb = Comb(0.5, 0.5, ins)

# 出力たち
outp.SetOutput(1, ins)
outp.SetOutput(2, comb)

# スレッド
thread = SndThread()
thread.AddObj(inp, SNDIO_IN)
thread.AddObj(outp, SNDIO_OUT)
thread.AddObj(ins)
thread.AddObj(comb)

# 処理を始める
thread.ProcOn()
time.sleep(30)
thread.ProcOff()

GUIを持ったオシレータ(wxPythonを使って)

from sndobj import *
from wxPython.wx import *
import traceback
import time

class ControlPanel(wxPanel):
    # Override the base class constructor.
    def __init__(self, parent):
        wxPanel.__init__(self, parent, -1)
        self.ID_BUTTON1 = 10
        self.button1 = wxButton(self, self.ID_BUTTON1, "On/Off", (20, 20))
        # ボタンとイベントハンドラを結びつける
        EVT_BUTTON(self, self.ID_BUTTON1, self.OnClickButton1)
        # 音符のピッチの変化のためのスライダを作る
        self.ID_SLIDER1 = 20
        self.slider1 = wxSlider(self, self.ID_SLIDER1, 300, 200, 400, (20, 50), (200,50), ¥
				    wxSL_HORIZONTAL | wxSL_LABELS)
        self.slider1.SetTickFreq(5, 1)
        # スライダをイベントハンドラに結びつける
        EVT_SLIDER(self, self.ID_SLIDER1, self.OnSlider1Move)
        EVT_CLOSE(parent, self.OnClose)
        # 標準のピッチ
        self.pitch = 300
        self.tab = HarmTable()
        self.line = Interp(0, 10000, 0.05)
        self.osc = Oscili(self.tab, self.pitch, 0, None, self.line)
        self.out = SndRTIO(1, SND_OUTPUT)
        self.out.SetOutput(1, self.osc)
        self.thread = SndThread()
        self.thread.AddObj(self.line)
        self.thread.AddObj(self.osc)
        self.thread.AddObj(self.out, SNDIO_OUT)
        self.play = False

    def OnClickButton1(self, event):
        if(self.play):
            self.line.SetCurve(10000, 0)
            self.line.Restart()
            self.play = False
        else:
            self.line.SetCurve(0, 10000)
            self.line.Restart()
            self.play = True
            self.thread.ProcOn()

    # スライダームーブメントのハンドル−ピッチを変える
    def OnSlider1Move(self, event):
        self.pitch = event.GetInt()
        self.osc.SetFreq(self.pitch)

    # ウィンドウを閉じるハンドル−パフォーマンスをストップ
    def OnClose(self, event):
        try:
            self.thread.ProcOff()
            time.sleep(1)
            self.GetParent().Destroy()
        except:
            print traceback.print_exc()

# wxのアプリケーションを作る。
application = wxPySimpleApp()
# コントロールパネルを保持するのにフレームを作る。
frame = wxFrame(None, -1, "PySndObj example")
# フレームの子としてコントロールパネルを作る。
controlPanel = ControlPanel(frame)
# フレームを描く
frame.Show(True)
# アプリケーションを起動する。
application.MainLoop()

原文: SndObj_Manual-2.6.3.pdfの「Python Programming with PySndObj」より