header

Puredata 初歩の初歩

以下は、技術評論社SoftwareDesign誌2008年6月号に寄稿した記事「オーディオシンセシス環境Puredata初歩の初歩」を基に再編したものです。

もくじ
  • Pdとは
    • 歴史
    • Pdでできること
    • パッチ
    • 得手・不得手
    • 安定性
    • Max/MSPとpuredata
    • 依存ライブラリ
  • コラム:舞台裏のPd
  • Pdを導入する
    • 本家サイトのPd(Vanilla)
    • ディストリビューションのパッケージ
    • Pd-extended
    • プラットフォーム毎の差異
    • 開始前に
    • Edit mode
    • input/outlet
    • パッチ線による結線
    • オブジェクト/パッチ線の削除
    • その他
  • オブジェクトの種類
    • Objectボックス
    • Messageボックス
    • Numberボックス
    • bang
    • その他
    • ヘルプ機能
  • データ形式
    • Message
    • signal
    • Message/Signalの互換性
  • InletのHot & Cold
  • Pdの常套句
    • カウンタ [f]x[+1]
    • 連続する数値を滑らかなsignalに変換
    • signalの数値を読む
    • 再生機器を保護する
  • Pdの拡張
    • Abstraction
    • C/C++で記載する
    • 外部スクリプト
    • その他
  • 事例集
    • スクラッチ再生
    • モノフォニック・シンセサイザー
  • 終わりに

Pdとは

Pdは、各種デバイスから入力されたデータが加工され、出力されるまでの手続きを視覚的に表記するためのインタプリタ型・開発環境です。

Pdの操作画面

元々はデジタル・オーディオをリアルタイムにて制御し、既成の概念にとらわれない自由な(そして広義の)楽器設計を行うことを目的に開発されました。後にオーディオ以外のメディアも扱えるようにする拡張が有志により提供されたことから、現在は音楽に限らず、いわゆるメディア・アート作品のバックエンドなど、幅広い層のユーザに使用されています。また、信号の加工されるプロセスが視覚的に把握しやすいことから、サウンド・デザインや信号処理の教材としても適しています。

近年はモジュール型のアナログシンセサイザーをシミュレートする製品が多数販売されており、ついにはニンテンドーDS用にまでKorgの銘機を模した製品が販売されるそうです。これらのアナログ・シンセサイザーで音色を編集する際には、Pdと同様に各種モジュールをパッチ・ケーブルで接続して、信号が加工される経路をデザインするのが一般的です。外観こそ似てはいるものの「puredata」はその名が示すとおり、より複雑なデータ処理も可能な、れっきとしたプログラミング環境です。これによりアナログ・シンセサイザーでは到底できないロジックの記述なども可能です。

歴史

時は1980年代、フランスの音響研究所IRCAMでは、同施設が開発したSogitec 4Xシンセサイザが作曲家、研究員の間で広く使用されていました。 (この4Xの要件定義の裏にLuciano Berioの発言があったという逸話は、現代音楽ファンにとって興味深いのではなでしょうか) 独自仕様のプロセッサを搭載した4Xは、デジタル・オーディオの処理能力に関しては先進的でありながら、主な用途は事前にスケジューリングされた処理の再生に限られていました。 この装置を、なんとか生演奏に適した楽器に仕立て上げる手段はないものか…。そういった問いへの答えとして、当時IRCAMに在籍していたMiller Puckette(注3)が開発したのがMaxと名付けられたアプリケーションでした。 Maxはあくまで演奏用のインターフェースに徹し、実際のオーディオ処理は4XのカスタムDSP上で行われていたことから、この組み合わせをシンセサイザー演奏におけるクライアント/サーバ型モデルの「はしり」ととる向きもあるようです。

Maxが持っていたコンセプトを踏襲しつつ、当時の一般的なマシン・スペックでは不可能だった音声信号処理の機能を追加したものが現在のPdです。

Pdで出来ること

Pdでは高度なオーディオ処理をリアルタイムで行えることに加え、前述のようにオーディオ以外のメディアを扱うライブラリも有志により多数公開されています。 有名なところでは、3D-CG(OpenGL)と映像入力を処理可能なライブラリ「GEM」などが挙げられます。(著者による拙いデモ

また、ハードウェア・インターフェース、RS-232C、LANなど、おおよそあらゆるデータを入力として処理し、場合によってはフォーマットを相互変換した結果を出力することができます。

このため、Pdで完結する作品を作るだけでなく、各種データをリアルタイム処理するためのミドルウェアを手っ取り早く組むのにも適しています。 (Pdを中心に、ソレノイドのファームに演奏させたケース

パッチ

Pdで作成したファイルは「パッチ(patch)」と呼ばれ、内部はアスキー形式で保存されています。 このため、作品中で使用するライブラリさえ共通であれば、プラットフォーム間の互換性が容易に確保できます。

得手・不得手

Pdはリアルタイムで入力を与え、その結果として出力を得るという性格が強い傾向にあります。 逆に膨大なスケジューリングを効率よく行う手段は持っていないため、大抵はユーザが必要に応じた実装を行うことになります。 具体的には、Pdが提供するタイマーや配列を組み合わせるほか、外部の機器やアプリケーションにプログラミングしたものを、何かしらのインターフェースを通して流し込むなどの方法があります。

また、環境がグラフィカルであるという性質上、再帰的な処理や、OOP言語のようにループ内でインスタンスを生成するような手続きは、不可能とまでは言いいませんが、スマートに実装する方法も現在のところありません。

安定性

オープンソース界隈のオーディオ・アプリケーション全般に言えることですが、Pdはあいにく「極めて安定している」とは言い難い状況にあります。

しかし、プロセスが落ちるのに至る動作のほとんどがパッチの編集作業に伴うため、なんとかパッチさえ完成させてしまえば、ライブ・パフォーマンスには十二分に耐えるというのがユーザ・コミュニティにおける共通認識となっているようです。

Max/MSPとPuredata

幾分かオーディオ・ソフトウェアをご存知の方であれば、これまでの説明をご覧になってまさにMax/MSPと同一ではないかと思われたかも知れません。

実は、かつてMiller氏が開発したMaxはPdに取って代わられたわけではなく、Miller氏がIRCAMを去った後も開発が継続され、後にDavid Zicarelliが起こしたCycling' 74社を通じて製品化・販売されることになります。製品ページ(執筆時の現行バージョンはMax/MSP4)現在も基本的なコンセプトやインターフェースの多くは共通しています。

オリジナルのMaxを開発し、その遠縁に当たるpuredataの作者でもあるMiller氏自身は、これらツールの区分を「Maxパラダイム」と一括りにしており、メディア・アートにおけるこれらソフトウェアの位置づけを語る際には特に区別はしません。(Miller Puckette著・"Max at seventeen"参照)

OpenOffice.orgをはじめ、市販ソフトウェアとそれに相当するFOSSという図式は沢山ありますが、同じ原作者によるものがそれぞれ異なる道を歩み、互いにインスピレーションを与えながら進歩しているケースというケースは珍しいのではないでしょうか。

依存ライブラリ

PdはGUIの描画にTcl/tkを使用しています。また、オーディオ・ドライバ/ライブラリは、LinuxならばJack、ALSA、OSS、WindowsにおいてはMMIO、ASIO(PortaAudio)に対応しています。

かつてクロス・プラットフォームを実現するために、Tcl/tk、PortaAudioへの依存が決断されたのは、当時ライブラリの選択肢が限られていたこともあったと思われます。 ことTcl/tkに関しては多大なオーバーヘッドがつきまとうことから、Miller氏自身、自らがとった選択を悔やんでいる旨の発言を度々しています。

舞台裏のPd

ここで、少し特殊なものばかりですが、実社会(?)でのPd導入事例をご紹介致します。

Electronic Arts - SPORE

公式サイト

EA社のPlay Station3用ソフトSpore(日本未発売)では、プレイヤーが有機的な間接を組み合わせて、自由にキャラクターをデザインすることができます。 このゲームの効果音には、Pdのオーディオ・エンジンを独自にカスタマイズしたものが使用されていることを、エンジン担当者でありGEM開発者でもあるMark Danks氏がMLにて打ち明けています。 プレイヤーが作成したキャラクターの特徴や動作に合わせて効果音を変幻自在に追従させることにより、これまでのPCM音源(事前に録音された音)よりも豊かな表現が可能となりました。

記事執筆後日談:実際には発音タイミングのアルゴリズムにPdのエンジンが使用されているだけで、オーディオシンセシスには使用されていないことが、後になにかの折に製作者により明かされたとのことです。

New York Times - Moveable Type

解説ビデオ

2007年にNYタイムズ誌が本社ビルを移転した際、新社屋の一階ホールに、560台の組み込みLinuxと液晶パネルからなる巨大なインスタレーションが、嘱託されたBen Rubin、Mark Hansen両氏により設置されました。 「Moveable Type」と題したこの作品は、NYタイムズ社設立以来100年以上蓄積された記事のデータベースからテキストを抜き出し、様々なパターンで表示します。 また、それに伴う音響も、560台の端末に内蔵された個々のスピーカから再生され、マルチチャンネルのスピーカでは表現できないようなサウンド・スケープが演出されています。この作品のオーディオ部分には、PdのPDA用ポート、その名もPdaをカスタマイズされたものが使用されています。 Moveable Typeが展示されているホールは一般の方にも常時開放されていますので、NYに行かれる際にはぜひお立ち寄り下さい。

Pdを導入する

それでは早速、Pdをインストールしてみましょう。 Pd自体は特に癖もなくインストールできると思われますので具体的な手順は割愛させていただくとして、ここでは主なディストリビューションの特徴だけご説明します。 主な対応プラットフォームは、Linux、OSX、Windowsとなります。

本家サイトのPd(Vanilla) (注3)

Miller Puckette氏によるPdパッケージで、ソースおよびWindowsバイナリが公開されています。(Miller氏のサイト)また、他のディストリビューションと比べて「素」に近いからか、コミュニティにおいては「Pdバニラ(Vanilla)」の愛称で呼ばれています。

付属するオブジェクトはオーディオ・MIDIに特化しており、その他のメディアは扱えません。 第三者の提供する拡張ライブラリ(Extensions)を使用する場合には、svnを使用してソースを入手して各自でビルドするのが流儀となります。 この際にはソースパッケージに付属するヘッダ・ファイルが必要になります。

ディストリビューションのパッケージ

少なくともSarge以降のDebian/Ubuntuには、"puredata"パッケージが用意されていることを確認しています。このパッケージはVanilla Pd同様、オーディオ/およびMIDIを扱うオブジェクトしか付属していません。 公式レポジトリを使用するのであれば、少々バージョンは古いもののPdのOpenGL拡張である"GEM"パッケージもついでにインストールされることをお勧めします。

pd-extended

最後に、Hans-Christoph Steinerがメンテナを努める「pd-extended」をご紹介します。 このパッケージには主要な拡張ライブラリがバイナリ形式で含まれており、各自でソースを収集、ビルドする手間を省くことができます。 執筆時にはDebian/Ubuntu、Fedora Core、MacOSX、Windows版が用意されていました。 Stable版は比較的安定しており、初心者がPdを導入するのに大変便利です。(サイト

プラットフォーム毎の差異

Windows版のPdは依存しているライブラリの関係から、オーディオのレスポンスおよびMIDIのタイミング精度において一定以上の水準を確保するのが比較的困難なようです。 レイテンシ(遅延)が問題になるようであれば、一度他のプラットフォームも試してみると良いかも知れません。またMacOSXについて。 実は筆者はMac自体ほとんど知らないため、メーリング・リストから得る印象になり恐縮ですが、Mac OSXにおいては稀に独特の挙動はあるものの、動作に特に支障はないようです。

ちなみに筆者は通常業務にWindowsを多用しているため、思いつきでパッチを組む時はWindows + pd-extended、本腰を入れてオーディオ処理を行うときやLinuxにしかないライブラリを使用する際には、Ubuntu Studio 7.10 + pd-extendedと使い分けています。

開始前に

Pdを立ち上げると、まずメイン・ウィンドウが立ち上がります。

Pdのメイン・ウィンドウ

エラー・メッセージや[print]オブジェクト(後述)の出力などはすべてこのウィンドウのコンソールに表示されます。 パッチを新規作成するには、「File」→「New」を選択するか、Ctrl+Nを押して下さい。 オーディオの入出力を使用する場合は、オーディオ・エンジンを有効にする必要があります。以下に3通りの方法を記します。

  1. メイン・ウィンドウのメニューより「Media」→「audio ON」を選択
  2. メイン・ウィンドウ上の「compute audio」にチェックを入れる
  3. Ctrl + / (オフはCtrl + .)

Edit mode

Pdには「Edit mode」という概念があり、オン時は編集に、オフ時には演奏にそれぞれ都合の良いようインターフェースの挙動が異なります。 この切り替えは、Editメニュー内の「Edit mode」をチェックするか、Ctrl + Eを押して行います。 オブジェクトの配置変更やパッチ線の描画などは、Edit modeがオンの状態で行います。 逆にEdit modeがオフの間はパッチの内容を変更することはできず、演奏中にうっかりオブジェクトをドラッグして移動させてしまうこともありません。 また、ボタンやフェーダーの操作はEdit modeがオフの状態でのみ行えます。Edit modeの状態は、メニューの項目にチェックが入っているかどうか以外に、カーソルのアイコンからも確認することができます。 Edit modeがオンの間、カーソルは人差し指以外を握った拳のアイコンとなり、オフの間は矢印で表現されます。

inlet/outlet

Pdのオブジェクトは、オブジェクト上段にinlet(入力)、下段にoutlet(出力)を持ちます。

inletとoutlet

あるオブジェクトのoutletから出力される内容を、異なるオブジェクトのinletに接続することによりパッチを組み上げていきます。 各オブジェクトが持っているinlet/outletの意味や受け付けるデータの種類に一貫性は特になく、それぞれのヘルプ・ファイルを参照することになります。

パッチ線による結線

パッチ線でオブジェクトを結ぶには、任意のoutletをクリックした後にマウスをドラッグし、パッチ線が延びていることを確認しながら、接続先のinlet上でマウス・ボタンを離します。もしinletが接続を受け付けない場合、オブジェクトの扱うデータ形式に互換性がない可能性があります。詳細は後述する「データ形式」の項をご覧下さい。

オブジェクト/パッチ線の削除

オブジェクトやパッチ線をクリックまたは範囲指定すると、選択された部分が青くハイライトされます。 この状態でDeleteを押すことにより削除が可能となります。 Windows用バイナリではおそらくTcl/tkの互換性から、Backspaceが削除に割り当てられています。

その他

現在、アプリケーション自体がマルチバイト文字に対応していないようです。

例えばWindows版用のバイナリの場合、半角文字を含むパスを指定すると予期せぬ場所にファイルが保存されたりすることが起こります(「デスクトップ」等を含む)。 このため、英文字だけから成る作業用ディレクトリを作成することをお勧め致します。

オブジェクトの種類

Pdのワークスペースに配置できるオブジェクトは、その性質からいくつかの種類に分類されます。 各種オブジェクトは、Putメニューより選択して配置します。

Objectボックス

なにかしらのデータ処理を行うオブジェクトです。 Objectを配置すると表示される空のボックスにオブジェクト名をタイプすることにより、そのオブジェクトのインスタンスを生成するができます。

オブジェクトの例

この際、オブジェクト名に続いて、初期値を引数で指定できるものもあります。

Pdで使用できるオブジェクト名については体系的な一覧表は存在しません。 よって、事前に名称を知っておく必要がありますが、付属のチュートリアル・ファイルを一通り読み終える頃には、基本的なアイディアを実現できるだけの知識は十分身に付いているものと思われます。

以降、文中のオブジェクト表記はユーザ・コミュニティの慣習に倣い、object boxを模した[]を使用して表記します。

Messageボックス

Messageボックス

Edit modeがオフの状態においてマウスでクリックするか、あるいはinletから何かしらの入力を受けると、書き込んだ値がメッセージとして送信されます。 このときinletからの信号は単なるトリガーとして解釈され、入力された内容自体は基本的に無視されます。

Numberボックス

Numberボックス

Numberは、数値のコントローラと表示用のオブジェクトという二つの機能を兼ね備えています。 まず、inletから数値が入力されるとその値が表示されます。 また、Edit modeがオフの状態で上下にドラッグすると数値が変更され、その都度値がoutletから出力されます。 Shiftキーを押しながらドラッグした場合は、0.01ステップのより緻密な変更が可能です。

bang

bang(バンあるいはバング)とは、Pdにおいて多用される汎用のトリガーです。 多くのオブジェクトがbang受信時の動作を定義されていますが、実際にどのような動作を行うかについて一貫性はありません。

bangを送信可能なオブジェクトには、Putメニューから選択できるボタン型のbangと、単にメッセージ・ボックスにbangと記載したものの二つがあり、これらは同様に機能します。

bangを送信可能なオブジェクトの一例

ただし、ボタン型がinlet入力時に点灯するのに対し、メッセージ・ボックスの方はGUI上変化しないという差異があるため、前者はデバッグ時にデータの流れを確認する場合、後者は描画のオーバーヘッドを軽減したい場合と使い分けることも可能です。

余談ですが、いざパッチを自作し始めると、とりあえずルーチンを始動する第一歩としてルーチンの頂点にあるオブジェクトにbangを送信する構造になりがちです。 このことから、bangメッセージはユーザ・コミュニティおいて「何かの始まり」を司るシンボルとして、各種ロゴなどにも用いられています。

その他

ボタン以外に、演奏に便利なボタンやフェーダー、チェック・ボックスなど有用なコントローラが配置可能です。 これらを配置した後、右クリックで開くプロパティ・ウィンドウから、値のとりえる範囲やカーブの種類、サイズなどの変更が可能です。 配置できる主なコントローラの一覧はputメニュー内にあります。

その他のコントローラ

ヘルプ機能

オブジェクトを右クリックして開くウィンドウから「Help」を選択すると、そのオブジェクトのヘルプ・ファイルを開くことができます。 Pdのヘルプ・ファイルはそれ自体がパッチとなっているため、ヘルプ中のサンプルを実際に操作して反応を確認することができます。 また、サンプル内で機能が解らないオブジェクトを見つけた際には、再帰的にヘルプファイルを開いて学習を進めることができるようになっています。

データ形式

他のプログラミング言語と同様、Pdのオブジェクト間を流れるデータには数種類の型があります。 型については、多少大掛かりなプログラミングに取り組むまでは、意外と意識せずとも目的を果たすことができると思われますので、本稿においては割愛させていただきます。 しかし、データが流れるタイミングや順序の理解は、正確なロジックを組む上で避けて通れません。 ここでは、最低限必要と思われるポイントをご説明します。

Message

Messageは、入力があったとき、またはスケジューリングされたタイミングにのみ流れるデータです。 これまでにご紹介しました各種ボックスの入出力やbangなどがこれに分類されます。 Messageが流れるパッチ線は通常、1ピクセルの太さで表現されます。

パッチの接続線

またmessageを出力するオブジェクトを[print]オブジェクトに接続すると、入力された内容をメイン・ウィンドウのコンソールで確認することができます。

signal

signalを出力するオブジェクトは、1サンプル毎に32ビットのfloatを一つ出力します。(実際には関数呼び出しのオーバーヘッド軽減のため、任意のブロック・サイズ(デフォルトは64サンプル)毎に処理されます)

例えばサイン波を出力するオブジェクトを、サウンドカードの出力を司るオブジェクトに接続すると仮定します。このときサンプリング・レートが44.1kHzに設定されているならば、毎秒44,100個の32ビットfloatがオブジェクト間を流れます。 ちなみにロジック中のsignalは32ビットfloatが表現できるならどのような値をとっても構わないのですが、サウンドカードへの出力は-1~+1の値をとることが期待されています。よって、出力段階までにこの範囲に収まるように処理がなされないとオーディオが歪む結果となります。 Signalが流れるパッチ線は比較的太い線で表現されます。 また、入出力のいずれかがsignalを扱うオブジェクトは、オブジェクト名の末尾にティルダ(~)が付きます。

Message/Signalの互換性

入力にsignalを受け付けるinletは大抵、Messageによる数値も受け付けます。 しかし、逆にMessageを受け付けるオブジェクトに対してsignalを入力することはできません。 (試してみると判りますが、GUIがそもそも結線を許可しません) そのため、例えばサイン波を発生するオブジェクトの出力値を読む場合には、前述のようにNumberボックスを直接接続する代わりに、別の手段を講じる必要があります。 後に一例を記しておきます。

InletのHot & Cold

複数のinlet/outletを持つオブジェクトについては、メッセージが流れる順序に、ある規則が存在します。 Messageを扱う(名前の末尾に~が付かない)オブジェクトは、常に左端のinletがHot、その他すべてのinletがColdと定義されています。 Coldなinletに入力を受けたオブジェクトは、内部で何かしらの処理は行うものの、出力は一切行いません。 次にHot inletに入力があった場合には、必要であれば内部で処理を行った後、outletから出力を行います。 ここで、float値を一つ保持する機能をもつ[float]オブジェクトを例にとってみましょう。

Inletのhot/coldの違い

以降、サンプル・ファイルによく見かける形式に倣い、[float]オブジェクトを省略形である[f]と記載します。

[f]オブジェクトの二つのinletはいずれも、入力された数値で保持する値を上書きするという機能を持ちます。 しかし、右側のinletは規則通りColdと定義されていますので、入力を受けたタイミングでは出力を行いません。 翻って左側のinletはHotのため、数値が入力されると保持する値を上書きしつつ、同時に新しい値を即座に出力します。 また、同図にあるように[f]オブジェクトはbangを受信しても保持する値を出力する機能を持ちます。

また、複数のoutletを持つオブジェクトは、必ず右から順に値を出力するという規則があります。このようにメッセージが入出力される順序に一貫性をもたせることにより、複数のinlet/outletをもつオブジェクトを結線する際に、流れを把握し整合性がとり易い工夫がなされています。

二つのinletをもつオブジェクト1

では、一つのoutletを二つの異なるinletに接続した場合にはどのような順序で処理が行われるのでしょうか? この場合は、結線が行われた順番にデータが処理されるのですが、これではパッチを眺めただけではフローを把握することはできません。

二つのinletをもつオブジェクト2

そこで、このような場合にはデータの処理手順を明示する[trigger](または略号である[t])オブジェクトを使用します。 (図12右)[trigger]オブジェクトはこれまでの規則通り、右のoutletから順に出力をコピーして行います。 また、必要であれば型変換を同時に行うことも可能です。 指定できる型の種類と略号は、[trigger]オブジェクトのヘルプ・ファイルをご参照下さい。

signalを扱うオブジェクトについては上記の限りではなく、出力はサンプル毎に行われ、見た目には全ての入出力が同時に処理されます。 例えば信号の加算を行う[+~]オブジェクトなどは、双方の入力を同時に受け付け、結果を処理します。

Pdの常套句

他のプログラミング言語と同様に、Pdにおいても頻出する目的を果たすための常套句が存在します。 本稿では、付属のサンプル・ファイルを読むのに役立つと思われる定番をいくつか選択してご紹介します。

カウンタ [f]x[+1]

カウンター・パッチのスクリーン・ショット

[float]オブジェクトと[+]を組み合わせて、カウンタを作成します。

図中の[float]オブジェクトはbangを受信する度に、現在保持する値をNumberボックスと[+]オブジェクトに送信します。 送信された値は、引数に1を持つ[+]オブジェクトによりインクリメントされ、[float]オブジェクトのinletに返されます。 ここで、[+]オブジェクトの値が[float]のcold inletに返されていることにご注目下さい。 これにより、更新された値が再度送信され無限ループが生じるようなことはありません。

連続する数値を滑らかなsignalに変換

ここでは、いよいよ音の出るパッチを作成します。

パッチのスクリーン・ショット

[osc~]オシレータはサイン波の生成、[dac~]はサウンド・カードへの出力(D/Aコンバータの略)で、今後もっとも使用するオブジェクトになると思われます。

このパッチにおいて[line~]オブジェクトを挿入せず、Numberボックスの出力を直接[osc~]オブジェクトの入力に接続するとどうなるでしょうか? Numberボックスをドラッグすると、値が連続して送信されますが、その粒度は毎秒44,100(あるいはそれ以上)という膨大な数のfloatを扱うsignalオブジェクトに比べて大変低く、いかに細かいステップで数値を変化させても出力信号の飛び、つまり音飛びが生じてしまいます。 「指定した時間をかけて、数値をサンプル単位で滑らかに変化させる」という機能を持つ[line~]オブジェクトを挿入することにより、このような現象を回避することができます。

[line~]オブジェクトは、スペースで区切られた二つの数値を受け取ると、「現在保持する値から、入力された<値1>まで<値2>msecかけて、間を補間されたsignalを出力する」機能を持ちます。 また、先ほどmesssage box自身は入力の内容に関係なくトリガーされると書きましたが、ここでは$1により入力を変数として受け取り、次のオブジェクトに渡すメッセージを構成していることがお解りいただけるかと思います。 (ここではlist型というへ暗黙に変換していますが、現段階では特に意識せずとも直感的に扱える範囲と思われますので、詳細は割愛します) 音飛びを防止するのが目的であれば、ここで指定する時間はせいぜい2~5(単位はmsec)程度で構いません。

signalの数値を読む

これまでに、signalを出力するオブジェクトは、値を表示する目的でNumberや[print]オブジェクトに直接接続することができない旨を説明しました。ここで、便利なオブジェクトの紹介を交えながら、signalの値を間接的に読み取る方法を一つ提案します。

パッチのスクリーン・ショット

[phasor~]オブジェクトは、0から1まで連続的に上昇して最後に0にジャンプするという動作を1サイクルとし、これを引数で指定した速さ(単位はHz)で繰り返しsignalを出力します。 (シンセシスに詳しい方へ:ノコギリ波を期待してサウンドカードの出力に接続する前に、振幅が-1~1ではなく0~1の値を取っていることにご注意下さい。 …早い話、[-~ 0.5]すればよい)

[snapshot~]オブジェクトは、左端のinletにbangを受信すると、その時点で同inletに受信しているsignalの値をmessageに変換して出力します。

[metro]オブジェクトは、初回のbangを受け取って以降、引数に指定した時間(単位はmsec)毎にbangを出力し続けます。 (出力を停止させる方法はヘルプ・ファイルをご参照下さい)

図中のパッチでは、0~1まで0.1Hzの速さで、つまり10秒かけて変化する[phasor~]オブジェクトの出力を、200msec毎に取得してNumberボックスに送信しています。

再生機器を保護する

最後に、オーディオ出力の前段に常套的に挿入される[hip~]オブジェクトをご紹介します。直流の信号や極端に低い周波数は、人間の耳には聞こえないものの、大抵のスピーカや音響機器にとってよくありません。 最悪の場合、物理的な動作に耐え切れず、スピーカ・コイルが破損することさえあります。 市販CDの多くはこのような事故のないよう、あるいは可聴域外の成分情報が大域を無駄に占有しないよう、低周波をカットした状態で収録されています。 しかしPdの出力はどのような値もとることができるので注意が必要です。 大切な音響機器を保護するためにも、汎用のハイ・パス・フィルターである[hip~]をサウンド・カードへの出力の前段に挿入することをお勧めします。 通常は引数に、5かそれ以上の数値を指定します。

Pdの拡張

Pdのオブジェクトを自作するには、主に3つの方法があります。

Abstraction

作成したいオブジェクトがPd本体で実装可能な場合、パスの通ったディレクトリにパッチを保存すれば、オブジェクト名としてファイル名を指定するだけで異なるパッチから呼び出すことが可能になります。

Abstractionの例

この形式で実装されたパッチはAbstractionと呼ばれています。 呼び出し側のパッチ(左ウィンドウ)には、Abstraction中に記載された[inlet]、[outlet]オブジェクトの数に応じて、inlet/outletの数が正しく表示されます。 また、呼び出されたAbstraction(右ウィンドウ)のウィンドウ・タイトルにご注目下さい。任意の名前で保存された、あくまで通常のパッチであることがお解りいただけるかと思います。 Abstractionの中身は他のPdパッチと同様テキスト形式で保存されるため、プラットフォーム間の互換性も維持されます。

C/C++で記載する

速度を要する処理、あるいはPdだけでは実装が不可能な機能は、ガイドラインに沿ってC/C++でビルドすることが可能です。

外部スクリプト

[pyext]、[pdlua]はそれぞれ、ガイドラインに従って書かれたpython、Luaスクリプトをオブジェクトとして呼び出せるラッパー・オブジェクトです。

その他

Abstractionに似た手法で、Sub-patchという概念がありますが、本稿では割愛します。興味のある方は付属のチュートリアルをご覧下さい。

事例集

それではここで、オーディオを扱うパッチをいくつか実際に組んでみましょう。 なお、この項においてはPdでパッチを製作する際の「雰囲気」さえ掴んでいただければよしとしまして、新たに登場するオブジェクトやアルゴリズムについての説明は最小限のものとさせていただいております。

スクラッチ再生

ターン・テーブル上のレコード盤を手で回すのと同様に、読み込んだオーディオ・ファイルや音声入力をマウスでスクラッチ再生可能なパッチを作成します。

スクラッチ再生パッチ
  1. ウィンドウ上部のputプルダウン・メニューより、Array(配列)を選択します。Arrayは32bit floatを保存することができる汎用の配列です。音声データの録音に限らず、各種数値の管理に使用することができます。 配置時にArrayに割り当てる名称とサイズを尋ねられます。ここではArrayの名前をsample、サイズを88,200としました。これでサンプリング・レートが44.1kHzの場合、88,200サンプル、つまり2秒間の録音が可能なバッファができました。
  2. [soundfiler]はarrayにオーディオ・ファイルを読み込んだり、逆にarrayの内容をオーディオ・ファイルに書き出したりするのに使用します。通常はルーチンには直接接続せずに配置し、コマンドを送ることで処理を実行します。ここでは「ルート・ディレクトリに保存されたsweets.wavを、sampleという名前をもつarrayに読み込め」というコマンドを送ります。この例の場合、[soundfiler]に宛てるメッセージで明示していないため、オーディオ・ファイルのCh.2(右チャンネル)およびarrayに収まりきらない2秒目以降は無視されます。[soundfiler]にこのメッセージを送信するには、Edit modeをオフにしてmessage boxをクリックする必要があります。
  3. Hsliderを配置します。設置したsliderを右クリックすると出現するポップアップから、「property」を選択します。ここでは横幅を400ピクセル、output-range:right(スライダーの右端が取り得る範囲)を、arrayの最終地点である88,199としました。パッチの完成後は、Edit modeをオフにしてこのスライダーをドラッグすることにより、再生位置を決定します。
  4. [tabread4~]は、arrayの任意の箇所をから連続する数値をsignalとして読み出すオブジェクトです。読み出す位置は、左inletへ数値を入力することにより指定します。
    さて、arrayの読み出し位置をスライダーで指定することになるわけですが、今回作成したarrayが88,200ものサンプルを保持しているのに対し、画面上のスライダーはたかだか400ピクセルしかありません。このままでは、スライダーを1ピクセル移動させる度に、読み出し位置は約220サンプル単位で飛んでしまいます(88,200/400)。[tabread4~]に送る「読み出し位置情報」をサンプル単位で正確に指定しないことには、連続性のない数値がサウンド・カードに出力されてしまいます。そこで前述の例のように、[line~]オブジェクトを挿入して、スライダーの数値が補間された数値の連続となるよう処理します。図中で[line~]の代わりに使用している[vline~]および、[tabread~]に対する[tabread4~]は、現段階では比較的高い負荷と引き換えに、より高い精度を得るための代替オブジェクトとだけ理解しておいていただければ結構です。
  5. 最後に[tabread~]によりarrayから読み出した数値の連続を、サウンドカードの出力である[dac~]に接続します。
  6. オマケで、音声入力を録音するオブジェクトを配置しました。[tabwrite~]は、bangを受信すると任意のarrayの0地点に始まり、終端に到着するまで入力されたsignalを1サンプルずつ書き込むオブジェクトです。ここでは[adc~](A/Dコンバータ)の左チャンネルを接続しましたので、bangを押してから2秒間、オーディオ・カードのch.1(Lチャンネル)への入力が録音されます。録音された音声は、先ほどファイルから読み込んだ波形と同様にマウスによるスクラッチ再生が可能です。

ここで余談ながら、重要なポイントを一つ。今回のケースのように、保存された88,200個の数値を「録音されたオーディオ信号」として扱うのは、arrayの唯一の用途でなければ、まして中心的な用途でもありません。先ほども書きましたように、arrayは「汎用の」配列です。 同様に、各種オブジェクトが出力するsignalは「汎用の信号」であり、用途は特定されていないことをご理解下さい。例えばあるモジュールの出力信号は、スピーカに接続されて初めて「オーディオ」信号であると解釈できます。例えばモジュール型アナログ・シンセサイザーの定番機能「LFO(Low Frequency Oscillator)」は、低い周波数で異なるオシレータの音量制御に使用すればビブラートの効果を出す「変調器」になりますし、周波数を可聴域まで上げればそれ自身が発音器であると見ることができます。 各種波やデータ列を、どのような場面で変調に転用できるかという発想、あるいはボキャブラリの数が、この類のツールから引き出せる音色のバリエーションに比例します。

モノフォニック・シンセサイザー

単音の矩形波(ファミコンの内蔵シンセでお馴染みの音)を演奏できるのシンセサイザーを製作します。小ぶりながら、MIDIキーボードによる演奏も可能です。

パッチのスクリーン・ショット

キーボードをお持ちでない方は、中央上段の49, 61と書かれたmessage boxをクリックすることで、二つの音程を演奏することができます。

  1. まず、波形を表示するオシロスコープとして使用するためのarrayを3つ用意します。サイズはすべて400、名前はそれぞれphasor1、phasor2、scopeとします。
  2. オシロスコープといえど、実態はただのarrayです。そこで、arrayの内容を定期的に更新するba仕組みを用意しなければなりません。ここでは[metro]オブジェクトを使用し、200msec毎にオシロスコープを再描画するトリガーとなるbangを生成します。[metro]オブジェクトに接続された[send](図中では略号である[s]を使用)は、引数で指定された同名の[receive](同じく[r]を使用)に入力されたメッセージを転送します。以降パッチ内に計3つ存在する[r writeArray]と[tabwrite~]の組み合わせは、「フロー内の各箇所で200msec毎に入力をarrayを書き出す仕組み」とご理解下さい。(書き込み先のarray sizeが400ですので、具体的には「200msec毎に飛来するbangに反応して、400サンプル採取しては次のbangまで何もしない」という動作になります)
  3. MIDIデバイスの入力、または数値を受け取ると音を発するようにします。入力された数値はMIDI note numberとして扱われ、続く[mtof]オブジェクト(MIDI to Frequency)により周波数を表す数に変換されます。 ちなみに「MIDI note number」とはピアノ鍵盤の各キーに通し番号を割り当てたもので、通常は0~127の値をとります。各数字が対応する音程はMIDI規格により定められています。
  4. さて、先に鍵盤などから入力されたメッセージは、エンベローブ(音量)を処理するセクションと、波形と音程を扱うセクションに分岐されました。まずはエンベローブを制御している[vline~]オブジェクトについて、今回受け取っているメッセージ「0, 1 15, 0 500 100」を以下に意訳します。
    • 0に移動する。
    • 1まで15msecかけて移動する。
    • 0まで500msecかけて移動する、トリガー受信から100msec後に。
    0から1へ、そして0に戻るこのsignalを波形の振幅に乗算することで、音量を変化させています。この動作は入力があった際にのみトリガーされますので、隣のブロックが絶えずsignalを発しているのにも関わらず、任意のタイミングでのみ音が鳴るわけです。
  5. さて、いよいよこのパッチの肝となる箇所を覗いてみます。実はPdには、単体で矩形波を出力するオブジェクトは存在しません。そこで[phasor~]と[wrap~]を応用します。[wrap~]オブジェクトは「入力された値と、その値より小さく、かつ最大の整数との差」を求めるのに使用します。なにやら複雑な表現ですが、0以上の値を入力する分には「整数部分を無視して、小数部分だけ出力する」と考えていただいて結構です。そこで、0~1の値を繰り返し出力するphasor~の各サンプルに0.5を加算して、先の[wrap~]が提供するロジックを適用するとどうなるでしょう?phasor1、phasor2の各arrayへの出力をご覧になればわかるように、なんと元のphasor~の出力から、半波長だけ位相のずれた波形が得られます。さらに、元の[phasor~]の出力と、この半波長ずれた波形の差を[-~]を求めると、振幅が-0.5~0.5となる矩形波を得ることができます。

終わりに

以上、Pdの基本的なコンセプトから背景までを、広く浅く紹介してまいりました。

PdにはMiller氏が提案する「音楽ソフトウェアは、それにより製作される音楽の様式を規定してはならない」という哲学が見事に結晶されており、一つの定まった用途を提案しません。 今回は単純な音の生成に終始しましたが、アナログ機器でも可能なロジックに基づく音響の生成は、Pdの持つ膨大なボキャブラリーのうち、ごく一部に過ぎません。

このように自由度が高く強力なツールであるはずのPdですが、現在のところ日本語のリソースが不足しているという点が災いして、国内において不当に低い認知度にとどまっているように感じます。 今回の記事は、資料としては散漫になることを覚悟の上で「とっかかり」となるだけの情報を日本語で提供できればという思いで執筆させていただきました。

Pdに付属のチュートリアルは英文ではあるものの、基本的なオブジェクトの用法や有用なロジックが順序立てて説明されており、非常に学習しやすい環境が整っています。ここまでお読みいただいて少しでもPdに興味を持たれた方は、ぜひとも付属チュートリアルの方もご覧下さい。