- 楽器や機材がなくても音楽を作れる環境として Sonic Pi が紹介されており、Ruby ベースの DSL で音符・コード・スケール・タイミングを直接記述できる
- Ruby の関数、配列、条件文、繰り返し、スコープを活用すると、
play、sleep、play_pattern_timed、chord、scale を組み合わせて 反復パターンとアルペジオ を簡潔に構成できる
in_thread、ring、flatten、splat 演算子、with_fx を組み合わせると、複数の「楽器」を同時に動かし、重なった音や異なるリズム をレイヤーできる
- ADSR エンベロープの
attack、decay、sustain、release の調整は、実際の合唱の再現よりも 持続時間と分離感 を合わせることに重点がある
live_loop は再生中のコードを更新しながら繰り返し実行できるため、Sonic Pi を ライブパフォーマンス向けのツール にし、コードを可読なテキストであると同時に創作行為として捉えられるようにする
コードで制御する Sonic Pi
- Sonic Pi は、一般的なオーディオアプリケーションとは異なり、コードのみで制御されるソフトウェアシンセサイザー である
- 独自の制御言語は Ruby を拡張した ドメイン特化言語 (DSL) で、音楽やオーディオの概念を Ruby の文法上にマッピングしている
- 基本要素は Ruby の値と Sonic Pi の関数で構成される
:c4 のような音名は、対応する MIDI コードに対応するシンボルとして使われる
chord(:d3, :maj7) のように、ルート音とコード構造を引数に取ってコードを作れる
play は音を再生し、Ruby の sleep と組み合わせて時間間隔を制御する
play_pattern_timed は音の一覧と時間間隔を受け取り、反復再生コードを短く書けるようにする
- 例の目標は、外部 MIDI やサンプルなしで Sonic Pi の基本機能だけを使い、デモ用の伴奏 をコードで作ることである
- Sonic Pi アプリをインストールすれば、例のコードを貼り付けてそのまま試せ、言語ドキュメントやチュートリアルも標準で提供されている
Ruby 構文で反復パターンを作る
- 基本例では
use_bpm 70 で BPM を変更し、use_synth :pulse でデフォルトのサイン波の代わりに pulse シンセサイザー を使う
play :c2、sleep 0.25 を繰り返すと音を順番に再生でき、play_pattern_timed [ :c3, :d3, :e3, :g3 ], 0.25 と書けば同じ構造をより短く表現できる
- 制御言語は Ruby 上にあるため、関数やループでパターンを抽象化できる
arpeggiate 関数はルート音と任意の短調指定を受け取り、上行・下行パターンを作る
4.times の繰り返しで同じパターンを複数オクターブにまたがって実行する
- 条件文で短調のときに 3 度の音を変え、配列の
map でルート音に間隔を足して音の一覧を生成する
use_synth_defaults amp: 0.1 のようにシンセサイザーのデフォルトオプションを先に設定でき、play や play_pattern_timed に直接オプションを渡すこともできる
- Ruby では関数呼び出しの括弧は省略可能だが、
play chord(:a3, maj7) のような場合は区切りを明確にする必要があることもある
並列実行とレイヤリング
in_thread do ブロックは、Sonic Pi でコードを並列に実行するために使われる
- 異なる
in_thread ブロックを用意すると、2 つの別個の「楽器」を同時に実行できる
- 1 つのスレッドはアルペジオパターンを担当できる
- もう 1 つのスレッドは
use_synth :saw、メロディ配列、リズム配列を使って別の旋律を再生できる
play_pattern_timed は音の一覧だけでなく時間間隔の一覧も受け取れる
[1] * 2 は [1, 1] のように配列の長さを増やして内容を繰り返す
- ネストした配列は
play_pattern_timed がそのまま受け取れないため、flatten で 1 層の配列に平坦化して使う
- 合唱のような重なった音を作るときは、
ring(:c5, :e5) のように複数の音をまとめて扱える
flatten は ring 内部の一覧まで結合してしまうことがあるため、この場合は splat 演算子 * でリストの内容を親配列に展開する方法を使う
スコープ、エフェクト、合唱パートの構成
- ネストした
in_thread を使うと、外側のスコープのリズム断片を共有しつつ、内側の各スレッドごとに同じ変数名を再利用できる
- ソプラノやアルトのようなパートを別スレッドに分けると、各ブロックが独自のスコープを持つため、互いの変数に直接アクセスしない
with_fx :reverb, mix: 0.2 はエフェクトブロックを作り、信号の流れは最も内側のレイヤーから始まって外側の エフェクトチェーン へと進む
mix は wet 信号と dry 信号の混合度を表す
- wet 信号はエフェクトが適用された信号である
- dry 信号はエフェクトのない信号である
- グループ全体を 1 つのエフェクトで包む方法は DAW のバスのように使えるが、より深いルーティングは手動で行う必要があり、スコープの都合上、おおむね 上から下へ構成 する必要がある
- Sonic Pi は精密なプロダクションツールというより、楽器のように扱う 方が自然である
ADSR エンベロープで音の長さを合わせる
play_pattern_timed では sustain 値を追加できるため、長いコードと短いコードの持続時間を直接そろえられる
attack、decay、sustain、release は、音量が時間とともにどう変化するかを示す ADSR エンベロープ である
attack は 0 から最初のピークに達するまでの時間で、ギターの弦を弾いたりピアノハンマーが当たる瞬間のような初期アタックに相当する
decay は最初のピークから下がるまでの時間で、ピアノ鍵盤やギターの弦を押さえたままでも音が徐々に減っていく区間に相当する
sustain は安定した音量で音を保つ時間で、弓で鳴らす弦や長く伸ばすボーカルのような持続音に相当する
release は音を離してから実際に静かになるまでの時間である
- すべての音が ADSR の要素をすべて持つわけではない
- シンセサイザーの音色は生成された音なので、必ずしも初期の立ち上がりや残響があるとは限らない
- 自然楽器は演奏方法によって各要素の比率が変わる
- 例の合唱シミュレーションは、実在感よりも、音が正確な時間だけ保たれ、コードの間にわずかな分離が生まれるようにすることに集中している
choral_rings notes, sus 関数は音の一覧と持続時間を受け取り、ring(*notes) で同時に再生し、sustain と release を計算したうえで sleep sus により次のイベントまで待機する
live_loop でライブコーディングする
live_loop を使うと、コードを無期限に繰り返し実行できる
- Sonic Pi は ライブパフォーマンス を強く意識したツールであり、
live_loop 内のコードはプログラムを停止するまで動き続ける
- 再生中でもループの内容を変更でき、開始コマンドを再実行すると次の反復から更新されたループが適用される
- 既存の外側の
in_thread ループは live_loop :some_unique_name の形に置き換えられる
- エフェクトチェーンはループが回るたびに作り直されるため、エフェクトを多く重ねるほど、リソース面では
live_loop の外側に置く方が低コストである
- 最終例は
live_loop :harp と live_loop :choir で構成される
:harp ループは :square シンセサイザーと長さ 0.25 のアルペジオパターンを使う
:choir ループは :saw シンセサイザー、sleep 64、with_fx :reverb, mix: 0.75、choral_rings 関数呼び出しで合唱コードを再生する
プログラミングを創作行為として見る
- 技術的な作業は通常コンピュータサイエンスの観点から語られるが、プログラミングも 芸術 になり得る
- オーディオ生成や CSS レイアウトのように、意図的に創造的な成果物を作るときだけが芸術的なのではない
- コードは機械向けに最適化された命令であるだけでなく、他人や未来の自分が読む 整理されたテキスト でもある
- 良いコードとは、他人や 6 か月後の自分がひと目で理解できるように書かれたコードである
- ときにはコードの芸術性そのものが目的となり、Sonic Pi の例はその点を音楽制作を通して示している
1件のコメント
Hacker Newsのコメント
ライブコーディングに興味があるなら、Glicol(https://glicol.org)も試す価値がある
TidalCyclesもあるし、HaskellとRubyのDSLを作る力は本当に称賛に値する
Glicolでは、シンセサイザーに着想を得た文法、作曲速度、サウンドデザインのしやすさに焦点を当てている。既存のプログラミング習慣を持ち込みつつ、特定の言語に縛られないDSLを設計しようという発想だ
https://github.com/tidalcycles/strudel
数年前、YouTubeで誰かがSonic PiでTHX Deep Noteを再現する動画を見た
最初は何を作るのか説明せず、音の単一の「トーン」を作りながらそれをハチと呼んでいた。そのハチの音を少しずつ調整して聴かせたあと、最後に「このハチを数百匹作って、ハチの巣でどう聞こえるか見てみよう」という流れになり、その瞬間にDeep Noteが現れた
あの動画は本当に良かったのに、その後もう一度見つけられていない。リンクを知っている人がいたら共有してほしい
Rubyが輝く例の一つだと思う。メタプログラミングのおかげで、文法をほとんど英語のように見せられる
数年前、Sam Aaron、つまりSonic Piの作者がSonic Piでライブ演奏するのを見たことがある
コードがリアルタイムで変わるたびに音楽も進化し続けていて、実際とても良かった
Sonic Piを使うアーティストの例が気になるなら、以前DJ_Daveを知ったのだけれど、才能があって熟練した音楽家がこのツールをうまく使っている良い例だと思う
以前RedditでAMAもやっていたし、GitHubにも作品があるようだ
[1] https://www.youtube.com/watch?v=JiQHclg_648
[2] https://www.reddit.com/r/audius/comments/19dxmy6/hey_audius_...
[3] https://github.com/algorave-dave
Ruby開発者としては本当に格好よく見える。アルゴリズム生成音楽に使ったら面白そうだし、騒がしいgitリポジトリのイベントを何らかのアルゴリズム音楽に変えてみたいと思っていたので、これにはかなり合っていそうだ
ただ、複数の鍵盤楽器を持っている音楽家の立場からすると、曲を作るならMIDIキーボードで演奏したり、アコースティック楽器を録音してループさせたりすればよく、わざわざRubyで音楽シーケンスを書く理由はあまり分からない。Ruby DSLでやりたいことを入力できるのは分かるが、ピアノの鍵盤に比べてユーザー体験が良いとは言いにくい
言い換えれば、Logicの代わりとしてこれを使うことはたぶんない。もちろん個人的な好みではある
参考: http://listen.hatnote.com/
実際、「今はハ短調のアルペジオ、次はヘ長調のアルペジオ」のように考えることがあり、そうした意図を関数として非常に明快に作曲できる点が良い
音を一つ一つ演奏するより、アルゴリズムで生成することが核心に近い
それでも、普段なら使わないようなツールを変わった制約のために面白く活用するという点で、Hacker Newsの関心にはかなり合っている
気に入っているキーボードがあって理論上はこの作業に使えるのだが、個人的にいろいろ複雑な事情があって、楽器はしばらく全部倉庫に入っている
ちょうど数日前にSonic Piのことを考えていて、オンライン動画をいくつか見た
数年前に少し触ったことがあるだけで、そのときは昔ながらのOld MacDonaldやHot Cross Bunsのような曲を打ち込んでみた
音楽プログラミングの別のアプローチが気になるなら、ライブではないがPython向けのscamp[0]も見る価値がある
作者がYouTubeにこれで作った作品の動画をたくさん上げていて、たとえばFourier Eliseの動画[1]がある
[0] http://scamp.marcevanstein.com/
[1] https://www.youtube.com/watch?v=zq32bIud3OM
HTMLコメントが効いていないようだ。エディタが
--という2つのハイフンを—という1つのem dashに置き換えてしまったらしい私が一番好きなSonic Piのライブコーダー alsoknownasrox もおすすめ
https://www.youtube.com/watch?v=wXIvXrBQFkE