#talk #programming #music #creativity-support-tool https://chci.pages.dev/aist-seminar 2023/11/23(木) --- ## イントロダクション こんにちは。[[松浦知也]]です。 本日は、この様な機会を与えてくださってありがとうございます。 この発表では芸術表現のための創造性支援ツールというテーマの中で、先ほどXavierがプログラマブルなDAW([[PAW]])という実例を見せてくれたこともあるので、私はより理論や歴史的な背景を補足しようと思います。 その上で、現在私が開発している関数型プログラミングとDAWを統合したソフトウェア[[otopoiesis]]について簡単に紹介します。 ## 自己紹介(ここまで1分) 私は現在東京芸術大学の芸術情報センターという、大学のネットワークインフラを管理したり、学生向けのFablab的な設備を提供している場所で働いています。 私は自分のことを音楽土木工学(Civil Engineering of Music)との研究者と呼んでいます。 これは実際には存在しない学問領域ですが、名前の通り、テクノロジーを音楽に応用するのではなく、音楽実践を通じて基幹的な技術インフラを考え直す学問です。 具体的には、自作楽器を使っての演奏活動や、音楽のためのプログラミング言語”mimium”の開発や、今日お話しするプログラマブルな音楽ソフトウェアotopoiesisの設計などに取り組んでいます。 ## 音楽とプログラミングの歴史 では、まず音楽制作に関わるソフトウェアやプログラミング環境について解説しましょう。 一般的に、また、商業的によく使われているDAW、つまり音楽制作ソフトウェアの代表例として、ProtoolsやCubase、Ableton LiveやStudio Oneといったソフトウェアがあります。 これらの多くは、テープの録音やハードウェアシーケンサーに由来するワークフローをシミュレートしたものと言って良いでしょう。 多くはプラグインという音にエフェクトをかけたり、インストゥルメント、つまりノートの情報を受け取り音声を出力するシンセサイザーを組み合わせることで機能を拡張していきます。 一方で、同様にコンピューター上で音を作成するソフトウェアとして、[[Cycling'74 Max]]に代表される音のためのプログラミング環境が挙げられます。 Maxのようなビジュアルプログラミング環境はポピュラーではありますが、[[SuperCollider]]や[[Sonic Pi]]のようなテキストベースの言語も多く存在します。 音楽プログラミング言語のユーザーは時折Digital Audio Workstationソフトウェアとの連携を望みますが、その選択肢は豊富とは言えません。多くの場合は、プログラミング言語で作ったものをオーディオエフェクトやシンセサイザーとして、他の販売されている有料プラグインなどと同じように使用します。 有名なものとしては、[[Ableton Live]]は[[Max for Live]]という、Maxランタイムそのものを埋め込んだ拡張機能でオーディオプラグインやシンセサイザーを作ることができます。有志が作った無料/有料のプラグイン市場も存在します。 またオープンソースの例としては、Maxとも共通の歴史を持つ[[PureData]]という環境を同様にプラグイン化するプロジェクトが歴史的にいくつか存在します。近年ではモダンなGUIを持つTimothy Schoenによるplugdataという環境が有名になってきています。 しかし、依然としてプログラミングによる機能拡張という点では、DAWユーザーはコアな機能を改変することは難しいです。・・・例えば拍子が混在するポリリズミックな音楽を作ろうとするといきなり大変になる、とか。 だからと言って、MaxやPuredataを使って0からDAWのようなアプリケーションを構築できるかというと、音楽のためのDSLの表現能力はそこまで高くありません。 それゆえ基本的には音楽において作曲をする人と音楽プログラミング言語を使う人の間には以前隔たりがあります。 ## 変わらぬ基盤モデル:Unit Generator こうした分業の体制には長きにわたり音楽をコンピューターで生成するにあたってのメンタルモデルが固定化されていることに起因すると私は考えています。 それが、[[Unit Generator]]と呼ばれる信号処理モデルです。 今日の音楽プログラミング環境の多くはその基礎に、基本的な音声合成のユニット、例えばオシレーターやフィルターを繋ぎ合わせていくUnit Generatorというコンセプトを引き継いでいます。 この概念が誕生したのは1960年代で、最も初期のコンピューター音楽環境MUSICシリーズの3から導入されました。 気をつけて欲しいのは、この時代にはまだCRTディスプレイなどによるGUIは存在していなかったことです。 この時代におけるサウンドプログラミングとは、スコアを紙に書き、UGenの接続を紙に書き、それをテキストベース言語のフォーマットに書き直し、パンチカードに入力し、結果を磁気テープにオフラインレンダリングして、出来上がったものを聞く、というプロセスです。このUGenコンセプトは60年代から大きく変化することなく、全てのオーディオプログラミングの前提として存在しています。例えばWebブラウザ上で音声を合成するWeb Audio APIも実質的にUGenをベースにしています。 このUGenモデルはいわゆるハードウェアのシンセサイザーでパッチケーブルを繋いで信号のフローを組み立てる、モジュラーシンセをシミュレートしたものだと思う人も多いでしょうが、実際にはモジュラーシンセが考案されたのはUGenとほぼ同時期です。ただ、特にGUIが一般的になって以降はモジュラーシンセのアイディア、例えば周波数の低い制御信号と実際に音として聞こえる信号を分けて処理するアイディアなどが音楽プログラミング言語の構造にフォードバックされたり、相互共生してきたことは間違いありません。 さらに、1980年代にはハードウェアアクセラレーターを用いることでリアルタイムでの信号処理が可能になり、プログラムのUGen自体をハードウェア化することがプログラムのメタ操作よりも優先されるようになりました。 結局、DAWであっても、ビジュアルプログラミング言語であっても、そしてテキストベースであってさえも多くの音楽プログラミング言語で、我々はUGenを繋ぐという視覚的メタファーに頼っているのです。 私は、これが結果的には音楽ソフトウェアの利用における分業と機能改変可能性の乏しさにつながると主張したいです。 なぜなら、ビジュアルプログラミング言語はデータを流して変換することに特化しているものの、プログラムそのものをデータとして扱うことが難しいためです。別の言い方をすれば、今のUGenベースのビジュアルプログラミング言語はせいぜいビジュアルで表示可能な程度の複雑さしか表現できていない、ということになります。 (ちなみに、MaxやPuredataでメタプログラミングをすることはできないのかというと、不可能ではないです。ただし、そのスタイルはアプリケーションランタイムに新しいオブジェクトを作る命令を投げる、imperativeなスタイルになってしまいます。) ### Epistemic Tools > "As opposed to the acoustic instrument maker, the designer of the composed digital instrument frames affordances through symbolic design, thereby creating a snapshot of musical theory, freezing musical culture in time." ("Of Epistemic Tools: musical instruments as cognitive extensions", Thor Magnusson, Organized Sound 14-2, p173 (2009)) コンピューター音楽の研究者[[Thor Magunusson]]は、コンピューターで作る楽器のことをEpistemic Toolと呼びました。 これは、コンピューターを使った楽器のデザインやそれの使用が常にシンボルを通じた操作となるため、根本的にその時代の音楽文化を埋め込んだシンボルを経由することを指しています。よりシンプルに言えば、アコースティックな楽器と比べると、コンピューターを使う楽器や音楽作成システムは誤用に基づくオルタナティブな表現の追求が困難である、と言えます。 さらに、ツール自体で表現できる語彙があらかじめ与えられている状態になると、その外側の思考に至ることはやがて難しくなります。マグヌッソンは、この負のフィードバック・ループは、音楽理論のスナップショットを作り出し、音楽文化を時間に凍結させるものと表現します。 ドメイン固有言語はドメインの課題を解決する一手段としてみれば一般性を確保する意義はそこまで大きくありません。しかし、芸術や音楽のための言語の場合は、言語仕様に特定のメンタルモデルやメタファーを持ち込むことは表現の多様性を絞ることにもなりかねないのです。 ## Alternative Abstractions of Time Functions では、音楽のためのプログラミング環境ではあるものの、単なるUGenの接続に留まらないより高次の抽象化された表現や、オルタナティブな抽象化の試みはあったのでしょうか? 実のところUnit Generatorコンセプトを考案した当の本人である[[Max Mathews]]は、1970年代以降もコンピューター上で新しい音楽の抽象化方法の模索を続け、Unit Generatorコンセプトにこだわることはありませんでした。 その思想がよく現れているのがMathewsとMooreにより制作されたGROOVEシステムです。 このシステムで扱えるのは200Hz程度までの遅い周波数の信号ではあるものの、リアルタイムでのデータ記録や変換が行えることから、今日のMaxのようなリアルタイムに挙動を変えられるプログラミング環境の原点の一つに数えられます。 しかし、その設計思想はUnit Generatorコンセプトとは全く異なるものです。MathewsとMooreはその設計思想を時間信号のファイルシステムと呼称していました。この時点ではまだMacintoshのようなスキューモーフィックなGUIは世の中に存在していないことに留意してください。 MathewsはこのGrooveシステムを最終的には音楽に限らず時間を扱うあらゆるプロセスに応用できると考えていました。 ここまでの応用は実際のところ実現していないと思いますが、音楽のための言語の開発がやがて時間を取り扱う計算モデルという基礎的な分野に新たな光を当てる可能性はあると思っています。 他にも時間に関わる信号自体のより一般的な表現の追求の例はいくつかあって、代表的なものが[[Eli Brandt]]による[[Chronic]]です。これはevent, finite vector, inifinte vector 3種類の型コンストラクタの組み合わせとして時間関数のジェネリックな表現を提案したものでした。 また、今日ポピュラーな音楽プログラミング言語の中でも特異なのが[[Faust]]です。 Faustは強く形式化された言語で、あらゆる信号処理をシグナルブロックの並列、直列、分岐、合流、フィードバックの5種類の演算子で組み合わせることで表現するほか、マクロで高次の抽象化を実現しています。 Faustによってもたらされた重要な知見は、ほとんどの信号処理は基本演算に加えてディレイとフィードバックがあれば表現できるということです。 音楽における信号処理は純粋な関数ではなく、内部状態を保つことが多いです。そのため多くはオブジェクトのようなデータと関数の組み合わせで表現されますが、この内部状態がディレイとフィードバックで置き換えられると、UGenの接続は関数の合成として表せるようになるのです。 私が開発していた[[mimium]]はfaustの思想をベースにしつつ、内部表現をラムダ計算として形式化したものです。 元々は実装の結果そのような仕様に落ち着いた、というのが実情なのですが、近しい思想を持つ[[The w-calculus a synchronous framework for the verified modelling of digital signal processing algorithms | W Calculus]]がたまたま同じタイミングで提案されたため、それを参考にしつつよりフォーマルな定義を行っている最中です。 ## otopoiesis: a functional programmable DAW otopoiesisのコンセプトはシンプルに言えば **DAWのデータ構造をわずかに抽象的にする**ことを目指しています。 通常、DAWはプロジェクトファイルの中に複数のトラックという構造を持ち、複数のトラックからミキサーに信号が送られて音声を出力します。またトラックは、入力されたストリームにエフェクトをかけることもありますが、記録されたデータの断片を含む、リージョンという構造体を複数抱えて、一つのオーディオストリームを生成します。 リージョンは、記録されたデータを、何秒の位置からある長さの秒数というデータとともに保持します。記録されたデータとはつまりオーディオファイルのことですが、これは一般化すると何かのオーディオを生成する関数の演算結果を保持していると言えるでしょう。 一般的なDAWにおけるプラグインとはMIDIの配列をオーディオに変換するか、オーディオをオーディオに変換します。これは簡単に言えば何かのトラックを別のトラックに変換する関数を適用している、と言えるでしょう。 ならば、トラック以外のものも関数として考えることはできないでしょうか? プロジェクトもトラックもリージョンも関数として考えてしまえば、DAWの中で使われる幾つかの機能はプログラミング言語機能のサブセットとして考えることができるでしょう。例えばトラックにあらかじめ幾つかの組み合わせでのプラグインを挿入するトラッププリセット、プロジェクトにあらかじめ決まったトラックを挿入しておくプロジェクトテンプレートのようなプリセット類も単なる関数として考えることができます。 また処理が重いがリアルタイムの計算を必要としないトラックを一時的にパラメータを固定してレンダリングしておくフリーズと呼ばれる処理があります。言葉としては真逆ですが3D CADのソフトウェアではBakeと呼ばれる機能にも近いですね。これはプログラミング言語において定数になっている部分をあらかじめ評価してしまう定数畳み込みや部分評価と呼ばれる処理と捉えることができます。さらに、プロジェクト自体がパラメトリックになるのであれば、リージョンの中にプロジェクト自体を埋め込むような再帰的データ構造が実現でき、これはデータの再利用性を高めることになるかもしれません。 ## 例:リージョンにフェードをかける 簡単に、現時点でのotopoiesisで実現できている例を示しましょう。 今回は、リージョンをリージョンに変換する関数の例として、リージョンにフェードイン、フェードアウトを適用するものを考えます。これらの機能は普通DAWでは組み込みの機能として提供されますが、otopoiesisではユーザーコードの中でライブラリの関数を呼び出す形で適用できます。 現時点でのotopoiesisはこんなGUIを持っています。右側には、コードのデータ構造がJSONフォーマットで表示されています。 この内蔵言語はいまだにテキストのシンタックスを持っていないのでJSON形式で表示されていますが、疑似コードで表記するとこのようになります。 FadeInOut関数はリージョン型の式を受け取り、一と長さは元々と同一の、しかしその中身にフェードインアウトのエフェクトをかけるコードになっています。 実際のユーザーアクションで、コードを書いてこのエフェクトを適用するかというと、そうでもありません。リージョンを右クリックするとフェードエフェクトをかけることが出来て、既存のリージョンに対して関数が適用される形にコードを変形します。 FadeInOutのエフェクトはあくまで関数ですので、二重三重に適用することもできます(あまり意味はないものの)。 ここで、コンパイルしたときにアプリケーションはパラメーターを探し出してUIを生成します。 UIは関数の内側に入るたびに、変数のスコープに応じて自動でグループ化されるようになっています。 こうした、リージョンに対するエフェクト処理や、DAWの中では破壊的プロセスとして行われるケースが多いです。リージョンに対する操作を関数としてまとめられたり、型の変換も含められるのであれば、例えばこんなことができるはずです。ビートルズがやったことで有名ですが、録音したデータを逆再生する処理は音楽表現としてよく行われます。この時、任意のメロディーを最終的に作りたい場合は、あらかじめフレーズを逆転させて演奏する必要があります。 例えばMIDIのようなノートデータが素材としてあった場合、その前後を逆転し、シンセサイザーを関数として適用しオーディオデータに変換、さらに書き出されたオーディオを前後逆転することで、狙ったフレーズの逆回転という処理を関数として再利用可能にできるでしょう。 ## 執筆時のメモ・・・ - プログラマブルなDAWはいくつかある(例えば[[Reaper]]、[[Ardour]]など)。しかし新しいデータ型を作れるわけではない・・・つまりオートメーションである。 - また、CSoundにDAWっぽいフロントエンドを載せたプロジェクトとして[[Blue]]などがある。 - しかし、CSound自体のメタ表現力はそんなに高くはない - タイムラインベースの汎用プログラミング環境もある。例えば[[OSSIA Score]]や[[IanniX]] - しかし、これもデータの抽象化そのものができるかというと - インタラクティブな音楽を作るためのものとして、ゲーム音楽用のオーディオミドルウェアというのもある。[[Wwise]]や[[ADX]]、[[Fmod]] - しかし、どっちかというとこれもDAWと連携する方向だよね ### グラフベースからの脱却 ### DAWのデータフォーマット https://github.com/bitwig/dawproject 例えばDAWprojectの様なオープン化を目指したものが出てきている 昔ながらのもので言えば、OMFやAAF(オーディオ・ビデオデータのみ)とSMF(シーケンスデータ、複数のMIDIデータの集合)とか Program as a Format - MPEG-Structured Audio(CSoundベースの音源配布フォーマット) ## [[otopoiesis]]について ### プロジェクトの構造 まだシンタックス(パーサー)が実装されてないので、Rust風の擬似ソースコード ```rust let sinewave =|freq,amp,phase|{ ... } let apply_fadeinout = |start,dur,time_in,time_out,content|{ ... } let FadeInOut = |time_in,time_out,origin|{ let time_in = Param("time_in",0.01,0.0..inf); let time_out = Param("time_out",0.01,0.0..inf); Region({ start: origin.start dur : origin.dur content: apply_fadeinout(start,dur,time_in,time_out,origin.content) }) } let project = |sample_rate|{ let tracks = Track([ FadeInOut( 0.1, 0.1, region: { start:0.0, dur: 1.0, content: || sinewave{ Param("freq",440.0,20.0..20000.0) Param("amp",1.0,0.0..1.0) Param("phase",0.0,0.0..1.0) } } ) ]); tracks.map(|t| t.render()).sum() } ```