Sonic Piメモ


このサイトは、1994年7月24日に開設しましたが、2025年3月で終了致します。
移転先は未定ですが、決まり次第告知します。

Sonic Pi(ソニックパイ)は、音楽生成、ライブコーディング(ステージ上でのプログラミングによるDJ等)、子供から大人までのプログラミング入門(体験から入門、活用まで)に最適なプログラミング言語です。初等教育でのプログラミングの必修化に伴い、ScratchやPyonkeeなどのビジュアルプログラミング系言語が注目されていますが、音で動作がわかるサウンドプログラミング言語の Sonic Pi も日本での教育に利用する価値は十分にあります。下記にサンプルプログラム等を多数公開していますので情報処理教育等に活用下さい。
タイトルの波形画像の作り方は

英ケンブリッジ大のSam Aaron氏の作であり、Radsberry Pi, MacOSX, Windows, Linuxに対応しているオープンソースソフトウェアです。(MITライセンス)

StackoverflowのブログでのSonic Pi記事では由来から、仕組み、方向性まで簡潔にまとめられていました。2020.2
The live coding language that lets you be an actual rock star
Google翻訳で意味がわかる日本語となります。


小学校プログラミング教育の手引(第二版)文科省 2018.11
に、Sonic Piが適していそうな項目が追加されました。
B 学習指導要領に例示されてはいないが、学習指導要領に示される各教科等の内容を指導する中で実施するもの
B-① 音楽 (第4学年) 様々なリズム・パターンを組み合わせて音楽をつくることをプログラミングを通して学習する場面


2020.2末にV3.2が一般公開されました。音のスペクトル表示も見やすく洗練されています。
3.0での新機能の多くは、ブログrbnrpiで詳しく解説されています。
3.0で追加されたchordは、7-11,7-13,halfdim,halfdiminished,m7b5,maj,minの7つ
エフェクトにeq,tremolo、コマンドに、with_swing、set,get、サンプルプログラムにCloud Beatなども追加されています。

以下のプログラムを実行すると、新しく追加されたサンプル音を聴くことができます。
a=[:perc_bell2, :perc_door, :perc_impact1, :perc_impact2, :perc_swoosh, :ambi_sauna, :bd_mehackit, :sn_generic, :loop_3d_printer, :loop_drone_g_97, :loop_electric, :loop_mehackit1, :loop_mehackit2, :loop_perc1, :loop_perc2, :loop_weirdo]
for i in 0...a.length
sample a[i]
sleep sample_duration(a[i])
end

また、バージョン毎のsynth、sample,chord,scaleの数は、それぞれ、
42 164 71 73 (Ver.3.2)
42 164 70 73 (Ver.3.1)
42 129 70 73 (Ver.3.01)
42 129 63 73 (Ver.2.11)
39 129 63 71 (Ver.2.10)
と増加してきています。(下記の1行を各バージョンのSonic Piで実行しました。)
puts synth_names.length,all_sample_names.length,chord_names.length,scale_names.length


2017年9月末、Sonic Piについての新しい Q&A等の掲示板がオープンしました。in_thread



Sonic Piは、日本発で世界的に活用されているRuby言語(まつもとゆきひろ氏作)と音響合成言語のSuperCollider とQt等を使って作られています。
プログラムで本格的に音を出し音楽とすることのできる環境の中では、容易さや音質の面で最も優れていると思われます。
音を出し耳で確認しながらプログラミングができるので、英国の特にケンブリッジでは子供のプログラミング入門用(文法はほぼRuby)として大いに用いられているようで、世界中に広まりつつあります。

Sonic Piの操作画面



概要

下記の最初の項目のSonic PiメモPDFには、多くの情報を詰め込んでいます。
思いついたプログラムの中で簡単で興味深いものを順不同に並べています。情報教育その他で活用ください。

Sonic Pi4メモ (PDF、16頁) 使い方、リファレンス、注意点などいろいろ(自分用メモで加筆中、中身は順不同です.2023.10改訂)
「春の海」(宮城道雄)の演奏例とプログラム、その作製法
MIDIファイルやMuseScoreの楽譜データをSonic Pi用に変換する方法 MIDI -> MuseScore -> MusicXML ->(Processingによる変換プログラム) -> Sonic Pi
テキストファイルによるSonic Piのリアルタイム制御 (Ver.3になって必要なくなりました.)
Sonic PiからProcessingへの、ProcessingからSonic Piへの、テキストファイルを介した連携 (Ver.3になって必要なくなりました.)
Processingで操作するSonic Piのテルミン (Ver.3になって必要なくなりました.)
オフィシャルサイトのプログラム例の日本語解説
DTMF音のプログラム例
Sonic Piで竹内関数音楽 (たらいまわし関数、Takeuchi,Tak function)(再帰呼び出し,recursive call)
5行のプログラムで1000000桁円周率π音楽(5 lines Pi music
5行のプログラムで素数音楽(5 lines Prime Numbers Music)
・ランダム般若心経 ( 上記のPDF SonicPi_memo.pdf 内に記載 )
AudacityのエコーをSonic Piで (Audacity's Echo)
小鳥のさえずり (Little bird's song)
1/fゆらぎ的なカラスの鳴き声(1/f fluctuating crow)
マキシマイザー的な使い方 (Maximizer)
n平均律音楽 (12以外の平均律で演奏する.微分音) 例「かえるのうた」「フレールジャック」(Microtonal music)
DNA ゲノム音楽 (MIT-Media Lab.所長伊藤穣一氏の遺伝子塩基配列を使用) (DNA Gene music)
バブルソート音楽.データの可聴化 (Bubble Sort sounds)
五度円(五度圏)上を廻るコード (Circle of Fifth chords sound)
Gapminderの平均余命データを可聴化 (社会問題の可聴化例) (Life Expectancy data sounds)
ピタゴラスのコンマのずれを聞く (Pythagorean Comma sounds) 2017.4
リサージュ図形のいろいろ (Lissajous) 2017.5
Sonic Piによる奏者の発音タイミングデータの活用 (Miles Davis "So What")
Sonic Piによるドビュッシーのシリンクスの演奏。5人の巨匠の比較。 Debussy,Syrinx
ランダムな音程が元の旋律に変化、音のモーフィング (Random to Melody、Morphing; Hey Jude)
最も簡単なライブコーディング体験法 (The Simplest Live Coding Experience)
LibreOfficeのImpress(MS-OfficのPowerPointに相当)のサウンドをSonic Piから直接鳴らす
音感テスト(音程) Check of pitch perception 2017.7
等速で変化するポルタメント (Portamento changing with constant speed)
パーリンノイズ音楽 (Perlin Noise Music) 2017.8
ニュートン法による方程式の解の音楽 (Equation Solving Music, Newton Method)
波形アートの作成法(このページのタイトル画像、Sonic Piは使いません) wav2vec,Inkscape (Making of Sound Wave Art)
将棋の棋譜を音楽化(Shogi Music) 藤井聡太、羽生善治、Ponanzaなど 2018.4
2つの交差したポルタメント(Two Intersected Portamentos) 2018.4
囲碁の棋譜を音楽化(Go Music) Google Alpha Go、李世石、柯潔ら 2018.4
コードをアルペジオで鳴らす例 PPM(Peter Paul & Mary) の The Cruel War (悲惨な戦争) 2018.4
重音のあるアルペジオの例 Arpeggios with overlapping sounds. 2018.4
タブ譜をSonic Piで鳴らす方法の例 Eagles - Hotel California intro., 2018.4
テキスト表示されたタブ譜を簡単に鳴らす方法 Led Zeppelin - Stair to Heaven, 2018.4
太陽光スペクトルの音(スペクトルの可聴化) Sun Light Spectrum Sounds, 2018.5
和音の音程の同時移動 Simultaneous movement of chords, 2018.6
THX ディープ・ノート(映画の効果音)の再現の試み Deep Note, my trial, 2018.6
PowerPoint 2016(mac) の画面切り替えサウンドを鳴らす PowerPoint2016 sounds, 2018.6
MuseScoreのDrumline機能拡張のサンプリング音1026個を鳴らす. 2018.11
macOSのsayコマンドで喋らせる. 2018.12
1次元セルオートマトンによる音 Elementary Cellular Automaton Sounds, 2019.2
徐々に倍音が加わる音 Gradually Increasing Harmonics Sounds, 2019.2
sleep時間のベンチマーク, Benchmark of the "sleep" time, 2019.4
ORCA (ORCΛ) から Sonic Pi に値を送る方法 2019.6
順列音楽 Permutation Music, 2019.7
ピアノの音を伸ばす decay: 2019.8
onset命令で分割可能な音 2019.8
スティーブ・ライヒの"Reed Phase"風な、鼻笛による"Nose Flute Phase" Inspired by Steve Reich - Reed Phase, 2019.10
日本語変数名が使えます Japanese variable names can be used. 2019.12
10進数をn音階として鳴らす Convert a decimal to n scales. 2019.12
画像を線画SVG音楽にImage to SVG Music (linedraw) 2020.2
新型コロナウィルス遺伝子音楽 (Coronavirus Genome Music) 2020.4
QueenのPlay The Gameのイントロのシンバル音の逆再生をSonic Piで 2021.1
画像を変換して、スペクトログラムが元の画像となるような音を生成するプログラム 2022.6
全てのスケール151を鳴らし、OSCでProcessingに送って五線譜表示をする 2023.7
ハノンピアノ教本の1番から20番を鳴らす(Hanon piano exercises No.1 - No.20) 2023.8
Sonic Piの10個のバッファを1つのテキストファイルにバックアップする 2023.8
正弦波の場合 amp:2.5 を越えると波形が歪み、音も濁ります。 2023.9
ハノンピアノ教本 60番(Hanon piano exercises No.60) 2023.9



2016.11.5 オープンソースカンファレンス(OSC Tokyo/Fall)で「授業で使ってみた音関連OSS」というタイトルで「Sonic Pi」を中心にセミナー講演をしました。資料

高機能なオープンソースのシンセサイザーソフトSurge XTの解説、入門 SurgeXTメモ 2024.1.23


紹介

mehackit (Creative high school technology courses in the Nordics.) が、Processingの操作パネルで操作し、Sonic Piを鳴らすシンセサイザーをオープンソースで公開しています。
Processingの画面をマウスで操作するだけで、いろいろなビートを操作することができ、大変興味深いものです。

下図、左側がProcessingのプログラムを実行すると現れる操作画面。     右側がSonic Piのプログラム


手順
プログラミング言語のProcessingがインストールしてあることが前提です。
Githubの mehackit/technomachine: Processing + Sonic Pi Techno Machine https://github.com/mehackit/technomachineからプログラムを入手します。
右側にある[Clone or download]ボタンから "technomachine-master.zip" をダウンロードし、zipファイルを解答した中にあるフォルダ[Sonic_Pi_Techno_Machine]をProcessingのスケッチ用フォルダに入れ、ファイル"Sonic Pi Techno Machine.rb"をSonic Piで開き、両者を実行(どちらが先でも可のようです)すると、上記の図のようにProcessingのSonic Pi_Techno Machineウィンドウで、Sonic Piを操作できるようになります。

なお、実行前に、Processing側では、ライブラリーのcontrolP5とoscP5をインストールしておくことが必要です。
 メニューの[スケッチ]→[ライブラリーをインポート]→[ライブラリを追加] という操作でライブラリーのインストールできます。
Sonic Piは、Ver.2.11.1が必要です。
Processing3.3 macOSで動作確認済. Windowsでも問題ないと思われます。

Processingのプログラムは450行程度であり、その中身も多数のボタン操作の記述がほとんどなので、これを元に改造することも容易でしょう.



「春の海」のSonic Piによる演奏例


宮城道雄の
「春の海」(MuseScoreファイルのHarunoumi_v2c.mscz)(著作権は消滅)を五線譜ソフトMuseScoreを使ってパート毎に(琴は右手と左手も)別々のMusicXMLファイルにエクスポートし、さらにSonic Pi用に変換(自作のProcessing言語による下記のプログラムで)してみました。
一部、トレモロや、アルペジオを省略している部分があります。
# 琴の右手と左手の分別は、左手の音を伸ばす必要があり、右手のデータとできない部分のみを左手としています。
# Harunoumi_v2c.msczでは、スピートの指定部分に何らかの音符か休符がないと、XML作成時にスピード指定が消えてしまう(変換プログラムが対応していない)ので、尺八、琴(右、左)には、音符や休符の長さなどを変更している部分があります。

(Sonic Pi ForumでRobin Newmanさんに教わった) CueとSyncを使った実行方法によって全曲を連続して演奏することができます。
下記の4つのSonic Piのプログラムを別々のBufferに入れ、最初に[パート3]を入れたBufferでRunして下さい。(音は出ずにsyncだけが登録されます) 次に[パート2b]、その次に[パート2a]のBufferをRunして下さい。同様にsyncだけが登録されて音は出ません。最後に[パート1]を実行すると、連続して全曲が演奏されます。
再度連続演奏をする場合には、[パート3]のRunからの手順を繰り返す必要があります。

Sonic Pi用プログラム (拡張子はRubyと同じ.rb)
春の海(Harunoumi_1.rb) パート1
春の海(Harunoumi_2a.rb) パート2a
春の海(Harunoumi_2b.rb) パート2b
春の海(Harunoumi_3.rb) パート3

上記を連続して演奏した MP3ファイル
Harunoumi_SonicPi.mp3 (CC-BY)

#(なお、これで完成というわけではなく、このデータを元にプログラミングによって、自在に音を加工してゆくことの方に意味があります。)
上記のパート2a以降をSonic Pi上で単独に演奏したい場合には、各プログラム中に3箇所あるsyncの行の行頭に#を入れてコメント化して下さい。cueの行はそのままで問題ありません。

参考ファイル
MuseScoreで出力した3つのMusic-XMLファイル(これをProcessingプログラムでSonic Piに変換しました。)
MusicXMLファイル(尺八 Shakuhachi)
MusicXMLファイル(琴 右手 Koto Right)
MusicXMLファイル(琴 左手 Koto Left)

・元の 春の海(Haru no Umi, The Sea in Spring/The Sea of Spring) (harunoumi_v2b.mid) MIDIファイル


Processing による MusicXML to Sonic Pi 変換プログラム

上記の春の海の変換に仕様した、MuseScoreで出力したMusicXMLファイルを読み込み、Sonic Piのコードを出力する
Processing言語のプログラムを公開します。
Processingは、Java系の言語であり、データの可視化、アート作品の生成などで幅広く用いられていますが、ここではグラフィックス機能は一切使っていません。

MusicXMLtoSonicPi_01.pde , ( Licence CC-BY )

Sonic Piは、主にEDM(Electric Dance Music)やノイズ系の音楽のDJで用いられていますが、既存の音楽を演奏するには、play文を一から作らなければなりません。教育用に用いる場合も、音楽データを利用できると、活用の幅が広がります。

このプログラムは、とりあえず動作するだけの汚いスパゲティープログラムで、既に自分でも修正は困難を極めます。
入力ファイル名(??.xml)は、プログラム中に書き込んで下さい。
Sonic Piのプログラムは、Processingの標準出力に表示されますので、コピペして下さい。
出力される data??.txt 等のファイルは、不要です。
MusicXMLファイルを作成する前の入力データとする、MuseScoreのスコア譜は、パート譜に分割して1パートだけにして下さい。さらにMuseScore内のパート1-4 を使用している場合は1のみとして下さい。
# MuseScore上で、あるパートだけの音符や休符の選択(右クリックから[選択]→[詳細]→[同一の声部]) やパート1とパート2の交換(メニューの[編集]→[声部]) ができます。
装飾音符にはある程度対応していて、1/16拍とします。(多数の装飾音符が並ぶと次の音符の長さが負になります。)
コードやタイには対応します。タイの付いたコードにはあまり対応していません。
ダブルシャープ/フラットには対応していませんので、MuseScoreでダブル#bなしの移調を2回繰り返して元に戻すことによって削除して下さい。

MIDIファイルがあれば、MuseScoreで読み込んで、さらにMusicXMLに書き出してSonic Piに変換することができますので、Sonic Piを容易に活用するツールとなります。


使用した
Sonic Pi (MIT Licence)
MuseScore (GPL Licence)
Processing (GPL Licence)
は、いずれもオープンソースであり無償で公開されています。



変換操作の仕組みについて
MuseScoreで春の海は、下記のように入力されています。

これを、MuseScore上でMusicXML形式にエクスポートしたファイルの、尺八パートの冒頭と最初の2音付近は、下記のようになっています。 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd"> <score-partwise> <identification> <rights>&lt;font size=&quot;8&quot;/&gt;春の海</rights> <encoding> <software>MuseScore 2.0.3</software> === === === === <note default-x="94.20" default-y="-10.00"> <pitch> <step>D</step> <octave>5</octave> </pitch> <duration>12</duration> <voice>1</voice> <type>eighth</type> <stem>down</stem> </note> </measure> <measure number="3" width="162.40"> <note default-x="12.00" default-y="-5.00"> <pitch> <step>E</step> <octave>5</octave> </pitch> <duration>48</duration> <voice>1</voice> <type>half</type> <stem>down</stem> </note> === === これらの中から、音符の音程を表している <step>D</step> や、音符の長さ <duration>12</duration> などを取り出してSonic Pi用に変換した Sonic Pi のコードの一部が下記です。(拡張子.rbのファイル) (ここで、a,bは2次元配列です。) a[0]=[:r,:r,:r,:r,:D5,:E5, ... ] # 音程 b[0]=[4.0,2.0,1.0,0.5,0.5,2.0, ... ] # 長さ c=[60, ... ] # テンポ use_synth :dpulse # シンセ音源に dpulseを用いる for i in 0...a.length # a配列のi要素の数だけ繰り返す use_bpm c[i] # テンポを指定する for j in 0...a[i].length # a[i]のjの要素の数だけ繰り返す play a[i][j], sustain: b[i][j]*0.6, amp: 0.3 # 配列a[i]のj番目の要素を音程として音源を鳴らす。 sleep b[i][j] # 配列b[i]のj番目の要素の数値を拍として間を置く. end end
---
上記の変換プログラムを英国のRobin Newmanさんが自身のブログ(Raspberry Pi関連,Sonic Pi関連で有名)で詳細に(このページよりもずっと詳細に丁寧に)解説してくれました。
また、このプログラムを活用し、MIDIデータから変換し、Sonic Piで演奏した23分もの大曲など数曲を公開されています。

Converting MusicXML or midi files to work with Sonic Pi rbnrpi ブログ
Fugue in F by Sidney Newman played by Sonic Pi(23分) Youtube




テキストファイルによる、Sonic Piのリアルタイムコントロール

適当な場所にMIDIノート番号の数字を一つだけ入れたテキストファイルを作成し SonicPi_Text_MidiNo.txt という名前で保存します。
同様に、音量とするamp値の数字を一つだけ入れたテキストファイルを作成し SonicPi_Text_Amp.txt という名前で保存します。
同様に、sleep値とする数字を一つだけ入れたテキストファイルを作成し SonicPi_Text_Sleep.txt という名前で保存します。
loop do
  a=File.read("/Users/???/SonicPi_Text_MidiNo.txt").to_f # 保存したファイルのフルパス名を与えます.
  b=File.read("/Users/???/SonicPi_Text_Amp.txt").to_f
  c=File.read("/Users/???/SonicPi_Text_Sleep.txt").to_f
  play a,amp: b
  sleep c
end
例
ファイル SonicPi_Text_MidiNo.txt の中身の例は、 60。  60.5も可能
ファイル SonicPi_Text_Amp.txt の中身の例は、 1.0
ファイル SonicPi_Text_Sleep.txt の中身の例は 0.5
Sonic PiのプログラムをRunした後、テキストエディタ等でファイルの中身を書き換えて、"その都度保存"すると、Sonic Piの動作をリアルタイムに制御できます。

参考 rANGEL (PDF)


Sonic PiとProcessing間によるテキストファイルを介したリアルタイムコントロール 例

上記のSonic Piの制御に用いたテキストファイルを、Processingでの画面上のマウスクリックの座標等から算出し、テキストファイルに書き出すことにより作成します。
逆に、Sonic Pi側で音程をテキストファイルに出力し、Processingで読み込むことにより、グラフィックスを作成することができます。

Sonic Pi --> Processing の例

Sonic Piで同時に鳴るランダムな2つの音の音程と音量をx,y,rとして3つのファイル(場所はProcessingプログラムのフォルダ中)に書き出す。 Processingで、ファイルから値を読み込んで、x、yを中心とし、rを半径とした円をランダムな色で描く。 リアルタイムではあるが、書き出す側と読み込む側の同期はしていない。 Sonic Pi側のプログラム use_debug false use_random_seed 0 # 乱数の種の番号。デフォルトは0 loop do x=rrand(48,96) # MIDIノート番号48〜96 (C3〜C6)の音を実数の乱数で生成。x座標とする y=rrand(48,96) # 同上。y座標とする。 r=rrand(0.1,5) # 0.1〜5.0の実数の乱数。音量とする。 File.write("Processingプログラムへのパス/SonicPi_to_Processing/SPtest1.txt",x) # xの値をProcessingのプログラムフォルダ内のファイルに書き出す。 File.write("Processingプログラムへのパス/SonicPi_to_Processing/SPtest2.txt",y) # yの値を 同上 File.write("Processingプログラムへのパス/SonicPi_to_Processing/SPtest3.txt",r) # rの値を 同上 play [x,y],amp:r # x,yを同時に、音量rで鳴らす。 sleep 0.25 # 0.25拍置く(デフォルト速度では0.25秒) end Processing側のプログラム // Sonic Piの2つの音とその強さの値をProcessingのdataディレクトリにファイル出力し、読み込んでグラフィック表示する。 // Sonic Pi側の書き込み中にProcessing側で読み込むと値がないファイルとなってエラーするため、読み込んだ配列の長さが0かどうかを調べている。 void setup() { size(600, 600); # 画面サイズ background(0); # 背景色を黒に strokeWeight(5); # 線の太さを5ピクセルに colorMode(HSB); # 色モデルをHSBに frameRate(5); # 画面の更新速度を5回/秒に } void draw() { float x=0,y=0,r=0; fill(0,2); # 塗り色を黒、透明度を2に(0が完全透明,255が不透明) rect(-5,-5,width+10,height+10); # 画面全体を薄い半透明の黒の四角形で塗りつぶす String[] s1 = loadStrings("SPtest1.txt"); # SonicPiで書き込んでいる値をファイルから読み込む,x String[] s2 = loadStrings("SPtest2.txt"); # 同上,y String[] s3 = loadStrings("SPtest3.txt"); # 同上,r if(s1.length>0) x=(float(s1[0])-48+1)*width/48.; # 画面サイズに合わせてx座標を作成する。ファイルが空の場合は配列の長さがゼロとなっているので、座標を生成しない。 if(s2.length>0) y=(float(s2[0])-48+1)*height/48.; # 同上 y if(s3.length>0) r=(float(s3[0]))*20.0; # 同上、半径r fill(random(255),255,255); # 塗り色の色相をランダムに設定。彩度と明度は最大。 stroke(random(255),255,255); # 同上、線の色 ellipse(x, y, r, r); # 円を描く // println(x+" "+y+" "+r); }

Processing --> Sonic Pi の例

Processing側で、マウスで画面をクリックした場所に円を描く。円の座標を2つの音程とし、円の半径はクリックしていた時間から生成し、それを音量とする。これら3つの値を3つのファイルに書き出す。 Sonic Pi側で3つのファイルを読み込み、2つの音を少しずらして鳴らし、読み込んだ音量で鳴らす。鳴らす間隔は1/4拍に固定。 リアルタイムではあるが、2つのプログラムは、同期していない。 Processing側 // Processing_to_SonicPi PrintWriter fx,fy,fr; float x,y,r; float xmin=48,xmax=96; float msec; void setup(){ size(600,600); background(255); stroke(255,0,0); strokeWeight(1); } void draw(){ fill(255,255,255,5); // 塗り色を白色の透明度5に設定 rect(-5,-5,width+10,height+10); // 半透明の白色の四角形を画面全体に描く } void mousePressed(){ msec=millis(); // マウスボタンがクリックされた時間を記憶する。 } void mouseReleased(){ // マウスボタンが離された時に実行される noFill(); x=mouseX*(xmax-xmin)/width+xmin; // マウスのx座標から音程を生成する. y=mouseY*(xmax-xmin)/height+xmin; // マウスのy座標から音程を生成する. r=map(millis()-msec , 0 , 1000, 0 , 5); // マウスボタンが押されていた時間から音量を生成する. if(r>5) r=5; // 音量の最大値を5とする strokeWeight(r*2); // 線の太さを音量から生成する ellipse(mouseX,mouseY,r*30,r*30); // マウスの座標に音量を直径として円を描く println(x+" "+y+" "+r); fx=createWriter("SPtest1.txt"); // Sonic Piに渡す値を保存するファイルを作成する.x用 fy=createWriter("SPtest2.txt"); // 同上、y用 fr=createWriter("SPtest3.txt"); // 同上、r用 fx.println(x); // xの値をファイルに出力する fy.println(y); // yの値を同上 fr.println(r); // rの値を同上 fx.flush(); // バッファからファイルに書き込む fy.flush(); fr.flush(); fx.close(); // ファイルを閉じる fy.close(); fr.close(); } Sonic Pi側 # Processing_to_SonicPi use_synth :dsaw # 音源の指定 loop do # 無限ループ x=File.open("Processingプログラムへのパス/Processing_to_SonicPi/SPtest1.txt").read.split(" ") # Processingのプログラムフォルダからxの値を読み込む y=File.open("Processingプログラムへのパス/Processing_to_SonicPi/SPtest2.txt").read.split(" ") r=File.open("Processingプログラムへのパス/Processing_to_SonicPi/SPtest3.txt").read.split(" ") play x[0].to_f, amp: r[0].to_f # x座標に元ずく音を音量rで鳴らす sleep 0.05 # 0.05拍置く play y[0].to_f, amp: r[0].to_f # y座標に元ずく音を音量rで鳴らす sleep 0.2 # 0.2拍置く end # .read.split(" ") は、データをスペースで区切って配列の要素にする機能ですが、行末コードによるエラーがこれにによって解消したので、そのまま使用しています。

上記の原理で作ったProcessingでのマウスの動きによって動作するSonic Piのテルミン(Thermin)は、Sonic Piメモ(PDF)内に記載しています。

KinectやLeapMotionによってより手の動きを取得して本物に近い操作としたり、Aruduino等で他のハードウェアと組み合わせて音を出すような仕組みにすることも容易にできるでしょう。





Sonic Pi 本家で、下記のコードの音を聞くことができます。(Topページの下部で)

Sonic Pi Examples (Officialページのサンプルプログラム) の日本語コメントによる解説

Haunted Bells

loop do # 無限ループを開始 sample :perc_bell, rate: (rrand 0.125, 1.5) # サンプル音源の:per_bellを0.125〜1.5のランダムな速度で再生 sleep rrand(0, 2) # 間隔をランダムに0〜2拍あける. end # 無限ループはここまで

Pentatonic Bleeps

with_fx :reverb, mix: 0.2 do # 全体にエフェクトのリバーブを0.2だけかける. loop do # 無限ループ開始 play scale(:Eb2, :major_pentatonic, num_octaves: 3).choose, release: 0.1, amp: rand # E♭のメジャー・ペンタトニックスケールのオクターブ2から3オクターブ分の音から1音をランダムに選び、余韻0.1拍、強さ1未満で、デフォルトの:beep音(サイン波)を鳴らす。 sleep 0.1 # 0.1拍の間をあける. end # 無限ループここまで end # エフェクトここまで

Tron Bikes

loop do # 無限ループ開始 with_synth :dsaw do # :dsaw 鋸型波形を使う with_fx(:slicer, phase: [0.25,0.125].choose) do # スライサを使い、間隔を0.25拍または0.125拍とする. with_fx(:reverb, room: 0.5, mix: 0.3) do # リバーブを使い、部屋サイズを0.5、混合度合いを0.3とする. start_note = chord([:b1, :b2, :e1, :e2, :b3, :e3].choose, :minor).choose # 開始音を、マイナーコード6種から選んだ一つのコード、からさらに選んだ1音とする. final_note = chord([:b1, :b2, :e1, :e2, :b3, :e3].choose, :minor).choose # 終了音 同上 p = play start_note, release: 8, note_slide: 4, cutoff: 30, cutoff_slide: 4, detune: rrand(0, 0.2), pan: rrand(-1, 0), pan_slide: rrand(4, 8) # 開始音を余韻8拍、前の音からの音程の移動に4拍、ローパスフィルタのカットオフ高さを30(ノート番号)、前の音のカットオフ値からの移動に4拍、音程0.2未満ずらした音を混ぜる、パンは左〜中央、パンの移動に4〜8拍かける. control p, note: final_note, cutoff: rrand(80, 120), pan: rrand(0, 1) # 終了音に対して設定に従い連続的に移動する。カットオフ値は80〜120、パンは、中央から右 end end end sleep 8 # 8拍の間を置く end # 無限ループ終わり

Wob Rhythm

with_fx :reverb do # リバーブをかける in_thread do # 他と並行動作させる. loop do # 無限ループ開始 r = [0.5, 1.0/3, 3.0/5].choose # 音程となる再生速度を3種からランダムに選ぶ 8.times do # 8回繰り返す sample :ambi_choir, rate: r, pan: rrand(-1, 1) # サンプリング音源の:ambi_choirを速度rで、左右のパンはランダムにして再生する。 sleep 0.5 # 0.5拍の間を置く end end end end # メインプログラム with_fx :wobble, phase: 2 do |w| # wobbleの間隔を2拍とし、2拍目のドラム音にモジュレーションをかける. # |w|は使われていないがsleepの後にcotrol w, phase: rrand(0.5, 4) 等により変化を増やせる. with_fx :echo, mix: 0.6 do # エコーを混合度合0.6で適用し、ドラムが減衰しながら3回鳴っているようする. loop do # 無限ループ開始 sample :drum_heavy_kick # サンプル音源のdrum_heavy_kickを鳴らす. sample :bass_hit_c, rate: 0.8, amp: 0.4 # 同時に bass_hit_cを、再生速度0.8、強さ0.4で鳴らす. sleep 1 # 1拍置く end # 無限ループはここまで end # エコーはここまで end # wobbleはここまで

Ocean Waves

with_fx :reverb, mix: 0.5 do # リバーブを混同度合い0.5で適用する loop do # 無限ループ開始 s = synth [:bnoise, :cnoise, :gnoise].choose, amp: rrand(0.5, 1.5), attack: rrand(0, 4), sustain: rrand(0, 2), release: rrand(1, 3), cutoff_slide: rrand(0, 3), cutoff: rrand(60, 80), pan: rrand(-1, 1), pan_slide: 1, amp: rrand(0.5, 1) # 3種のノイズ音源から一つ選び、強さを0.5〜1.5、音の立ち上がり時間を0〜4拍、音の持続時間を0〜2拍、余韻時間を1〜3拍、ローパスフィルタのカットオフ音程の変化時間を0〜3拍、カットオフ音程を60〜80、パンを-1〜1、パンの変化に要する時間を1拍、強さを0.5〜1とする。 control s, pan: rrand(-1, 1), cutoff: rrand(60, 115) # 上記設定から音源をパン-1〜1、カットオフ音程60〜115に変化させる. sleep rrand(2, 3) # 2〜3拍置く. end end

IDM Breakbeat

define :play_bb do |n| # 関数play_bb を定義する.nの値が与えられて呼び出される. sample :drum_heavy_kick # サンプリング音源のdrum_heavy_kickを再生する. sample :ambi_drone, rate: [0.25, 0.5, 0.125, 1].choose, amp: 0.25 if rand < 0.125 # randが0.125以下の場合(1/8の確率で)この行を実行する. # ambi_droneを再生速度4種のいずれかで、強さ0.25で再生する. sample :ambi_lunar_land, rate: [0.5, 0.125, 1, -1, -0.5].choose, amp: 0.25 if rand < 0.125 # 同上 ambi_lunar_landを1/8の確率で再生する. sample :loop_amen, attack: 0, release: 0.05, start: 1 - (1.0 / n), rate: [1,1,1,1,1,1,-1].choose # loop_amenを立ち上がり時間0、余韻時間0.05拍、音源の開始位置1 - (1.0 / n)、再生速度は、7種から選ばれる.1/7の確率で、-1となり、逆再生(スクラッチ音)となる. sleep sample_duration(:loop_amen) / n # サンプル音源loop_amenの長さの半分の時間置く. end loop {play_bb([1,2,4,8,16].choose)} # 無限ループの中で、定義された関数をnの値を5種の中から選んで実行する. # 無限ループは、loop{ } とも書ける. # 関数の引数は、( )で囲っても良い.

Acid Walk

in_thread do # 並列実行するプログラム. use_synth :fm # fm 音源を使う sleep 2 # 2拍置く loop do # 無限ループ開始 28.times do # 28回繰り返す sample :drum_bass_hard, amp: 0.8 # サンプリング音源のdrum_bass_hardを強さ0.8で再生する. sleep 0.25 # 0.25拍置く. play :e2, release: 0.2 # 2オクターブ目のEの音を減衰0.2拍で鳴らす. sample :elec_cymbal, rate: 12, amp: 0.6 # サンプリング音源のelec_cymbalを再生速度12倍、強さ0.6で再生する. sleep 0.25 # 0.25拍置く. end # ここまでを28回繰り返す sleep 4 # 4拍置く. end end # メインプログラム use_synth :tb303 # 音源をth303にする with_fx :reverb do |rev| # リバーブを設定する. loop do # 無限ループ開始 control rev, mix: rrand(0, 0.3) # リバーブのmix値を0〜0.3とする with_fx :slicer, phase: 0.125 do # 1/8拍間隔で音をスライスする sample :ambi_lunar_land, sustain: 0, release: 8, amp: 2 end control rev, mix: rrand(0, 0.6) # リバーブのmix値を0〜0.6に変更する. r = rrand(0.05, 0.3) # 余韻長さとするrを0.05〜0.3とする. 64.times do # 64回繰り返す play chord(:e3, :minor).choose, release: r, cutoff: rrand(50, 90), amp: 0.5 # Eのオクターブ3のマイナーコードから1音を任意に選び、余韻長さr、ローパスフィルタのカットオフ音程50〜90、強さ0.5で鳴らす sleep 0.125 end control rev, mix: rrand(0, 0.6) # リバーブのmix値を0〜0.6に変更する. r = rrand(0.1, 0.2) with_synth :prophet do 32.times do sleep 0.125 play chord(:a3, :m7).choose, release: r, cutoff: rrand(40, 130), amp: 0.7 end end control rev, mix: rrand(0, 0.6) # リバーブのmix値を0〜0.6に変更する. r = rrand(0.05, 0.3) 32.times do play chord(:e3, :minor).choose, release: r, cutoff: rrand(110, 130), amp: 0.4 sleep 0.125 end control rev, mix: rrand(0, 0.6) # リバーブのmix値を0〜0.6に変更する. with_fx :echo, phase: 0.25, decay: 8 do # エコーを位相0.25、減衰を8拍とする. 16.times do # 16回繰り返す play chord([:e2, :e3, :e4].choose, :m7).choose, release: 0.05, cutoff: rrand(50, 129), amp: 0.5 sleep 0.125 end # 16回のループはここまで end # 無限ループはここまで end # リバーブはここまで end # tb303音源はここまで

以上、Sonic Piの公式ページのサンプルプログラムの解説




試しに作ってみた小プログラム集

Sonic Piでプッシュフォンのダイアル音を鳴らす. DTMF tone

# DTMF sound (Dual-Tone Multi-Frequency) dial="0123456789ABCD*#" # 鳴らしたいプッシュボタンを文字列で与える hi=[1209,1336,1477,1633] # 高音側の周波数 lo=[697,770,852,941] # 低音側の周波数 pushButton=[["1","2","3","A"], # プッシュボタンの並び ["4","5","6","B"], ["7","8","9","C"], ["*","0","#","D"]] define :dtmfPlay do |d| # d に鳴らしたいボタンの文字が入り、音を鳴らす関数 for i in 0...4 # lo for j in 0...4 # hi if(d == pushButton[i][j]) # 鳴らしたいボタンに一致する並びを調べる play hz_to_midi(lo[i]),attack: 0.05 ,release: 0.3 # 低音側の音を鳴らす、アタックは弱め、余韻は短め play hz_to_midi(hi[j]),attack: 0.05 ,release: 0.3 # 高音側の音を鳴らす(2音は同時に鳴る) end end end end for i in 0...dial.length puts dial[i] dtmfPlay dial[i] # dialの配列から1文字取り出して、音を鳴らす関数を呼ぶ sleep 0.5 # 間隔を与える end


Sonic Piで竹内関数音楽(たらいまわし関数,Tarai,Tak function)

関数(メソッド)を巧みに再帰呼び出ししている関数です。
いろいろな言語で試みられていますが、Sonic Piで記述するのが最も容易だと思われます。

use_bpm 130
define :tarai do |x,y,z|
  a=[:D4,:E4,:F4,:G4,:A4,:B4,:C5,:D5,:E5,:F5,:G5,:A5,:B5]
  2.times do
    puts x,y,z
    play_pattern_timed [a[x+1],a[x+1]+12,a[y+1],a[y+1]+12,a[z+1],a[z+1]+12,a[y+1],a[y+1]+12],0.25
  end
  n=n+1
  if(x<=y)
    return y
  else
    return tarai( tarai(x-1,y,z), tarai(y-1,z,x), tarai(z-1,x,y))
  end
end

tarai 10,5,0


最後のreturn文の()は省けないようです。
関数の定義と呼び出しは、
define :tarai do |x,y,z|
tarai 10,5,0
を
define tarai(x,y,z)
tarai(10,5,0)
と書いても問題ないようです。

参考
Wikipediaの竹内関数
Tarai Function Music aike氏
竹内関数で音楽生成 aike氏
ハッカーの遺言状──竹内郁雄の徒然苔 第18回:問題児も悪くない


再帰呼び出しを使った簡単なプログラム例
最小公倍数(例では12と18の)を求める.
# ( )を使わない表記では、
define :gcd do |a,b|
  return a if b == 0
  gcd b, a % b
end
puts gcd 12,18

# ( )を使う表記では、
def gcd(a, b)
  return a if b == 0
  gcd(b, a % b)
end
puts gcd(12,18)



5行のプログラムで、1000000桁や10000000桁の円周率音楽, Pi Music


いろいろな数字を用いた音楽が作られていますが、その中でも円周率は古くから多くの人によって音楽とされているようです。 Sonic Piでは、Rubyのファイル読み込み機能を使って数字や文字をファイルから簡単に読み込むことができます。 複数行のファイルの場合は、行単位に配列の要素として読み込むことができます。ここでは、円周率を全て1行に並べているテキストファイルを一つの文字列として読み込んで利用しています。
読み込んだ文字列から、一文字づつを取り出して、整数に変換してから値を2倍して、中央のド(MIDIノート番号60)に加えて音程として使用しています。

円周率100万桁が改行なしに入力されている"pi1000000.txt"は、
https://www.angio.net/pi/digits.html から入手できます。
プログラムは、下記の5行と非常に簡単に記述できます。
pi=File.open("ファイル pi1000000.txt へのパス").read  # ファイルの置き場所は任意. デスクトップ等でも可.
for i in 0...pi.length
  play pi.slice(i, 1).to_i*2+60
  sleep 0.125
end
この設定では、演奏の完了には約37時間かかります。

二桁ずつ取り出すなどの改良も容易です。
for i in (0...pi.length).step(2)
  play pi.slice(i, 2).to_i+40
  sleep 0.125
end
なお、3.14の2文字目のピリオドは無視しています。
scaleやchordで音を与えるなどの工夫も容易にできます。

さらに、10000000桁(1000万桁)にしたい場合には、ここから Pi_10000000.txt が入手できます。


5行のプログラムで、素数音楽, Prime Numbers Music

素数の列(2から15,485,863までの100万個)をファイルから読み込み、前後の数値の差をC4に加えて鳴らします。

ファイルの準備
primes1.txt を http://primes.utm.edu/lists/small/millions/primes1.zip から入手して展開して下さい。
macOSのターミナル、Windows10のコマンドプロンプト(bash付), Linux または UNIXのターミナルで下記のコマンドにより、ファイル中の不要な行とスペース、改行コードを削除し、p1.txtファイルを生成します。
sed -e '1,2d' primes1.txt| tr -d '\n'| tr -d '\r'| sed -e 's/ */ /g'> p1.txt
p1.txtは8.2MBになります。

Sonic Piのプログラムは、
prime=File.open("ファイル p1.txt へのパス").read.split(" ")
for i in 0...prime.length-1
  play 60+prime[i+1].to_i-prime[i].to_i
  sleep 0.125
end


AudacityのエコーをSonic Piで

Sonic PiのfxのechoとAudacityのエコーは異なる仕組みで実現されています。Audacityのエコーは、[ディレイ時間]と[減衰ファクター]で設定でき、わかりやすいものでしたので、Sonic Piで同じようなエコーを生じるプログラムを作成してみました。 ディレイ時間によって、残響にも山彦風にもでき、減衰ファクターを1より大きくして発散させることも可能で、変わった音を作成することもできます。 ディレイ時間毎に、元の音に減衰ファクターをかけた音を足し合わせています。ディレイ時間毎に減衰ファクターの掛け合わせられる回数が増えてゆきます。 Audacityのソースリストをの確認したわけではありませんので、異なる場合もあります。
下記の例では、内蔵サンプリング音源のamen loopにエコーをかけていますが、他のファイルにしたい場合には、file=の後ろにファイルをドロップすればフルパスが入力されます。

参考:amenの起源は、The Winstons(1969)の
「Amen Brother」(Youtube)
file= :loop_amen_full			# 音を与える
sampleTime = sample_duration(file)		# 音の長さを調べる
delayTime = 0.2			# ディレイ時間
decayFactorIni = 0.4			# 減衰ファクター
decayFactor = decayFactorIni
sample file
(sampleTime/delayTime).times do
  sleep delayTime
  sample file, amp: decayFactor
  decayFactor = decayFactor * decayFactorIni
end


小鳥のさえずりをSonic Piで

多重起動により、小鳥の群れとすることができます。
2017.7.31 間違いを修正しました。
use_random_seed Time.new.usec				# 乱数の系列をミリ秒によって変える
loop do
  f1=hz_to_midi(rrand(4000, 5000))			# さえずりの高音側周波数の範囲をHzで与えmidi番号に
  f2=hz_to_midi(rrand(1000, 3000))			# さえずりの低音側周波数の範囲をHzで与えmidi番号に
  s= play f1, attack:0.02, sustain:0.2, release:0,
    note_slide:0.1, pan_slide: 0.1, amp:rrand(0.1,2), amp_slide: 0.1	# 高音側の音を鳴らす
  sleep 0.05					# 非常に短く伸ばす
  control s, note: f2, pan:rrand(-1,1), amp:rrand(0.1,2)			# 低音側の音を鳴らす
  sleep 0.05					# 非常に短く伸ばす
  control s, note: f1, pan:rrand(-1,1), amp:rrand(0.1,2)			# 高音側の音を鳴らす
  sleep rrand(0.1,1)					# さえずりの時間間隔は少し長めに
end
ずっと聞いていると、あまり気持ちよくはありません。音量や間隔や周波数に 1/fゆらぎ を取り入れると心地よくなると思われます。(次節)


1/fゆらぎ的カラス

周波数、左右のパン、音量、時間間隔を独立して1/fゆらぎ的(間欠カオス)に変化させたカラスの鳴き声(:misc_crow)です。
周波数はわずかしか動かしていません。
音量と時間間隔には同じ乱数値を使い、時間間隔が短い時には音量が小さ目になるようにしています。

1/f fluctuation, Intermittent Chaos method
use_random_seed Time.new.usec # 現在のミリ秒値で乱数系列を選択
define :x1f do |x|
  if x<0.5
    x=x+2*x*x
  else
    x=x-2*(1-x)*(1-x)
  end
  if x<0.01     # 両端付近の処理.この部分は適当です。
    x=rrand(0.01,0.1)
  elsif x>0.99
    x=rrand(0.9,0.99)
  end
  return x
end
x1=rand;x2=rand;x3=rand # 初期値
loop do
  x1=x1f x1 # 関数 x1fに引数x1を与え、戻り値x1を得る. x1=x1f(x1)と書いてもよい.
  x2=x1f x2
  x3=x1f x3
  # 再生速度の変化0.9〜1.1、左右のパン-1〜1、音量0.5〜1.5、時間間隔0〜2
  sample :misc_crow,rate:0.9+x1/5,pan:x2*2-1,amp:x3+0.5
  sleep x3*2
end



サンプル音をHypercompresするMAXIMIZERをSonic Piで

最新版(Ver4頃から)では、この機能はなくなり、振幅が1を超えた場合には、その部分はカットされるようになりました。波形の頭が切り取られてしまい台形となるため、(奇数次)高次倍音が多く含まれるようになり音が歪んでしまいます。この機能があったため、古いバージョンのSonic Piで作られたプログラムは、大きすぎる音量について考慮していないものが多いので注意が必要です。

Loudness War(音圧競争)という、音楽の販売のためだけに音を大きくする競争が今でも(特に日本では)続けられており批判もされています。Audacityでもコンプレッサーやリミッターやマキシマイザーを使うとこのような効果を得ることができますが、Sonic Piでも容易に超圧縮をすることができました。
ampの値を非常に大きするだけで波形がクリップされて"矩形"となることなく振幅が拡大されるため、音割れが殆どない状態で音量を大きくすることができます。
例: ラベルのボレロでは、最初のフルートから巨大な音量とし、後半でフルオーケストラになっても同様の音量とすることができました。

sample "Bolero.wav", amp:100

sample "Bolero.wav", amp:1000
1000でも音色には影響ありませんでした.


12以外の平均律で演奏する。n平均律、n Equal Temperament, 微分音 Microtonal music

平均律は、通常12等分(2の12乗根をかけてゆく)が用いられますが、15平均律,31平均律,100平均律などの n平均律が微分音とも呼ばれ、民族音楽や、現代音楽等で用いられているようです。
下記のプログラムでは、通常の演奏データを、nEqualTemperamentの値を他の整数値に変えるだけで平均律の分割数を変更した演奏とすることができます。live_loopを使っているので、一度Runした後、StopせずにnEqualTemperament値を変えて再度Runすると、輪唱の音程が順次変更されてゆきます。
中央のド(C4,MIDIナンバーの60)を基準にして、12平均律の場合のC1からC9の間の音程を生成します。(24とした場合には、中央のドの音程はそのままで、各鍵盤の間にもう一つづつ鍵盤を増やしたことに相当します.)
11平均律や13平均律を聞いていると音感が悪くなるかもしれません。小さすぎる値にすると音が足りなくなる場合があります。差を聞き取れませんが10000平均律でも動作はします。

# n Equal Temperament Music
nEqualTemperament=12    # 12平均律の場合。 この数値を6,10,13,31,100 等、自由に変更して下さい。
A4=440  # Tuning チューニングを変更したい場合
C5=A4*2.0**(3.0/12.0)
C0=C5/(2.0**5)
nET=[]
centerC=nEqualTemperament*4
for i in 0..nEqualTemperament*9
  nET[i]=hz_to_midi(C0*2.0**(i/nEqualTemperament.to_f))
end
# 以上が音程の生成。以下は演奏。
use_synth :tri # 音色 :triを:pianoに変更すれば 微分音ピアノ になります。
use_bpm 160 # 速度
a=[]
b=[]
# かえるのうた Kaeruno uta
a[0]=[:C4,:D4,:E4,:F4,:E4,:D4,:C4] # ドレミファミレド
b[0]=[1,1,1,1,1,1,2]
a[1]=[:E4,:F4,:G4,:A4,:G4,:F4,:E4] # ミファソラソファミ
b[1]=[1,1,1,1,1,1,2]
a[2]=[:C4,:C4,:C4,:C4] # ドドドド
b[2]=[2,2,2,2]
a[3]=[:C4,:C4,:D4,:D4,:E4,:E4,:F4,:F4,:E4,:D4,:C4] # ドドレレミミファファミレド
b[3]=[0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,1,1,2]
# 3部の輪唱で演奏する。
live_loop :lop1 do
  for i in 0...a.length
    for j in 0...a[i].length
      play nET[a[i][j]-(60-centerC)],sustain:b[i][j]*0.9,pan:-1
      sleep b[i][j]
    end
  end
end
sleep 8 # 8拍後に第2パートをスタートする
live_loop :lop2 do
  for i2 in 0...a.length
    for j2 in 0...a[i2].length
      play nET[a[i2][j2]-(60-centerC)],sustain:b[i2][j2]*0.9,pan:0
      sleep b[i2][j2]
    end
  end
end
sleep 8 # さらに8拍後に第3パートをスタートする
live_loop :lop3 do
  for i3 in 0...a.length
    for j3 in 0...a[i3].length
      play nET[a[i3][j3]-(60-centerC)],sustain:b[i3][j3]*0.9,pan:1
      sleep b[i3][j3]
    end
  end
end


曲を「かえるのうた」から、「フレールジャック」に変更する場合には、上記のaとbの配列[0]から[3]の8行を、下記2行に置き換えてください。
# Frere Jacques
a[0]=[:C4,:D4,:E4,:C4,:C4,:D4,:E4,:C4,:E4,:F4,:G4,:E4,:F4,:G4,:G4,:A4,:G4,:F4,:E4,:C4,:G4,:A4,:G4,:F4,:E4,:C4,:C4,:G3,:C4,:C4,:G3,:C4]
b[0]=[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,2.0,1.0,1.0,2.0,0.5,0.5,0.5,0.5,1.0,1.0,0.5,0.5,0.5,0.5,1.0,1.0,1.0,1.0,2.0,1.0,1.0,2.0]



DNA Genome Music, DNA遺伝子音楽


NHKで放映中の「スーパープレゼンテーション」のキャスターである伊藤穰一氏(MITメディアラボ所長)が、
TED 「How to read the genome and build a human being ゲノムを解読し ヒトを生み出す」リッカルド・サバティーニ
の回で、自らのゲノムを(日本人の公開例が少ないこともあり)公開していると語っていたのでデータを入手し、Sonic Piで音にしてみました。

伊藤穰一氏の遺伝子データの公開ページ
ファイルは、https://my.pgp-hms.org/user_file/download/1789
ファイル中に、塩基のA,G,T,C以外にI,T,-の文字があったので、IをE、TをF、-をBに置き換えて音程にしています。
genome_Joichi_Ito_Full_20160218143309.txt は、大きすぎたので、先頭の1000行を使用。(全576326行のファイルの後ろ側を削除してgenome_Joichi_Ito_Full_20160218143309_1-1000.txtとして使用)
ファイルの最終行に空行を入れないこと.(演奏後にエラーとなります.)

ファイル内の一部の様子(TAB区切りデータの4カラム目が塩基配列です.#で始まる行を読み飛ばして、行の後ろからTABの位置を探しています。)
# rsid chromosome position genotype
rs3094315 1 752566 AA
rs12562034 1 768448 AG


Sonic Piのプログラム
path="各使用環境でのファイルへのpath /genome_Joichi_Ito_Full_20160218143309_1-1000.txt"
d = []
open(path){|f| d = f.readlines}
for i in 0...d.length
  if d[i].index("#")
  else
    puts d[i][d[i].index("\t",-6)+1...d[i].length-1]
    dd=d[i][d[i].index("\t",-6)+1...d[i].length-1]
    for j in 0...dd.length
      ddd=dd[j]
      ddd="D" if dd[j]=="I"
      ddd="E" if dd[j]=="T"
      ddd="B" if dd[j]=="-"
      play ddd
      sleep 0.5   # 音の間隔
    end
  end
end
なお、御本人からTwitterにて,いいねとリツイートをいただいていますので公認と考えれれます。


修正版
最初に作成した上記では、ファイルを全部読み込んでから操作を行っていたので全遺伝子のデータを一度に読み込むことができませんでした。
下記では、1行づつ読み込んでいるので、元のファイル genome_Joichi_Ito_Full_20160218143309.txt をそのまま読み込むことができます。
また、改行コードを.chompで除き、.split("\t")でTAB区切りデータを分割し4要素目の[3]を取り出すようにしました。
塩基配列の記載文字数は、1文字と2文字が混在しています。(もし3文字以上があった場合も動作します.)
if文による分岐の記述方法については、検討の余地があります。

path="ファイルへのパス genome_Joichi_Ito_Full_20160218143309.txt"
File.open(path) do |file|
  file.each_line do |dataLine|
    if !dataLine.index("#")
      d=dataLine.chomp.split("\t")[3]
      for i in 0...d.length
        dd=d[i]
        dd="D" if d[i]=="I"
        dd="E" if d[i]=="T"
        dd="B" if d[i]=="-"
        play dd
        sleep 0.1
      end
    end
  end
end
========================================
DNA遺伝子音楽を宇宙的サウンドにした例 Genome cosmic sounds

上記のプログラムで使用した単音をコードとして使い、先頭音を変えながら上昇(メジャーコード :M )、下降(マイナーコード :m )させています。
コードをより複雑なものに変更するだけでイメージを大きく変えることができます。(:major7, :minor7, :sus4, '7sus4', :dim7等)
ファイルの読み込み方法は修正前のものです。

path="各使用環境でのファイルへのpath /genome_Joichi_Ito_Full_20160218143309_1-1000.txt"
use_debug false
d = []
open(path){|f| d = f.readlines}
with_fx :panslicer do
  for i in 0...d.length
    if d[i].index("#")
    else
      puts d[i][d[i].index("\t",-6)+1...d[i].length-1]
      dd=d[i][d[i].index("\t",-6)+1...d[i].length-1]
      for j in 0...dd.length
        ddd=dd[j]
        ddd="D" if dd[j]=="I"
        ddd="E" if dd[j]=="T"
        ddd="B" if dd[j]=="-"
        ddd=ddd+"3"
        puts ddd
        for k1 in 0..9
          play chord(ddd,:M,num_octaves:3,invert:k1),amp:rrand(0.5,2),attack:0.1
          sleep 0.25
        end
        for k2 in 9.downto(0)
          play chord(ddd,:m,num_octaves:3,invert:k2),amp:rrand(0.5,2),attack:0.1
          sleep 0.25
        end
      end
    end
  end
end



バブルソート音楽、可聴化, Buble Sort Music, Sonification

データを目で見えるようにする手法の"可視化"に対して、音で聴いて耳で判断できるようにすることを"可聴化(
Sonification)"といいます。Sonic Piは可聴化に対しても優れたツールとなります。
ここでは、最も簡単な例としてバブルソートの過程を音として鳴らしてみました。1オクターブの音階を使い、最も悪い並びである逆並びからスタートさせています。
# のコメント行を活かせば、ランダムな音程からスタートできますが、ソートがずっと早く終わります。
nの値を増やすことで、音の数を変えることができます。
音階指定の:majorを他の音階とすることもできます。:minor, :hirajoshi(琴の平調子) 等
nを増やして音数が足りなくなった場合には、scaleのスタート値の60(中央のド)を小さくして、num_octaves:の値を大きくして下さい。
他のソートアルゴリズムと音で比較してみるのも興味深いでしょう。

# Sonification, Buble Sort Music 
n=8  # 音の数
a=[]
for i in 0...n
  a[n-i-1]=scale(60,:major,num_octaves:3)[i]
end
# n*2.times do  # Randomization
#  i=rrand_i(0,n-1)
#  j=rrand_i(0,n-1)
#  a[i],a[j]=a[j],a[i]
# end
for i in 0...n-1
  for k in 0...n
    play a[k]
    sleep 0.1
  end
  puts "-----------"
  sleep 1
  for j in 0...(n-1-i)
    if a[j]>a[j+1] then
      a[j],a[j+1]=a[j+1],a[j]
    end
  end
end
#(n-1).downto(0) do |k|  # 逆順に鳴らす場合下のforの代わりに
for k in 0...n
  play a[k]
  sleep 0.2
end



五度円(五度圏)上を廻るコード

完全五度の関係にある調を順に並べて行くと12の調からなる円になります。隣り合ったコード同士は相性が良く3つ並んだ3コードで曲が作られたりしています。
以下のプログラムでは、Cから始め、左側、現在と同じ、右側、を乱数の-1,0,1で決めてランダムに移動します。移動量は12で割った余りをつかっていますので1オクターブ内を移動します。音はコードで2音ずつ鳴らしています。

# Random walk around on the Circle of Fifth
use_debug false
use_random_seed Time.new.usec
use_synth :pluck
i=0
loop do
  2.times do
    play_pattern_timed (chord 48 + i%12, :major),0.01
    puts i/7, note_info(48 + i%12)
    sleep 0.5
  end
  i=i+(rrand_i(0,2)-1)*7
end

時々、+9または-3して対応するマイナーコード(:minor)(円の内側)にするなども容易にできる改良です。



Gapminderの平均余命データを可聴化

Gapminderは、
NHK スーパープレゼンテーションの初回放送 ハンス・ロスリング(Hans Rosling)「増え続ける世界人口」2012年4月2日 でも紹介され、注目を集めているデータの可視化で社会問題を理解し解決しようというサイトです。参考(本サイト内)
トップページとなっているグラフは、各国の平均余命を縦軸に、個人の収入を横軸に取り、1800年から現在までの変化を点の動きで見ることができ、点の大きさを国の人口、色で地域を表し、5次元データを一つの画面上にわかりやすく可視化した画期的なものです。

データは全て公開されていますので、この中から、日本と英国の平均余命を音にして可聴化を試みてみました。
下記のプログラムでは、日本を左側の英国を右側のスピーカーから、余命を音程に、年度順に、発音のタイミングをずらしてピアノ音で鳴らしています。音程は整数化していないので微分音となっています。(to_fをto_iとすれば平均律の音程になります。)
コメント化しているplay文を使えば、両者の差を音程として鳴らすことができます。
前半は音程が低いので、ノートPCのスピーカーでは聞き辛いと思われます。
音色を変えるだけでも印象が大きく異なります。よりわかりやすく印象的なものとするのは工夫次第です。
国名をCSVファイル内にあるものに変更すれば、他の国々とすることができます。
Perocessingのグラフィックスと連携して、グラフとしての可視化と同時に可聴化することも試してみたいものです。


プログラム
#日本と英国の余命データの可聴化
# Sonification of Japan vs UK Life Expectancy Sounds
use_synth :piano
require 'csv'
path="path to  /indicator life_expectancy_at_birth.csv"
d=CSV.read(path, headers: false)
for i in 0...d.length
  C1=i if d[i][0]=="Japan"
  C2=i if d[i][0]=="United Kingdom" # "United States"
end
for j in 1...d[C1].length
  puts d[0][j]
  #play 72+(d[C1][j].to_f-d[C2][j].to_f)*1.5,amp:3 # play difference
  play d[C1][j].to_f,amp:3,pan:-1 # play JP from left
  sleep 0.1
  play d[C2][j].to_f,amp:3,pan:1 # play UK from right
  sleep 0.1
end

使用したデータファイルは、 "indicator life_expectancy_at_birth.csv" です。
Ruby言語のCSVに関する機能を使用して読み込んでいます。
path= の後ろは、データファイルの置き場所に応じて変更して下さい。

このデータのありかと作成方法
Gapminderの旧版(フラッシュ版)は、XY軸にそれぞれ元データを表示するボタンがありましたが、新版には見当たりませんでした。
データの一覧ページから" Life expectancy (years) "を探します。
Excelファイルとして "indicator life_expectancy_at_birth.xlsx" をダウンロードし、カンマ区切りのCSV形式で保存します。
Excelファイルへの直リンクは、http://spreadsheets.google.com/pub?key=phAwcNAVuyj2tPLxKvvnNPA&output=xls
作成されたCSVファイルの後半の263行から1001行までは、カンマのみのデータでない行なので、テキストエディタ等でこれらの行を削除して保存します。
念のため行末コードをUNIXのLFとして保存したのが、上記ファイルです。

同様に、他の膨大な社会問題についてのデータも同様に入手できますので、可聴化してみるのは興味深いことでしょう。


ピタゴラスのコンマのずれを聞く

ピタゴラスが美しい響きの得られる音程の比率について考察したときに、弦の長さを2/3にした時の響きが美しかったので、この操作を繰り返して得た音階がピタゴラス音階と言われています。五度円は、この2/3倍の音程を時計方向に順に並べたものです。 弦を2/3とすると、音程は1.5倍となりますが、繰り返してゆくと上のオクターブに移動してしまいます。このときには、音程を1/2してオクターブを下げて元のオクターブの中に収まるようにします。これを繰り返して行くと、五度円となり、一周すると元に戻ります。しかし、開始した音程とは完全には一致しません。このずれをピタゴラスのコンマ(Pythagorean Comma)と言っています。
以下のプログラムでは、一周する間の各音を順に鳴らし、最後に元の音と一周後の音のずれを同時に鳴らして、唸りとして聞こえるようにしています。
開始音をC4以外に変更した場合も同様となります。

a=midi_to_hz(:C4) # 開始音
play hz_to_midi(a);sleep 1
b=a
12.times do
  b=b*1.5
  b=b/2.0 if b>a*2
  play hz_to_midi(b);sleep 1
end
puts "Pythagorean comma=",(hz_to_midi(b)-hz_to_midi(a))*100
play [hz_to_midi(a),hz_to_midi(b)],sustain:4  # ピタゴラスのコンマによる唸り



リサージュ図形のいろいろ

Sonic Piでは、左右の音の位相のズレをXY軸としてグラフ表示をしてくれます。
グラフの表示は、[Prefs]ボタンから[ビジュアル]→[Lissajous]をチェック.
左右にpanを振って適当な整数比となる周波数を与えると図形を観察することができます。
release時間(デフォルト設定のまま)によって図形がうまく重なって移行してくれました。

プログラムは、
a=[[600,600],[600,550],[600,500],[600,400],[600,300],[600,200]]
for i in 0...a.length
  play hz_to_midi(a[i][0]),amp:3,sustain:2,pan:-1
  play hz_to_midi(a[i][1]),amp:3,sustain:2,pan:1
  sleep 2
end
配列中の周波数[ , ]の左右を入れ替えると、グラフのXY軸が交換します。panの値の入れ替え(1と-1)でも同様です。

このプログラムの解説とver.2.12の機能を使い大幅に拡張したプログラムの解説したYoutubeビデオを英国のRobin Newmanさんが公開しています。
改良版のコードも公開されています。



Sonic Piによる奏者の発音タイミングデータの活用(Miles Davis "So What")

Miles DavisのSo Whatの冒頭のトランペットソロの部分の演奏を利用しています。

作成方法の概略
1) AudacityまたはSoinc Visualiserのスペクトル表示機能を利用して発音の開始時間をラベルとしてマーク(目視)し、ラベルファイルとして出力します。(テキストファイルが得られます)
下図は、Audacityで読み込んだMilesのソロの出だしのD5,A4,D4の部分にラベルを付けたところ.(マウスでクリックしてcommand+B, Winではcontrol+B)
ここでは、基音よりも2倍音の成分の方が大きく見えており、これは聴感上と一致すると思われますので、基音でなく2倍音の開始位置を選んでラベルを付けています。
3倍音以上も、スケールを変えて目視確認はしましたが、基音または2倍音よりも大きくなることはありませんでした。

2) Excel等で各時間の差をとって横並びにしてカンマで区切り、音符の長さとする。このとき要素の先頭と最後だけは後で調整します。
これが下記の配列bとなります。

3) MIDIデータWebから入手しをMuseScoreで読み込み、演奏に合わせて楽譜を修正します。(このとき、音の長さ、休符は使用しないので考慮するは必要ありません)
MuseScoreで作成されたMilesのソロの先頭部分の例。上記のスペクトルに対応

4) MuseScoreでMusicXML形式に出力し、本サイト内で公開しているProcessingによる変換プログラムでSonic Piの音符に変換します。
5) 出力された音符のデータから休符":r,"を全て削除してから、先頭にのみ加えると下記の配列aが得られます。

6) これらの作業は、一回で音程データと時間データが一致することはありませんでした。演奏させてみて、ずれた部分を探しての修正を繰り返すことになります。
作業1)では、楽譜には記述されない、小さな音を拾うか捨てるか迷うことがありました。この部分は、演奏の解析にも活用できるでしょう。同じ音程の音でも、整数次倍音が優勢な音と奇数次倍音が優勢な音なども観察できます。(トランペットは構造上、奇数次倍音が優勢な楽器と言われています。)


この作業では、音の強さは考慮していません。
#でコメント化してある2行は、別途作成したマイルスの元演奏のソロ開始の少し前から切り出したWAVファイルを同時に再生するためのものです。
この目的のために、配列bの先頭を 5.31秒 と長くしていますので、適宜0.31等に書き換えて下さい。
スペクトルの表示色の設定により音として見える大きさが異なり、また、色の変化から目視で発音のタイミングを得ているので、ある程度の誤差はありますが、元演奏にほぼピッタリと合ったタイミングでSonic Piが演奏してくれます。
スペクトル表示の設定を操作すると、赤く見える部分の大きさが変わります。スペクトル表示前に、コンプレッサ(マキシマイザー)を強くかけて音量を揃えておくのも一つの方法と考えられます。
楽器をpianoにすると、フェイクの様子がより鮮明になります。
完全なソロ演奏の場合は、作業が比較的に容易です。DebussyのSyrinxもデータは作成済みで公開予定(演奏者は、Moyse, Gazzelloni, Galway, Phaud etc.)
OpenSMILEの利用や、Processing等の言語でFFTで音を自動取得するプログラムの作成も検討しましたが、誤差が大きく自動化が難しかったためあきらめました。


use_bpm 60
#f=" Path to the file   So_What_solo.wav"
a=[]
b=[]
a[0]=[:r,:D5,:A4,:D4,:D4,:A4,:G4,:A4,:D4,:D4,:D4,:F4,:A4,:G4,:A4,:D4,:D4,:F4,:A4,:G4,:A4,:B4,:C5,:B4,:C5,:B4,:A4,:F4,:A4,:G4,:A4,:D4,:D4,:D5,:D5,:D5,:D5,:D5,:F5,:D5,:A4,:G4,:F4,:F4,:E4,:F4,:G4,:A4,:Df5,:D5,:E5,:G5,:E5,:D5,:C5,:A4,:G4,:D4,:D4,:Af3,:Ef4,:Df4,:F4,:Af4,:Fs4,:Bf4,:C5,:Df5,:Ef5,:C5,:Bf4,:Bf4,:Fs4,:Af4,:Fs4,:F4,:Af4,:F4,:Ef4,:Ef4,:Bf3,:Df4,:Ef4,:F4,:Fs4,:Af4,:Bf4,:Df5,:D5,:Af5,:D5,:Df5,:C5,:Bf4,:Af4,:G4,:A4,:Df5,:D5,:A4,:A4,:D5,:A4,:D4,:F4,:A4,:D5,:D5,:D5,:F5,:E5,:D5,:A4,:A4,:G5,:E5,:C5,:E5,:G5,:E5,:C5,:C5,:G4,:E4,:C5,:E5,:C5,:E5,:G5,:E5,:C5,:A4,:F4,:Af4,:A4,:D5,:A4,:G4,:F4,:F4,:D4,:F4,:A4,:Df5,:D5,:A4,:G4,:G4,:F4,:A4,:G4,:A4,:D4,:D4,:F4,:A4,:G4,:A4,:C5,:B4,:C5,:B4,:A4,:A4,:Af5,:F5,:Df5,:Bf4,:Af4,:Fs4,:F4,:Ef4,:Ef4,:Df4,:F4,:Ef4,:Fs4,:F4,:Af4,:Fs4,:Bf4,:Af4,:C5,:Bf4,:Df5,:Ef5,:C5,:Af4,:D5,:E5,:F5,:G5,:E5,:C5,:A4,:C5,:E5,:G5,:E5,:C5,:D5,:C5,:B4,:A4,:A4,:D4,:F4,:A4,:G4,:A4,:Df5,:D5,:E5,:C5,:A4,:D4,:F4,:Af4,:A4,:D4,:D4]
b[0]=[5.31,0.804,0.273,2.015,0.295,0.227,0.644,0.223,0.244,1.738,0.122,0.295,0.257,0.358,0.463,0.379,0.063,0.278,0.244,0.404,0.484,0.046,0.665,0.168,0.349,0.303,0.589,0.265,0.185,0.248,0.206,0.278,0.942,0.349,0.273,0.198,2.137,0.564,0.762,0.316,0.324,0.391,0.403,2.989,0.219,0.231,0.135,0.286,0.265,0.326,0.326,0.24,0.614,0.24,0.208,0.185,0.406,0.303,2.865,0.328,0.371,0.109,0.273,0.228,0.209,0.219,0.21,0.202,0.395,0.29,1.035,0.376,0.074,0.909,0.442,0.29,0.252,0.37,0.299,1.935,0.248,0.181,0.24,0.206,0.219,0.21,0.244,0.189,0.429,0.459,0.328,0.177,0.341,0.265,0.177,0.244,0.202,0.252,0.24,0.391,2.259,0.303,0.21,0.265,0.589,2.524,0.387,1.94,0.442,0.888,0.328,0.261,0.341,2.163,0.74,2.676,0.21,0.366,0.438,0.745,0.337,1.59,0.728,2.352,0.417,0.759,0.204,0.244,0.179,0.334,0.566,0.82,0.297,0.258,0.751,0.316,0.285,0.297,0.492,1.611,0.171,0.251,0.238,0.074,0.294,0.411,0.334,2.905,0.169,0.257,0.319,0.461,0.294,0.158,0.241,0.201,0.272,0.619,0.269,0.179,0.247,0.161,0.362,1.803,1.154,0.238,1.544,0.244,0.359,0.411,0.464,0.303,0.628,1.977,0.189,0.269,0.199,0.222,0.223,0.65,0.179,0.136,0.13,0.878,0.436,0.217,0.384,2.19,0.254,0.189,0.272,1.046,1.825,0.73,0.21,0.195,0.167,0.377,0.977,0.418,0.306,0.439,0.167,0.408,2.051,0.176,0.238,0.204,0.213,0.198,0.275,0.217,0.823,0.696,0.49,0.107,0.294,0.186,0.387,0.513,3]
#sample f, amp:3
use_synth :pretty_bell
in_thread do
  for i in 0...a.length
    for j in 0...a[i].length
      play a[i][j], amp:3
      sleep b[i][j]
    end
  end
end
So What(マイルスのソロ部分のみ)
前半2分は、Sonic Piのシンセ:pretty_bellに原曲を重ねて、後半2分は同じ部分を:pianoのみで.



Sonic Piによるドビュッシーのシランクスの演奏。5人の巨匠の比較。Debussy, Syrinx

マルセル・モイーズ Marcel Moyse 0:02- (2m26s)
セヴェリーノ・ガッゼローニ Severino Gazzelloni 2:32- (3m27s)
ジャンピエール・ランパル Jean-Pierre Rampal 6:05- (1m54s)
ジェームズ・ゴールウェイ James Galway 8:04- (2m17s)
エマニュエル・パユ Emmanuel Pahud 10:26- (3m23s).


コードとデータの作製法は、上記のSo Whatのプログラムとほぼ同様ですが、トリルの回数が演奏者によって大きく異なっているので、これにより音の総数も違ってきています。
音のタイミングの取得には、Sonic Visualiserを使用しました。(Audacityのスペクトルは使用せず) 目視によって音の出だしのタイミングをマークして数値として得ていますので、ある程度の誤差を含んでいます。
Youtubeのビデオ中で使用した音は、下記プログラムのampとreleaseとpanを音の長さによって少しだけ変化させるようにしています。
楽器をピアノ(use_synth :piano) とすると、余韻が減るため、一音一音の間隔がより際立って聴こえます。
play a[i][j]+1 というようにして半音上げ等の移調が簡単にできます。(半音上げると尺八で吹きやすくなり、+5程度で鼻笛で吹けるようになりますが、かなりの難曲です。)
使用ソフトウェアは、Sonic Pi, Sonic Visualiser, Audacity(音の切り貼り), MuseScore(楽譜からMusicXMLファイルの作成), ProcessingプログラムでMusciXMLをSonic Piの音符に変換、以上はOpen Source Software
ビデオ化には iMovie (Apple)を使用.

use_bpm 60
a=[]
b=[]
# Marcel Moyse
a[0]=[:r,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:C6,:B5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Gf4,:G4,:C5,:Gf4,:G4,:Df5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Af4,:B4,:Df5,:E5,:Af5,:Af5,:B5,:Df6,:Ef6,:Bf5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Af4,:Df4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Df5,:Ef5,:Gf5,:A5,:Af5,:G5,:Gf5,:Ef5,:D5,:Df5,:C5,:A4,:Af4,:G4,:Gf4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Df5,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Ef5,:Df5,:B4,:Bf4,:Af4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Df5,:Ef5,:F5,:Ef5,:Df5,:B4,:Bf4,:B4,:Df5,:D5,:Df5,:B4,:Bf4,:B4,:D5,:E5,:D5,:B4,:Bf4,:A4,:Af4,:Gf4,:D4,:Gf4,:Af4,:A4,:Bf4,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Bf4,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:Bf4,:F5,:Gf5,:Af5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:Df6,:E6,:D6,:Df6,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Df4,:Gf4,:F4,:E4,:Df4,:A4,:G4,:Df4,:B4,:A4,:G4,:F4,:Ef4,:Ef4,:Df4]
b[0]=[1,1.409,0.109,0.102,0.882,0.114,0.098,0.656,0.338,0.307,0.287,1.393,0.202,0.149,4.689,1.046,0.104,0.083,0.752,0.116,0.08,0.633,0.352,0.237,0.21,1.398,0.21,0.155,2.306,0.433,0.27,0.247,0.201,0.189,0.163,0.06,0.524,0.439,1.052,0.183,0.149,2.21,0.422,0.264,0.216,0.112,0.672,0.166,4.153,1.816,4.538,3.286,1.163,0.109,0.128,0.746,0.125,0.088,0.652,0.409,0.279,0.202,1.18,0.109,0.078,0.594,0.101,0.098,0.566,0.295,0.218,0.19,0.256,0.068,0.502,0.315,0.21,2.503,0.596,0.324,0.284,0.181,0.179,0.148,0.105,0.19,0.052,0.373,0.26,0.202,2.13,0.383,0.164,0.132,0.794,0.109,0.056,0.14,0.658,0.158,0.141,0.087,0.868,0.234,0.172,0.192,0.411,0.058,0.526,0.496,1.543,0.649,0.493,0.29,0.097,0.262,0.278,0.232,0.056,0.463,0.431,0.395,0.095,0.91,1.149,0.571,0.102,0.437,0.326,0.559,0.604,0.742,1.008,0.38,0.064,0.508,0.697,1.809,2.03,0.242,0.108,0.367,0.297,0.541,0.647,0.785,0.949,0.298,0.062,0.394,0.398,1.132,1.966,0.344,0.133,0.124,1.821,0.326,0.195,0.159,0.142,0.115,0.492,0.096,0.081,0.089,0.476,0.275,0.174,1.645,0.339,0.233,0.214,0.17,0.172,0.271,0.189,0.128,0.168,0.087,0.096,0.101,0.096,0.088,0.079,0.127,0.07,0.064,0.095,0.972,0.298,0.08,0.061,0.073,0.062,0.079,0.056,0.095,0.618,0.258,0.088,0.098,0.066,0.074,0.071,0.057,0.067,0.065,0.588,0.081,0.085,0.076,4.246,1.527,0.099,0.081,0.647,0.101,0.093,0.676,0.366,0.222,0.375,1.473,0.285,0.076,0.408,0.222,1.723,0.083,0.103,0.593,0.113,0.086,0.663,0.494,0.385,0.516,0.415,0.219,0.122,0.122,0.115,0.105,0.606,0.344,0.307,0.246,0.419,0.2,0.139,0.128,0.104,0.115,0.601,0.399,0.382,1.91,0.399,0.082,0.582,0.736,3.161,0.662,0.767,3.286,4.132,0.81,0.874,0.866,0.987,0.282,4.946]
use_synth :pretty_bell
in_thread do
  for i in 0...a.length
    for j in 0...a[i].length
      play a[i][j], amp:2.5, release:b[i][j]+0.3
      sleep b[i][j]
    end
  end
end

奏者を変更するには、上記のプログラム中の配列a,bを下記と入れ替えて下さい。
# Marcel Moyse
a[0]=[:r,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:C6,:B5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Gf4,:G4,:C5,:Gf4,:G4,:Df5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Af4,:B4,:Df5,:E5,:Af5,:Af5,:B5,:Df6,:Ef6,:Bf5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Af4,:Df4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Df5,:Ef5,:Gf5,:A5,:Af5,:G5,:Gf5,:Ef5,:D5,:Df5,:C5,:A4,:Af4,:G4,:Gf4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Df5,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Ef5,:Df5,:B4,:Bf4,:Af4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Df5,:Ef5,:F5,:Ef5,:Df5,:B4,:Bf4,:B4,:Df5,:D5,:Df5,:B4,:Bf4,:B4,:D5,:E5,:D5,:B4,:Bf4,:A4,:Af4,:Gf4,:D4,:Gf4,:Af4,:A4,:Bf4,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Bf4,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:Bf4,:F5,:Gf5,:Af5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:Df6,:E6,:D6,:Df6,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Df4,:Gf4,:F4,:E4,:Df4,:A4,:G4,:Df4,:B4,:A4,:G4,:F4,:Ef4,:Ef4,:Df4]
b[0]=[1,1.409,0.109,0.102,0.882,0.114,0.098,0.656,0.338,0.307,0.287,1.393,0.202,0.149,4.689,1.046,0.104,0.083,0.752,0.116,0.08,0.633,0.352,0.237,0.21,1.398,0.21,0.155,2.306,0.433,0.27,0.247,0.201,0.189,0.163,0.06,0.524,0.439,1.052,0.183,0.149,2.21,0.422,0.264,0.216,0.112,0.672,0.166,4.153,1.816,4.538,3.286,1.163,0.109,0.128,0.746,0.125,0.088,0.652,0.409,0.279,0.202,1.18,0.109,0.078,0.594,0.101,0.098,0.566,0.295,0.218,0.19,0.256,0.068,0.502,0.315,0.21,2.503,0.596,0.324,0.284,0.181,0.179,0.148,0.105,0.19,0.052,0.373,0.26,0.202,2.13,0.383,0.164,0.132,0.794,0.109,0.056,0.14,0.658,0.158,0.141,0.087,0.868,0.234,0.172,0.192,0.411,0.058,0.526,0.496,1.543,0.649,0.493,0.29,0.097,0.262,0.278,0.232,0.056,0.463,0.431,0.395,0.095,0.91,1.149,0.571,0.102,0.437,0.326,0.559,0.604,0.742,1.008,0.38,0.064,0.508,0.697,1.809,2.03,0.242,0.108,0.367,0.297,0.541,0.647,0.785,0.949,0.298,0.062,0.394,0.398,1.132,1.966,0.344,0.133,0.124,1.821,0.326,0.195,0.159,0.142,0.115,0.492,0.096,0.081,0.089,0.476,0.275,0.174,1.645,0.339,0.233,0.214,0.17,0.172,0.271,0.189,0.128,0.168,0.087,0.096,0.101,0.096,0.088,0.079,0.127,0.07,0.064,0.095,0.972,0.298,0.08,0.061,0.073,0.062,0.079,0.056,0.095,0.618,0.258,0.088,0.098,0.066,0.074,0.071,0.057,0.067,0.065,0.588,0.081,0.085,0.076,4.246,1.527,0.099,0.081,0.647,0.101,0.093,0.676,0.366,0.222,0.375,1.473,0.285,0.076,0.408,0.222,1.723,0.083,0.103,0.593,0.113,0.086,0.663,0.494,0.385,0.516,0.415,0.219,0.122,0.122,0.115,0.105,0.606,0.344,0.307,0.246,0.419,0.2,0.139,0.128,0.104,0.115,0.601,0.399,0.382,1.91,0.399,0.082,0.582,0.736,3.161,0.662,0.767,3.286,4.132,0.81,0.874,0.866,0.987,0.282,4.946]

# Severino Gazzelloni
a[0]=[:r,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:C6,:B5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Gf4,:G4,:C5,:Gf4,:G4,:Df5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Af4,:B4,:Df5,:E5,:Af5,:Af5,:B5,:Df6,:Ef6,:Bf5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Af4,:Df4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Df5,:Ef5,:Gf5,:A5,:Af5,:G5,:Gf5,:Ef5,:D5,:Df5,:C5,:A4,:Af4,:G4,:Gf4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Df5,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Ef5,:Df5,:B4,:Bf4,:Af4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Df5,:Ef5,:F5,:Ef5,:Df5,:B4,:Bf4,:B4,:Df5,:D5,:Df5,:B4,:Bf4,:B4,:D5,:E5,:D5,:B4,:Bf4,:A4,:Af4,:Gf4,:D4,:Gf4,:Af4,:A4,:Bf4,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Bf4,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Bf4,:F5,:Gf5,:Af5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:Df6,:E6,:D6,:Df6,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Df4,:Gf4,:F4,:E4,:Df4,:A4,:G4,:Df4,:B4,:A4,:G4,:F4,:Ef4,:Ef4,:Df4]
b[0]=[1,2.634,0.167,0.189,1.994,0.211,0.167,0.669,0.589,0.4,0.306,2.125,0.386,0.215,5.006,2.121,0.149,0.164,1.841,0.16,0.149,0.659,0.426,0.295,0.204,1.437,0.266,0.178,1.976,0.255,0.193,0.196,0.135,0.164,0.171,0.113,0.462,0.182,1.184,0.275,0.242,2.527,0.367,0.28,0.173,0.16,1.504,0.393,4.391,1.957,3.156,5.761,2.045,0.16,0.142,1.721,0.127,0.196,0.557,0.448,0.44,1.11,1.557,0.196,0.153,1.499,0.226,0.229,0.644,0.378,0.287,0.131,0.335,0.055,0.542,0.324,0.218,2.547,1.055,0.462,0.269,0.211,0.2,0.211,0.156,0.236,0.073,0.531,0.251,0.284,2.638,0.335,0.16,0.138,1.321,0.135,0.171,0.131,1.099,0.167,0.131,0.084,1.31,0.251,0.258,0.233,0.544,0.047,0.569,0.626,2.86,0.731,0.64,0.524,0.071,0.52,0.471,0.362,0.085,0.457,0.74,0.453,0.095,0.524,0.875,0.402,0.095,0.491,0.58,0.653,0.66,0.788,2.097,0.573,0.093,0.728,0.631,2.394,2.92,0.48,0.138,0.653,0.477,0.646,0.604,0.708,1.084,0.564,0.155,0.478,0.349,1.503,2.285,0.282,0.155,0.173,2.363,0.444,0.366,0.278,0.271,0.176,1.133,0.333,0.171,0.136,0.502,0.446,0.313,2.625,0.533,0.346,0.226,0.173,0.204,0.218,0.173,0.085,0.1,0.116,0.122,0.335,0.14,0.182,0.109,0.173,0.12,0.118,0.151,1.946,0.189,0.302,0.073,0.076,0.089,0.047,0.067,0.06,0.058,0.069,0.08,0.055,0.069,0.042,0.082,0.082,1.028,0.126,0.267,0.096,0.062,0.089,0.049,0.095,0.085,0.064,0.095,0.08,0.073,0.069,0.082,0.056,0.096,0.044,0.156,1.403,0.32,0.195,0.233,6.409,3.063,0.18,0.124,1.937,0.124,0.178,0.598,0.491,0.62,1.161,2.172,0.238,0.102,0.606,0.6,3.091,0.207,0.153,1.346,0.162,0.133,0.508,0.484,0.546,1.926,1.01,0.271,0.198,0.196,0.169,0.147,0.469,0.444,0.558,1.963,0.777,0.182,0.151,0.189,0.115,0.135,0.566,0.557,0.906,3.629,0.946,0.236,0.995,1.044,2.703,1.181,1.483,3.866,5.723,1.168,0.951,1.384,2.832,0.819,7.308]

#Jean-Pierre Rampal
a[0]=[:r,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:C6,:B5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Gf4,:G4,:C5,:Gf4,:G4,:Df5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Af4,:B4,:Df5,:E5,:Af5,:Af5,:B5,:Df6,:Ef6,:Bf5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Af4,:Df4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Df5,:Ef5,:Gf5,:A5,:Af5,:G5,:Gf5,:Ef5,:D5,:Df5,:C5,:A4,:Af4,:G4,:Gf4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Df5,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Ef5,:Df5,:B4,:Bf4,:Af4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Df5,:Ef5,:F5,:Ef5,:Df5,:B4,:Bf4,:B4,:Df5,:D5,:Df5,:B4,:Bf4,:B4,:D5,:E5,:D5,:Cs5,:B4,:Bf4,:A4,:Af4,:Gf4,:D4,:Gf4,:Af4,:A4,:Bf4,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Df5,:Bf4,:Gf5,:F5,:Gf5,:F5,:F5,:Bf4,:F5,:Gf5,:Af5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:Df6,:E6,:D6,:Df6,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Df4,:Gf4,:F4,:E4,:Df4,:A4,:G4,:Df4,:B4,:A4,:G4,:F4,:Ef4,:Ef4,:Df4]
b[0]=[1,1.409,0.106,0.102,0.704,0.078,0.091,0.453,0.337,0.286,0.206,1.517,0.203,0.197,4.995,1.21,0.107,0.093,0.569,0.046,0.102,0.366,0.238,0.248,0.228,1.167,0.216,0.164,1.303,0.206,0.125,0.132,0.08,0.109,0.091,0.091,0.267,0.202,1.176,0.199,0.154,1.162,0.186,0.139,0.077,0.078,1.094,0.229,2.191,1.281,2.624,4.332,1.206,0.126,0.086,0.641,0.103,0.093,0.396,0.367,0.184,0.189,0.659,0.113,0.055,0.267,0.084,0.075,0.234,0.164,0.168,0.122,0.115,0.042,0.282,0.149,0.173,1.29,0.289,0.184,0.215,0.125,0.106,0.104,0.094,0.09,0.057,0.244,0.061,0.123,0.863,0.205,0.106,0.106,0.53,0.073,0.071,0.116,0.235,0.084,0.042,0.115,0.399,0.104,0.055,0.058,0.245,0.052,0.27,0.19,1.38,0.489,0.216,0.189,0.045,0.299,0.181,0.208,0.045,0.332,0.327,0.215,0.087,0.338,0.267,0.158,0.071,0.142,0.183,0.364,0.228,0.251,0.65,0.237,0.051,0.266,0.177,1.387,2.544,0.187,0.094,0.145,0.173,0.342,0.226,0.194,0.319,0.155,0.08,0.193,0.173,0.64,0.955,0.147,0.11,0.103,1.576,0.273,0.109,0.122,0.119,0.086,0.197,0.102,0.039,0.109,0.289,0.268,0.372,1.181,0.245,0.102,0.128,0.118,0.118,0.068,0.119,0.058,0.087,0.015,0.044,0.126,0.131,0.068,0.057,0.058,0.1,0.071,0.048,0.048,0.614,0.112,0.086,0.044,0.078,0.06,0.075,0.084,0.254,0.093,0.046,0.094,0.103,0.077,0.203,0.049,0.046,0.052,1.357,0.993,0.096,0.089,0.315,0.065,0.093,0.345,0.263,0.199,0.373,0.787,0.163,0.049,0.319,0.179,1.338,0.109,0.075,0.491,0.089,0.125,0.47,0.472,0.647,1.337,0.21,0.131,0.118,0.125,0.144,0.1,0.428,0.428,0.451,0.805,0.125,0.152,0.109,0.109,0.125,0.107,0.432,0.457,0.673,2.575,0.325,0.081,0.421,0.393,2.241,0.625,0.58,4.407,4.529,0.572,0.441,0.672,1.399,0.283,7.843]

# James Galway
a[0]=[:r,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:C6,:B5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Gf4,:G4,:C5,:Gf4,:G4,:Df5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Af4,:B4,:Df5,:E5,:Af5,:Af5,:B5,:Df6,:Ef6,:Bf5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Af4,:Df4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Df5,:Ef5,:Gf5,:A5,:Af5,:G5,:Gf5,:Ef5,:D5,:Df5,:C5,:A4,:Af4,:G4,:Gf4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Df5,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Ef5,:Df5,:B4,:Bf4,:Af4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Df5,:Ef5,:F5,:Ef5,:Df5,:B4,:Bf4,:B4,:Df5,:D5,:Df5,:B4,:Bf4,:B4,:D5,:E5,:D5,:B4,:Bf4,:A4,:Af4,:Gf4,:D4,:Gf4,:Af4,:A4,:Bf4,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Bf4,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Bf4,:F5,:Gf5,:Af5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:Df6,:E6,:D6,:Df6,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Df4,:Gf4,:F4,:E4,:Df4,:A4,:G4,:Df4,:B4,:A4,:G4,:F4,:Ef4,:Ef4,:Df4]
b[0]=[1,2.337,0.143,0.096,0.789,0.134,0.098,0.6,0.261,0.201,0.19,1.994,0.372,0.281,3.761,1.203,0.123,0.065,0.272,0.102,0.093,0.325,0.19,0.16,0.171,1.203,0.417,0.181,0.836,0.091,0.091,0.145,0.083,0.102,0.367,0.094,0.223,0.198,1.065,0.517,0.23,2.416,0.366,0.138,0.094,0.098,0.923,0.19,2.922,1.673,2.157,4.033,1.092,0.091,0.102,0.232,0.127,0.109,0.555,0.19,0.181,0.189,0.6,0.094,0.089,0.194,0.091,0.085,0.377,0.143,0.134,0.141,0.47,0.083,0.33,0.183,0.225,1.829,0.412,0.412,0.187,0.112,0.114,0.1,0.098,0.414,0.053,0.359,0.145,0.234,1.622,0.379,0.185,0.181,0.595,0.105,0.067,0.127,0.312,0.087,0.145,0.141,0.452,0.149,0.105,0.127,0.321,0.094,0.281,0.274,2.188,0.657,0.457,0.468,0.074,0.39,0.192,0.183,0.04,0.194,0.18,0.176,0.054,0.176,0.196,0.23,0.053,0.221,0.294,0.55,0.386,0.941,1.277,0.463,0.085,0.328,0.321,1.769,2.159,0.526,0.058,0.178,0.283,0.55,0.332,0.557,0.37,0.189,0.051,0.223,0.243,1.339,2.139,0.653,0.23,0.178,2.099,0.317,0.096,0.094,0.074,0.105,0.889,0.134,0.094,0.094,0.423,0.229,0.207,1.696,0.243,0.123,0.141,0.1,0.071,0.089,0.078,0.129,0.087,0.102,0.138,0.143,0.141,0.132,0.098,0.141,0.094,0.096,0.131,1.893,0.196,0.141,0.087,0.077,0.069,0.073,0.076,0.059,0.105,0.058,0.082,0.069,0.076,0.076,0.064,0.066,0.075,0.055,0.074,0.063,0.067,0.06,0.055,0.09,1.364,0.212,0.092,0.093,0.076,0.063,0.073,0.071,0.071,0.067,0.081,0.061,0.08,0.063,0.088,0.087,0.073,0.068,0.076,0.063,0.078,0.066,0.077,0.067,0.086,0.092,0.065,1.498,0.109,0.093,0.136,4.922,1.065,0.1,0.09,0.24,0.089,0.09,0.373,0.229,0.14,0.143,1.53,0.603,0.093,0.744,0.417,1.341,0.096,0.096,0.278,0.094,0.093,0.465,0.323,0.415,0.746,0.455,0.102,0.137,0.129,0.102,0.096,0.37,0.232,0.187,0.561,0.278,0.184,0.098,0.13,0.142,0.096,0.553,0.607,1.021,1.564,0.418,0.055,0.229,0.239,1.848,0.678,0.448,3.482,3.158,0.464,0.514,0.643,2.39,0.536,8.221]

# Emmanuel Pahud
a[0]=[:r,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:C6,:B5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Gf4,:G4,:C5,:Gf4,:G4,:Df5,:F5,:E5,:Df5,:Bf4,:Gf4,:G4,:B4,:Af4,:B4,:Df5,:E5,:Af5,:Af5,:B5,:Df6,:Ef6,:Bf5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Af4,:Df4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Gf5,:F5,:Ef5,:Df5,:Bf4,:Df5,:Ef5,:Gf5,:A5,:Af5,:G5,:Gf5,:Ef5,:D5,:Df5,:C5,:A4,:Af4,:G4,:Gf4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:Gf4,:F4,:E4,:Ef4,:F4,:E4,:Ef4,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Df5,:D4,:F4,:E4,:Df4,:C4,:Df4,:Gf4,:A4,:D4,:Gf4,:F4,:D4,:Df4,:Ef5,:Df5,:B4,:Bf4,:Af4,:Ef4,:Gf4,:Af4,:Bf4,:Df5,:Ef5,:Df5,:Ef5,:F5,:Ef5,:Df5,:B4,:Bf4,:B4,:Df5,:D5,:Df5,:B4,:Bf4,:B4,:D5,:E5,:D5,:B4,:Bf4,:A4,:Af4,:Gf4,:D4,:Gf4,:Af4,:A4,:Bf4,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Ef5,:Df5,:Bf4,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Gf5,:F5,:Bf4,:F5,:Gf5,:Af5,:Bf5,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf5,:Df6,:E6,:D6,:Df6,:Bf5,:A5,:B5,:Af5,:G5,:A5,:Gf5,:F5,:E5,:Df5,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Bf4,:A4,:B4,:Af4,:G4,:A4,:Gf4,:F4,:E4,:Df4,:Df4,:Gf4,:F4,:E4,:Df4,:A4,:G4,:Df4,:B4,:A4,:G4,:F4,:Ef4,:Ef4,:Df4]
b[0]=[1,1.583,0.131,0.091,1.437,0.12,0.123,0.651,0.376,0.273,0.516,2.777,0.286,0.18,7.218,1.664,0.136,0.132,1.032,0.091,0.129,0.562,0.328,0.28,0.562,1.712,0.228,0.193,2.572,0.261,0.147,0.274,0.136,0.09,0.422,0.088,0.276,0.37,2.02,0.263,0.137,3.161,0.374,0.218,0.139,0.097,0.869,0.251,3.524,3.245,3.449,6.107,1.401,0.111,0.094,1.027,0.119,0.096,0.459,0.282,0.282,0.51,0.975,0.109,0.124,0.792,0.094,0.098,0.463,0.235,0.229,0.233,0.371,0.089,0.327,0.192,0.227,2.459,0.692,0.422,0.278,0.284,0.184,0.141,0.092,0.133,0.053,0.131,0.094,0.147,1.951,0.424,0.178,0.147,1.014,0.096,0.087,0.097,0.652,0.095,0.088,0.049,1.106,0.103,0.096,0.131,0.694,0.096,0.324,0.424,2.833,0.831,1.026,0.646,0.093,0.451,0.291,0.414,0.051,0.321,0.419,0.587,0.069,0.948,1.855,0.859,0.098,0.371,0.453,0.616,0.6,0.976,1.629,1.018,0.088,0.241,0.376,2.963,3.953,1.061,0.098,0.604,0.359,0.659,0.471,0.88,2.286,0.869,0.092,0.327,0.3,3.049,2.918,0.373,0.139,0.135,1.937,0.392,0.227,0.096,0.1,0.096,0.776,0.135,0.098,0.057,0.514,0.319,0.284,1.894,0.331,0.224,0.296,0.12,0.153,0.224,0.139,0.143,0.229,0.184,0.096,0.229,0.094,0.098,0.129,0.094,0.057,0.082,0.098,1.304,0.184,0.276,0.063,0.078,0.055,0.084,0.055,0.084,0.045,0.043,0.057,0.278,0.929,0.092,0.324,0.104,0.096,0.08,0.051,0.049,0.071,0.063,0.073,0.059,0.059,0.053,0.065,0.057,0.145,1.114,0.324,0.09,0.098,7.888,1.616,0.057,0.092,1.537,0.09,0.094,0.694,0.408,0.382,0.882,1.814,0.455,0.055,0.745,0.416,1.902,0.135,0.1,1.065,0.133,0.102,0.655,0.512,0.835,3.933,0.478,0.229,0.186,0.235,0.178,0.147,0.598,0.416,0.608,1.024,0.504,0.235,0.235,0.229,0.186,0.188,0.741,0.51,0.978,3.222,0.584,0.086,0.524,0.363,3.673,0.927,0.694,6.353,4.145,1.114,0.792,1.298,2.124,0.435,13.131]
オープンソースソフトウェアだけで、このようなデータが作成できますので、音楽や演奏の解析等へのSonic Piのさらなる活用が期待されます。

Sonic Piを離れますが、
X軸を時間、Y軸を音程として5人の奏者を色分けしてプロットすると下記のようになります。まず、全長、最高音の部分、トリルの部分などの位置関係から眺めると興味深いものです。

X:Time , Y:Pitch , Black(Moyse), Red(Gazzelloni), Green(Rampal), Blue(Galway), Magenta(Pahud)

全演奏時間で正規化すると、ある程度類似点が見えてきますが、間の取り方は様々です。

X:Normalised Time , Y:Pitch , Black(Moyse), Red(Gazzelloni), Green(Rampal), Blue(Galway), Magenta(Pahud)

さらに、拡大してフレーズごとに比較するなど試してみると興味深いと思われます。



ランダムな音程が旋律に変化 (Morphing from random to melodies)


ランダムな音程が、だんだんと元の旋律に近づいて行きます。(音のモーフィングとも言えます。)

1) 元となる旋律の音程だけをランダムな音程に置き換えて、ランダムな音程で演奏します。

2) 一音ずつ再度乱数を作り、前回と今回のランダムな音程を比べて、元の旋律に近づいた方を採用して演奏します。(同じ音程だけずれていた場合は上下のずれが反転する場合もあります.)

ずれの絶対値和がゼロ(=元の旋律)になるまで、2)に戻って繰り返します。

CGの
コンピュータ画伯 (情報処理学会誌2017.6)のアイデアを音に適用しました。

下記の例では、Hey Judeの最初の4小節を使っており、ランダムから12回かかって元の旋律になります。
乱数の種の番号(use_random_seed)、乱数の上下限(low,high)の値を変えると様子が変わります。
最後の1音が、なかなか修正されない場合があります。

# Random to Melody by Sonic Pi
use_random_seed 0
use_debug false
use_bpm 180
use_synth :piano
low=:C4.to_i
high=:C6.to_i
# Hey Jude 2 vars
a=[:C5,:A4,:A4,:C5,:D5,:G4,:G4,:A4,:Bf4,:F5,:F5,:E5,:C5,:D5,:C5,:Bf4,:A4]
b=[1.0,2.5,0.5,0.5,0.5,3.0,0.5,0.5,1.0,1.5,0.5,0.5,0.5,0.5,0.25,0.25,2.0]
da=[]
s=0
for i in 0...a.length
  da[i]=(rrand_i(low,high)-a[i].to_i)
  # da[i]=-12  # 一オクターブ下から始まるメロディーに
  # da[i]=-a[i].to_i+60  # 全ての音が :C4 から始まるメロディーに
  play a[i]+da[i], amp:3,sustain:2,release:2
  sleep b[i]
  s+=da[i].abs
end
puts "Object func=#{s}"
while s>0
  sleep 2
  s=0
  for i in 0...a.length
    r=a[i]+rrand_i(-da[i].abs, da[i].abs);
    if ( (a[i]-r).abs <= da[i].abs ) then
      da[i]=(a[i]-r).abs;
    end
    play a[i]+da[i], amp:3,sustain:2,release:2
    sleep b[i]
    s+=da[i];
  end
  puts "Object func=#{s}"
end


コメント行の下記どちらかを生かすと最初のメロディーを指定できます。
# da[i]=-12 # 一オクターブ下から始まるメロディーに
# da[i]=-a[i].to_i+60 # 全ての音が :C4 から始まるメロディーに
2回目からランダムとなるため、あまり面白みがありません。
ランダムの度合いを小さめにする(乱数での音程の変化量を0〜2に制限する)と、よりモーフィング的に聞こえることでしょう。

音程と同様に、時間も変化させると、さらに興味深いと思われます。




最も簡単なライブコーディング体験 (The Simplest Live Coding Experience)


最も簡単なライブコーディングの例

play 60.00, sustain: 30
Runしてから音程を書き換えて、
play 61.00, sustain: 30
再度Run。さらに音程を書き換えて
play 61.20, sustain: 30
再々度Run。これを繰り返します。

上記のようにプログラムを "Run" して音が鳴っている間(30拍伸ばしている)に、60.00 を 60.10 等に書き換えて再度 "Run" します。
続けて、60.20、62.21 等に、70.00、71.05、50.00、51.00 等、次々と書き換えて "Run" し続けると奇妙な音が生成できます。
持続時間は30秒としているので、しばらくすると新たにRunした音が残ってゆきます。
マキシマイザー的な使い方のように、この操作をいくら繰り返して音を重ねても振り切れて音が割れることはないので安心です。

もう一行加えて、音源を左右に振るパン(pan)をランダム(rrand)値として加え

use_random_seed Time.new.usec
play 60.00, sustain: 30, pan: rrand(-1,1)

とすると、ステレオ環境での聴き映えが増します。
リサージュ図形も表示しておくと、変化するので視覚的にも美しく、最初のライブコーディング体験に適当でしょう。
1行目で乱数の系列をRunした時点でのミリ秒(usec)の値でその都度決めています。これがないと、左右のpan値は一定になってしまいます。





LibreOfficeのImpressのサウンドを鳴らす


LibreOfficeのImpressには、MS-OfficeのPowerPointと同様にスライド内で鳴らす音が多数用意されています。
音は、アプリケーション内にWAVファイルとして格納されているので、これを直接Sonic Piで指定して鳴らすことができます。

macOS版のLibreOffice 4.3では、下記のパス内にWAVファイルがあります。
バージョンによってパスは異なるようなので確認が必要です。
下記の例では、パス内にある音ファイルをabc順に再生し続けます。(最後のファイルの後はaに戻ります.)

path="/Applications/LibreOffice.app/Contents/share/gallery/sounds/"
i=0
loop do
  sample path,i
  sleep sample_duration path,i
  i=i+1
end

ファイル名を取得してから配列に入れて利用してみた例は、
s=["apert.wav","apert2.wav","applause.wav","beam.wav","beam2.wav","cow.wav","curve.wav","drama.wav","explos.wav","falling.wav","glasses.wav","gong.wav","horse.wav","kling.wav","kongas.wav","laser.wav","left.wav","nature1.wav","nature2.wav","ok.wav","pluck.wav","roll.wav","romans.wav","soft.wav","space.wav","space2.wav","space3.wav","sparcle.wav","strom.wav","theetone.wav","top.wav","train.wav","untie.wav","ups.wav","wallewal.wav"]
path="/Applications/LibreOffice.app/Contents/share/gallery/sounds/"
for i in 0...s.length
  sample path+s[i]
  sleep sample_duration path+s[i]
  sleep 0.1
end


LibreOfficeのライセンスはGPLですので、音だけを利用してもライセンス上の問題はないと思われます。

Windows10ではWAVファイルが、
C:\Program Files\LibreOffice 5\share\gallery\sounds\
にありましたが、Sonic Piからパスを指定しても鳴りませんでした。(十分な確認はしていません.)
WAVファイルをユーザー領域にコピーして使用すれば鳴ると思われます。

PowerPoint 2016のサウンドを鳴らす方法は、こちら



音感テスト(音程について) Check of Pitch Perception. Acoustic Training.

5つの音を鳴らします。
1音だけわずかにずれていますので、何番目がずれているか当ててください。
上にずれている場合と下にずれている場合があります。
5つ鳴った後で、ログに答えが表示されます。

use_debug false
use_random_seed Time.new.usec
n=5 # 鳴らす音の数
d=0.2*(rrand_i(0,1)*2-1) # 音をずらす量
r=rrand_i(0,n-1)
b=rrand_i(60,72) # 音程の範囲
a=[]
for i in 0...n
  da=0
  da=d if i==r
  a[i]=b
  play a[i]+da,release:0.5
  sleep 0.5
end
puts "Ans.= #{r+1}"

乱数を3回使っています。
1.音をずらす方向を音程を上げる方向にするか、下げる方向にするかを指定するために、0か1の乱数を2倍して1を引いて-1か1として利用しています。
2.音を5回鳴らす内の何回目の音程を変えるか。
3.元となる音程をC4〜C5の間から選択。
乱数の系列をプログラムの実行時のミリ秒の値で決めていますので、同じ乱数にはなりません。



等速で変化するポルタメント(Portamento changing with constant speed)

音程が変化する速度を一定としたポルタメントです。
2つの音程の差が大きければ、それに比例して音程の変化時間が長くなります。
音色によっては、音が途切れてしまいますが、:prophetでは、(ビンテージ)スポーツカーのエンジン音がギアシフトで変わるような音になります。
音色を:zawaにするとザワザワがつながり、その速度をbpmによって変えることができます。:mod_tri等もお勧め。

音を伸ばす長さsustain、音程の移動に要する拍数note_slideは、正の値でなければいけないので絶対値dn.absをとっています。
2つの音が同じ音程となってしまった場合には、新たに音程を作り直すようにしています。while内

use_bpm 240
use_synth :prophet
use_random_seed Time.new.usec
n1=rrand_i(48,72)
n2=n1
loop do
  while n1==n2
    n2=rrand_i(48,72)
  end
  dn=n2-n1
  puts n1,n2,dn
  s=play n1, sustain: dn.abs, note_slide: dn.abs, attack:0, release:0
  control s,note:n2
  sleep dn.abs
  n1=n2
end

play文をループの前に置き、control行だけをループ内に入れて、ループ内で note_slide:の値を変化させることができれば、音色によらず連続音とできますが、実現できていません。



パーリンノイズ音楽(Perlin Noise Music)

パーリンノイズ関数とは、コンピュータ・グラフィックスで活用されている、リアルなゆらぎを持っていて、雲や煙など、いろいろな表現に活用されている乱数を発生させる関数です。小さな変化が続き、時々ある程度大きな変化が起きます。
開発者のKen Perlinさんは、この業績によって(映画の)アカデミー技術賞を受賞しています。

下記では単音を鳴らしているだけですが、1D, 2D, 3Dそれぞれで活用されている関数ですので、複数の音と音色、音の長さとしてみるのも興味のあるところです。
プログラミング言語のProcessingでは、noise()という関数名で実装されており、CGに活用されています。

Ken Perlin本人によるプログラムは、ここ
LianさんによりRubyに移植されたプログラムは、ここ
このRubyのプログラムを、そのままSonic Piで利用することができました。

プログラムでは、ピアノの音色で、半音単位の音程にしています。
play 60+a.to_i, sustain:1
# <<<<< の行の値をいじると、乱数値が変わり、音が変わります。


ここから

def fastfloor(x)
  (x > 0 ? x : x-1).to_i
end

def noise(x, y, z)
  # find unit cube that contains point
  x_ = fastfloor(x) & 255
  y_ = fastfloor(y) & 255
  z_ = fastfloor(z) & 255
  
  # find relative x,y,z of point in cube
  x -= fastfloor(x)
  y -= fastfloor(y)
  z -= fastfloor(z)
  
  # compute fade curves for each of x,y,z
  u, v, w = fade(x), fade(y), fade(z)
  
  # hash coordinates of the 8 cube corners
  a = PT[x_] + y_
  aa = PT[a] + z_
  ab = PT[a+1] + z_
  b = PT[x_+1] + y_
  ba = PT[b] + z_
  bb = PT[b+1] + z_
  
  # and add blended results from 8 corners of cube
  lerp(w, lerp(v, lerp(u, grad(PT[aa  ], x  , y  , z  ), grad(PT[ba  ], x-1, y  , z  )),
               lerp(u, grad(PT[ab  ], x  , y-1, z  ), grad(PT[bb  ], x-1, y-1, z  ))),
       lerp(v, lerp(u, grad(PT[aa+1], x  , y  , z-1), grad(PT[ba+1], x-1, y  , z-1)),
            lerp(u, grad(PT[ab+1], x  , y-1, z-1), grad(PT[bb+1], x-1, y-1, z-1)))
       );
end

def fade(t); t * t * t * (t * (t * 6 - 15) + 10); end
def lerp(t,a,b); a + t * (b - a); end
def grad(_hash, x, y, z)
  h = _hash & 15
  u = h<8 ? x : y
  v = h<4 ? y : ((h==12 || h==14) ? x : y)
  ((h & 1) == 0  ? u : -u) + ((h & 2) == 0 ? v : -v)
end

PT_PERM =[ 151,160,137,91,90,15,
           131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
           190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
           88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
           77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
           102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
           135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
           5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
           223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
           129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
           251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
           49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
           138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180    ]
PT = []; (0...256).each { |i| PT[256+i] = PT_PERM[i]; PT[i] = PT_PERM[i] }

# 以上がPerlin Noise関数の定義部分で、いじらずにそのまま用います。
# 以下が演奏部分で、関数にパラメータを与えてから乱数値を得て、playしています。

use_random_seed Time.new.usec  # <<<<<
use_synth :piano
x=rand # <<<<<
inc=0.015 * 3  # <<<<<
loop do
  a=(noise x+inc, x, 0.0 )* 20 # <<<<<
  
  a=-60 if a<-60
  puts a
  play 60+a.to_i, sustain:1
  sleep 0.1
  x=x+inc
end

上記プログラムで、
use_random_seed 0
とし、
inc=0.015 * 3 黒線
inc=0.015 * 5 赤破線
とした場合の乱数値をそれぞれプロットすると、下記のグラフのようになります。




ニュートン法による方程式の解の音楽 (Equation Solving Music, Newton Method)

強力な方程式の解法であるニュートン法を用い、1変数の3次関数を数値微分を使って解き、初期値から収束までの変数値を音として鳴らしています。
初期値によっては、変数値が振動してしまい、収束しにくい関数を例として使用しています。
f(x)=x^3 - 3*x^2 +x +3


xの初期値を-1から1の間でランダムに与え、ループ毎に変数値をx*5+60とした音を鳴らし、収束時にはシンバルを、ループが100以上で収束しない場合にはブザーを鳴らし、その後は新たな初期値から計算を繰り返します。
迅速に2次収束する場合、振動してしまう場合などを音で聞き分けることができます。

use_debug false
define :fun do |x|
  return x**3 -3*x**2 +x +3  # Equation
end

loop do
  x=rrand(-1,1)   # initial value
  lop=0
  f=fun x
  while f.abs>0.00001  # Convergence criterion
    lop=lop+1
    x1=x*1.001
    f1=fun x1
    df=(f-f1)/(x-x1)
    x=x-f/df
    f=fun x
    play 60+x*5 if 60+x*5 >0
    puts "Loop= #{lop}, x= #{x}, ObjectFunc= #{f}"
    sleep 0.25
    sample :drum_cymbal_closed
    sleep 0.25
    if lop>100 then
      puts "##### Diverged ##########"
      synth :square,note: :C3,sustain:2
      sleep 3
      break
    end
  end
  if f.abs<=0.00001
    sample :drum_cymbal_hard,amp:3
    puts "----- Converged ----------"
    puts "Loop= #{lop}, x= #{x}, ObjectFunc= #{f}"
    sleep 1
  end
end

2変数以上の問題を、Newton-Raphson法で解き、複数の音を鳴らしてみるというのも興味深いと思われます。



波形アートの作成法 (Making of Sound Wave Art)

サウンド・アート、Sound Art, Soundwave Art, Waveform Art

Sonic Piは使いませんが、本家のタイトル "Sonic Pi, The Live Coding Music Synth for Everyone" の読み上げ音声をアートにして見ました。
概要
I) 何らかの音を用意。必要に応じてAudacityで編集。ここではmacOSのsayコマンドを利用
II) pythonプログラムのwav2vecを使ってwavファイルをSVGファイルに変換する。Python言語についての知識は必要ありません。
III) SVGファイルをInkscapeで読み込んで編集/加工する。

詳細
1) 読み上げは、(これだけはプロプライエタリーですが)macOSのsayコマンドで、読み上げのwavファイルを作成。(声を日本語用にすれば日本語の読み上げもでき、多数の言語に対応)
Sonic Piでの録音、他の音源でもなんでも可。

macOSのターミナルでは、
say Sonic Pi - The Live coding Music Synth for Everyone -o SonicPi.wave
注:wavファイルの拡張子は.waveとする必要があるようです。
声を変えたい場合には、[システム環境設定]→[音声入力と読み上げ]→[テキスト読み上げ]→[システムの声]を変更します。

2) macOSには初めからpythonが入っているので、インストールの必要はありません。Windowsでは別途インストールが必要で、その後、パスの設定等をすれば、コマンドプロンプトで同様に使用できると思われます。(以下はmacOSの場合の例です。)
GitHubのCristoperさんのwav2vecからPython言語のwav2vecプログラムを入手します。(他にpipコマンド等の環境を構築していれば直接実行できるプログラムを入手することもできます。)
ページ内の緑色ボタン[Clone or download]→[Download ZIP]からダウンロードします。
展開すると、[wav2vec-master]というフォルダができます。
フォルダを適当な場所に移動するか、または、そのままダウンロードフォルダに置いたままでも使用できます。
(pythonに対して、実行されるwav2vecプログラムの位置と、入力されるwavファイルの位置を正しく指定することによって、実行後にsvgファイルが得られます。) ターミナルで、キーボードからcdとその後ろに半角スペースを入力してから、フォルダをターミナル画面にドロップし(自動的にフォルダのフルパスが入力されて)、returnキーを押すと、ターミナルのカレントディレクトリが、wav2vec-masterに移動します。
MP3等の音源を使う場合には、Audacity等でWAVに変換しておく必要があります。

音のファイルSonicPi.waveもこのフォルダ内に移動してから、

python wav2vec.py --downtoss 10 SonicPi.wave > SonicPi.svg

とすると、ベクトルグラフィックスのSVG形式のファイルが生成されます。(他のフォルダに生成されるかもしれません)
ここで、パラメータの --downtoss 10 は、サンプリング点を1/10に減らすという指定です。
指定しない場合、通常のCD等の音源のサンプリング周波数44.1kHzの場合、図にした時に1秒間で44100個のノードが生成するため、点の数を減らさないと図の編集が困難になる場合があります。

10分程度の音楽等でも。downtossを1000程度にすれば1MB程度のSVGファイルに変換でき、利用可能です。

3) SonicPi.svgをInkscapeで読み込みます。(Illustrator等でも可)

3-1) 波形を横に伸ばして適当なサイズにします。(先にwav2vecで出力サイズを指定しておくことも可)

3-2) この図は、一つのオブジェクトとなっているので、メニューの[パス]→[オブジェクトをパスへ]によって、パスに変換します。(なぜか、この操作で自動的に線が細く表示されるようになることがありました。)元がステレオ音の場合は、左右チャンネルの波形がグループ化されているので、先に[グループ解除]します。
3-3) 必要に応じて[ノードツール]を選んで(下図)、不要部分を消します。(この場合末尾の無音部分を消去)1/10に減らしているとはいえ、膨大な数のノードが見えます。

3-4) ストロークにグラデーションをかけます。(注意:塗り色(フィル)のグラデーションではありません。)
3-4-1) 波形を選択してから、[フィル/ストローク]を開き、[ストロークの塗り]から[線形グラデーション]のマークをクリックします。
3-4-2) 次に、画面左下にある[グラデーションツール]を選択すると、波形上に左右方向にグラデーション設定の赤線が現れます。
3-4-3) 赤線の左端の四角形をクリックして、パレットで適当な色を与えます。
3-4-4) 赤線の適当な場所で、線の真上をダブルクリックすると、ダイヤマークが現れるので、パレットで色を与えるとグラデーションの中間点の色とできます。この点はドラッグして左右に移動できます。これを繰り返して複数色のグラデーションを作成します。線の両端を移動して斜め方向や、縦方向のグラデーションとすることもできます。放射状のグラデーションにもできます。

3-4-5) [オブジェクトの変形に従ってグラデーションも変形]のボタンを押しておきます。図の3番目のボタンです。これを押していないと、波形を移動してもグラデーション設定が移動しないので、グラデーションが変わってしまいます。

4) Copy&Pasteまたは複製で3〜4つにします。
5) [フィルター]→[散乱]→[葉っぱ]等で飾ります。(葉っぱの大きさは線の太さに依存します.)
・わずかに[ぼかし]て少し拡大し、下側に影として置く。
・[フィルター]→[リッジ]等で飾る。
・透明度を変える。
など、いろいろ試して重ねる順番なども検討します。
・背景に四角形置いて背景色を与える、写真等を置く、写真を波形でマスクする等も効果的です。
・パスの両端が開いているので、それを繋げて、塗り色を与えるのも効果的でしょう。塗り色の代わりにパターンを使うこともできます。
・[パスの簡略化]は、4回程度ならば波形が原型をとどめていました。
・ノードを表示して全てを選択して[選択ノードの種類を対称に]とすると曲線化して下記のようになり、これも活用できそうです。(今回は利用せず.)


6) 文字を入力します。
完成ファイルの例は、Inkscape SVG file (このファイルは、ブラウザでは表示されない場合があります。完成波形は枠外に置いてあります。右クリックで保存してからInkscape等で開いてください。)

作成した図は、ベクトルグラフィックスですので、拡大による劣化はなく、カラー印刷してポスター化することもできます。
Sonic Piでの録音、自分の声や歌、楽器演奏など何でも音を波形のアート風にできます。プレゼントにも適しています。
音の加工とグラフィックを融合したワークショップなどにも適当でしょう。
2017年10月現在、Googleでのwav2vecのヒット数は 23件であり、日本語はゼロでしたので、しばらくは希少性もあるでしょう。

さらにSonic Piから離れますが、
他の数値データ、グラフ等をSVG化してInkscapeで読み込みグラフィックス化するということも、Processing言語で描画後、SVGファイルとして出力することにより、容易にできます。
ellipseやrectは楕円や長方形のオブジェクトとなり、strokeとfillが別々に生成されます。beginShape(),endShape()で生成した折れ線等は一つのパスとして生成されます。Inkscape上でグループ解除すれば加工が容易にできます。SVGファイルの生成は、beginRecordを使うか、またはcreateGraphicsを使うなどでできます。


Inkscape 1.0 beta1 が、2019.9に公開されました。
改良点も多く素晴らしいので使っていますが、その中で見つけたバグとその回避法などです。
1) 起動後、四角形等を描くとツールコントロールバーの表示が消える。(アイコンが消えて場所だけ残る)(回避法:インポートまたはプリント等の画面を開き、キャンセルする)
2) レイヤーウィンドウ等が開かない。(回避法:インポートまたはプリント等の画面を開き、キャンセルする)
3) レイヤーのブレンドモードが動作しない。ver.0.92で設定したモードの表示は正常にされる。
4) パス→分割 で、文字をパスによって切断できない。(回避法:文字をパス化し、グループ解除し、結合してから分割する)
2019.12に Inkscape 1.0 beta2 が公開され、1,2,3は解消されたようです。




参考
このような波形アートの作成サービスをしているサイトもあります。
Voice Art Galley (何年か前にここを見つけ、オープンソースだけを使って、さらに容易な手順で実現したかったのがきっかけ.)
Waveform Artist - MP3 to Waveform Poster
SOUNDVIZ
BespokenArt

さらに手の込んだアート作品は、
SoundWaves ART




将棋の棋譜の音楽化 (Shogi Music)

音楽プログラミング言語Sonic Piによって将棋の棋譜ファイル(CSA標準形式)を読み込み、音楽にしました。

Youtubeに掲載したビデオでは、現在旬と思われる4つの棋譜を連続して演奏しています。
1.藤井聡太(四段) vs 佐藤天彦(名人)
2.藤井聡太(五段) vs 羽生善治(竜王)
3.藤井聡太(六段) vs 杉本昌隆(七段) 師弟対決
4.PONANZA vs 佐藤天彦(名人) コンピュータ側の勝利

棋譜は盤面の形で、画面右下のログ内にテキストで表示されます。ログの表示領域のサイズを調整すると、静止した画面上で駒の動きを観察できます。

OpenShot Video Editorで作成

棋譜には、CSA標準ファイル形式を用いました。(半角英数だけで表示できて簡便なのを利点と考えて採用)
CSA棋譜ファイルは 将棋DB2等から入手できます。
将棋DB2では、棋譜表示画面の左下の [棋譜の書き出し]->[CSA形式] で表示しで、コピーし、保存したファイルがそのまま読み込み用に使用できます。
棋譜ファイルのサンプルは、Sample_Shogi_kifu.txt (中央の歩だけが動いて投了)

・駒の動きのX座標の値を音程として、移動の前後を連続変化させた音として鳴らしています。同時に重ねてY座標についても鳴らしていますので、このままではXとYの区別はつきませんが、少しずらして鳴らすなどでは聴感上あまり効果がありませんでしたのでそのままにしています。
・駒の種類によって音色を変えています。
・成駒には、ディストーションをかけています。
・相手の駒を取った場合と、駒台からの打駒の場合は、別の音も鳴らしています。
・先手を左側から、後手を右側のスピーカーから鳴らしています。
座標の変化を聞き分けるのは容易でなく、また序盤戦の棋譜は似ているため、どれもかなり類似しています。(Ponanzaは少し異なります.)
音の鳴らし方、音色等はまだまだ考慮不足です。
当初は、音を聞いただけで盤面が想定可能となるような可聴化も念頭にありました。
同様の手順で、囲碁やチェスの棋譜も容易に音として活用できます。

ソースコードは、まだバグが残っていると思われますが、
==========
# SonicPiによる将棋の棋譜ファイルの演奏
# Shogi game record music by Sonic Pi,  2018.4.1 Hiroshi Tachibana

# 棋譜データを読み込み、駒の動きを音にします。
# Sonic Piのログ表示領域を適当なサイズにしておくと、棋譜をテキストとして、盤面が静止した状態で観察しながら音を聞くことができます。
# 棋譜には、"CSA標準ファイル形式"を用います。(半角英数だけで表示できて簡便なのを利点と考えて採用)
# http://www.computer-shogi.org/protocol/record_v22.html

# 将棋盤は、右上が一1、左下が九9
# 一手の前後の動きのXY座標をそれぞれ、座標変化をポルタメントで変化させた2つの音として同時に鳴らし、先手の音を左側(pan:-1)、後手の音を右側(pan:1)としています。
# 駒の種類によってsynthの音色を変えています。成駒にはディストーションをかけました。
# 相手の駒を取った場合と駒台から打った場合には、特に別の音も鳴らしています。

# CSA規格中、盤面座標の数字は移動前と移動後の4桁連続のみ場合しか扱っていません。
# 対局データの開始は、先頭文字が%でなくなった時にしています。
# 最終行の判定は、先頭文字の+-が、%になった時にしており、途中に%行があるとそこで停止してしまいます。

# 棋譜ファイルの形式は CSA標準で、将棋DB2 https://shogidb2.com/ 等から入手できる。
#   棋譜表示画面の左下の [棋譜の書き出し]->[CSA形式] で表示し、コピーして保存する.
path="藤井聡太 四段 vs. 佐藤天彦 名人 第11回朝日杯将棋オープン戦本戦.csa"
#path="藤井聡太 五段 vs. 羽生善治 竜王 第11回朝日杯将棋オープン戦準決勝.csa"
#path="藤井聡太 六段 vs. 杉本昌隆 七段 第68期王将戦一次予選.csa"
#path="Ponanza_佐藤名人.txt"

use_bpm 80       # 速度の設定
use_debug false

# 9×9の2次元配列の作成。各要素はスペース3つ"   "
ban=Array.new(9,"   ")
ban.length.times{|i|
  ban[i]=Array.new(9,"   ")
}

#XY=[:C4,:D4,:E4,:G4,:A4,:C5,:D5,:E5,:G5] # XY座標の音程
XY=[:E3,:G3,:C4,:E4,:G4,:C5,:E5,:G5,:C6] # XY座標の音程
komaS=["FU","TO","KY","NY","KE","NK","GI","NG","KI","KA","UM","HI","RY","OU"]
# 駒の種類による音色、成り駒には、distortionをかける
komaSound=[:beep,:beep,        # 歩 FU,NF
           :blade,:blade,      # 香車 KY,NY
           :chipbass,:chipbass,# 桂馬 KE,NK
           :tri,:tri,          # 銀 GI,NG
           :square,            # 金 KI
           :mod_tri,:mod_tri,  # 角 KA,UM
           :mod_saw,:mod_saw,  # 飛車 HI,RY
           :zawa]              # 王 OU

d=[]
open(path){|f| d = f.readlines}
i=0
while(d[i].slice(0,1) != "+")  # 駒の初期配置を棋譜から読み込む。+で先手の手が始まる前までのPで始まる9行。
  if d[i].slice(0,1)=="P" then # 行の先頭がP
    k=d[i].slice(1,1).to_i-1
    ban[8][k]=d[i].slice(2,3)
    ban[7][k]=d[i].slice(5,3)
    ban[6][k]=d[i].slice(8,3)
    ban[5][k]=d[i].slice(11,3)
    ban[4][k]=d[i].slice(14,3)
    ban[3][k]=d[i].slice(17,3)
    ban[2][k]=d[i].slice(20,3)
    ban[1][k]=d[i].slice(23,3)
    ban[0][k]=d[i].slice(26,3)
    #   駒の初期配置の表示
    # puts k+1,ban[8][k], ban[7][k] ,ban[6][k] ,ban[5][k] ,ban[4][k] ,ban[3][k] ,ban[2][k] ,ban[1][k] ,ban[0][k]
  end
  i=i+1
end
puts
# 駒のない位置は、スペースとする
for ii in 0..8
  for jj in 0..8
    ban[ii][jj]="   " if ban[ii][jj]==" * "
  end
end

# 駒の全体配置を表示する
puts 0  # 手数
for ii in 0..8
  puts ban[8][ii],ban[7][ii] ,ban[6][ii] ,ban[5][ii] ,ban[4][ii] ,ban[3][ii] ,ban[2][ii] ,ban[1][ii] ,ban[0][ii]
end

#ファイル中の位置jを先手の初手の位置に移動する。
j=i+1

while(d[j].slice(0,1) != "%")
  # puts j-i,d[j]  # 手数、棋譜での表記
  sente=true if d[j].slice(0,1)=="+"  # +で始まる行が先手の手
  sente=false if d[j].slice(0,1)=="-" # -で始まる行が後手の手
  
  pos1=d[j].slice(1,2) # 移動前の位置
  pos2=d[j].slice(3,2) # 移動後の位置
  koma=d[j].slice(5,2) # 移動後の駒(成っている場合もある)
  
  # 駒の音色
  km=99
  for k in 0...komaS.length
    if ban[pos1.slice(0,1).to_i-1][pos1.slice(1,1).to_i-1].slice(1,2) == komaS[k] then
      km=k
      # puts "===",ban[pos1.slice(0,1).to_i-1][pos1.slice(1,1).to_i-1].slice(1,2),komaS[k],km,k
    end
  end
  
  sleep 0.5
  
  panVal=-1 if sente  # 先手の音を左側から出すためのpan
  panVal=1 if !sente  # 後手の音を右側から出すためのpan
  
  use_synth komaSound[km]
  # 成り駒の場合は、distortionをかける
  # 駒台からの打駒の場合
  if(pos1.slice(0,1).to_i-1==-1) then
    play :C7,amp:2
    play :C3,amp:3
    sleep 0.2
    # 通常の駒の移動の場合
  else
    # 成駒の場合
    if(km==1 || km==3 || km==5 || km==7 || km==10 || km==12) then
      with_fx :distortion,distort:0.9 do
        x=play XY[pos1.slice(0,1).to_i-1],pan:panVal,note_slide:0.75,sustain:1 # 移動前のX座標の音
        y=play XY[pos1.slice(1,1).to_i-1],pan:panVal,note_slide:0.75,sustain:1 # 移動前のY座標の音
        sleep 0.25
        control x,note:XY[pos2.slice(0,1).to_i-1],pan:panVal # 移動後のX座標の音
        control y,note:XY[pos2.slice(1,1).to_i-1],pan:panVal # 移動後のY座標の音
        sleep 0.25
      end
    else
      # 成っていない駒の場合
      x=play XY[pos1.slice(0,1).to_i-1],pan:panVal,note_slide:0.75,sustain:1 # 移動前のX座標の音
      y=play XY[pos1.slice(1,1).to_i-1],pan:panVal,note_slide:0.75,sustain:1 # 移動前のY座標の音
      sleep 0.25
      control x,note:XY[pos2.slice(0,1).to_i-1],pan:panVal # 移動後のX座標の音
      control y,note:XY[pos2.slice(1,1).to_i-1],pan:panVal # 移動後のY座標の音
      sleep 0.25
    end
  end
  
  # 相手の駒を取った場合(移動後の場所が最初から空でなかった場合)高音とドラムを鳴らす
  if ban[pos2.slice(0,1).to_i-1][pos2.slice(1,1).to_i-1] !="   " then
    use_synth :dpulse
    (play 84,pan:panVal; sample :drum_snare_hard,pan:panVal) if sente
    (play 96,pan:panVal; sample :drum_cymbal_hard,pan:panVal) if !sente
    # sleep 0.2
  end
  # 打駒の場合
  if pos1=="00" then
    ban[pos2.slice(0,1).to_i-1][pos2.slice(1,1).to_i-1]="+"+koma if sente # 打駒の場合、先手では先頭に+をつけて駒を移動後の場所に
    ban[pos2.slice(0,1).to_i-1][pos2.slice(1,1).to_i-1]="-"+koma if !sente# 打駒の場合、後手では先頭に-をつけて駒を移動後の場所に
  else
    ban[pos2.slice(0,1).to_i-1][pos2.slice(1,1).to_i-1]="+"+koma if sente # 打駒でない場合、駒を移動後の場所に
    ban[pos2.slice(0,1).to_i-1][pos2.slice(1,1).to_i-1]="-"+koma if !sente # 打駒でない場合、駒を移動後の場所に
  end
  
  ban[pos1.slice(0,1).to_i-1][pos1.slice(1,1).to_i-1]="   " if pos1!="00" # 打駒でない場合には、移動元の場所は空にする。
  
  # 駒の全体配置を再表示する
  puts j-i,d[j]  # 手数、棋譜での表記
  for k in 0..8
    puts ban[8][k],ban[7][k] ,ban[6][k] ,ban[5][k] ,ban[4][k] ,ban[3][k] ,ban[2][k] ,ban[1][k] ,ban[0][k]
    #puts ban[0][k],ban[1][k] ,ban[2][k] ,ban[3][k] ,ban[4][k] ,ban[5][k] ,ban[6][k] ,ban[7][k] ,ban[8][k]
  end
  j=j+1
end



2つの交差したポルタメント (Two Intersected Portamentos)

2つの音がそれぞれ別々の音色で、別々の音程に連続変化します。
将棋の駒の移動時にX,Y座標をずらしたポルタメントで鳴らしXとYが区別できるようにするために作成しましたが、採用しませんでした。
下記のプログラムは、図のように変化の開始点をずらして、音程を変化させています。
縦軸は、MIDIノート番号、横軸は拍


わかりやすいように拍毎にハイハットシンバルを鳴らしています。
in_thread do
  6.times do
    sample :drum_cymbal_closed
    sleep 1
  end
end
use_synth :beep
x = play 60, sustain: 5, note_slide:3
use_synth :saw
y = play 72, sustain: 5, note_slide:1
sleep 1
control x, note:72
sleep 1
control y, note:60
sleep 3





囲碁の棋譜の音楽化 (Go Game Music)

囲碁の棋譜ファイル(SFG形式)を読み込み、音楽にしました。
使用した棋譜は、
Google Alpha Go vs リ・セドル(李世石,Lee Sedol) 2016年3月15日の3連戦の最終局
Google Alpha Go vs 柯潔(Ke Jie) 2017年5月27日の3連戦の最終局

先手黒番Bを左側から、後手白番Wを右側スピーカーから出力しています。
X座標をpianoで鳴らし、直後にY座標をpluckの音色で鳴らしています。
BGM には、Sonic Piのトップページにあるサンプルプログラムの Ocean Waves を使わせてもらいました。
碁石の情報の全てを音にしているので、音を解析して棋譜に戻すことも原理的には可能であり、棋譜の可聴化とも言えます。

画面右下に表示されるログファイルの表示サイズを調整することにより、静止した状態で棋譜表示を眺めることができます。

OpenShot Video Editorで作成

棋譜は、碁遊庵の棋譜ダウンロードから入手しました。
ハンデや、手順のパスは扱っていません.
直接棋譜に書かれていない、囲われた石を取り除く等の処理はしていません.
( による棋譜の階層構造は判定していません。
手が;で始まるように書かれていて、さらに行頭にある手の場合も;で始まっていないと正常に読み込みません。
従って、行頭が;で始まっていないSGFデータ(例:人間の知識を必要としなくて最強のAlphaZeroの棋譜 DeepMind社のNature論文のSupplementary informationとして公開されている) などは、行頭の手が読み込まれません。(改行コードを全て削除して全データを1行にするなどで対応可)

使用する音は、音階scaleで指定しています。ここでは、琴の「六段の調」などで使われている平調子(hirajoshi)を採用しているので、"和"の雰囲気になっています。
Sonic Piで用意されているScaleを変更することにより、雲井調子(kumoi)、岩戸調子(iwato)他、世界中のいろいろな音階に変えることが容易にできます。

黒がB、白がW、碁盤の左上がaaで、右下がssです。
ログ領域のテキスト表示は、黒を0、白をC、盤上の9点をoで、その他を. で表しています。

ソースリスト
==========
path="/各PCでのパス/李世石-AlphaGo-20160315.sgf" # 棋譜ファイルをpath=の後ろにドロップすれば、入力されます。
#path="/各PCでのパス/AlphaGo-柯潔-20170527.sgf"

use_bpm 160   #  速度
use_debug false
scaleName=:hirajoshi #与えるスケール (平調子)   :kumoi :iwato :egyptian :bartok など変更可

# 19×19の2次元配列の作成。 SGFファイルでは、1-19は、a-sと表される.左上が原点
ban=Array.new(19," ")
ban.length.times{|i|
  ban[i]=Array.new(19," ")
}
for i in 0...19
  for j in 0...19
    ban[i][j]="."
    ban[i][j]="o" if (i==3 || i==9 || i==15) && (j==3 || j==9 || j==15) # 盤上の9箇所の黒点の位置
  end
end

te=0 # 手数表示用変数

# 初期盤面の表示
puts te
for i in 0...19
  ban1L=""
  for j in 0...19
    ban1L=ban1L+ban[i][j]+" "
  end
  puts ban1L
end

# BGM の Ocean Waves( copied from https://sonic-pi.net/ )
in_thread do
  with_fx :reverb, mix: 0.5 do
    100.times do
      s = synth [:bnoise, :cnoise, :gnoise].choose, amp: rrand(0.1, 0.3), attack: rrand(0, 4), sustain: rrand(0, 2), release: rrand(1, 3), cutoff_slide: rrand(0, 3), cutoff: rrand(60, 80), pan: rrand(-1, 1), pan_slide: 1
      control s, pan: rrand(-1, 1), cutoff: rrand(60, 115)
      sleep rrand(2, 3)
    end
  end
end

f=File.open(path).read   # pathで指定された外部棋譜ファイルを開く
for i in 0...f.length
  # データの文字の順番が、;、BまたはW、[、2文字開けて]となった場合に手とみなします。
  if f.slice(i, 1)==";" && (f.slice(i+1, 1)=="B" || f.slice(i+1, 1)=="W") && f.slice(i+2, 1)=="[" && f.slice(i+5, 1)=="]" then
    x=f.slice(i+3, 1).ord-97 # ASCII文字を数値に aは97
    y=f.slice(i+4, 1).ord-97 # ASCII文字を数値に
    # 先手Blackの場合の盤面文字の設定と音 pan:-1
    if f.slice(i+1, 1)=="B" then
      ban[y][x]="C"
      use_synth :piano  # 音色の指定B
      # scaleNameで指定されたの音階に従って鳴らす.(音階によって1オクターブ内の音数の多少(3-12)があるため、開始音を上下する必要あり)
      play scale(:C3, scaleName, num_octaves: 7)[x],pan: -1,sustain:1 # C3で始まる7オクターブのscaleの中からx番目の音を取り出して鳴らす.
      sleep 0.2  # X座標の音を鳴らした後、Y座標を鳴らすまでの遅れ時間
      use_synth :pluck  # 音色の指定B
      play scale(:C3, scaleName, num_octaves: 7)[y],pan: -1,sustain:1
      sleep 0.8  # 上記の遅れ時間と合わせて1.0拍になるようにしています。
    end
    # 後手Whiteの場合の盤面文字の設定と音 pan:1
    if f.slice(i+1, 1)=="W" then
      ban[y][x]="0"
      use_synth :piano  # 音色の指定W
      play scale(:C3, scaleName, num_octaves: 7)[x],pan: 1,sustain:1
      sleep 0.2  # X座標の音を鳴らした後、Y座標を鳴らすまでの遅れ時間
      use_synth :pluck  # 音色の指定W
      play scale(:C3, scaleName, num_octaves: 7)[y],pan: 1,sustain:1
      sleep 0.8  # 上記の遅れ時間と合わせて1.0拍になるようにしています。
    end
    
    # 盤面の描画
    te=te+1
    puts te,f.slice(i+1, 1)+f.slice(i+3, 2)
    for i in 0...19
      ban1L=""
      for j in 0...19
        ban1L=ban1L+ban[i][j]+" "
      end
      puts ban1L
    end
  else
    sleep 0.001 # データを読み飛ばす場合
  end
end
==========
プログラムは、Processingと連携させて盤面をグラフィックスで描画(手順を3Dで見えるようにする等)したり、Processing側で、演奏パラメータの変更や手数の指定などをリアルタイムで行えるようにすると、より興味深いものとなると思われます。
さらにAlpha Goと連携して、手の評価値と音を関連づけるなども考えられます。




コードをアルペジオで鳴らす例


Peter, Paul and Mary(PPM)のThe Cruel War (悲惨な戦争)のイントロのコードを与えて、アルペジオで鳴らしています.
コード名を変数として、音程、コードの種類の順番で与えるため、比較的見やすくできます。
アルペジオのパターンは、基音を0として、コード内のどの順番の音を鳴らすかを0,1,2,3等で与えます。
この曲自体は、パブリックドメインです。

use_synth :pluck
arpeggio=(ring 0,1,2,1,3,2,1,2)
# Intro
c=[:G3,:M,:G3,:M,:E3,:m,:E3,:m,:A3,:m,:A3,:m,:B3,:m,:B3,'7',
   :C4,:M,:C4,:M,:A3,:m,:A3,:m,:D4,:M,:C4,:M,:G3,:M] #,:G3,:M]
with_fx :reverb, room:0.9 do
  for i in 0...c.length/2
    8.times do
      play chord(c[i*2],c[i*2+1],num_octaves:2)[arpeggio.tick]
      sleep 0.25
    end
  end
  play :G3
end




重音のあるアルペジオの例

上記では、単音のアルペジオでしたが、複数の弦を同時に鳴らすことのあるアルペジオを、2重のリストで与えるようにして関数としました。
リスト [0,[1,2]] では、コードの1番目の音を出した後に、2番目と3番目の音を同時に鳴らします。
関数 playChord は、コードとアルペジオのパターンと1音の長さを与えるようにしてあります。

# Arpeggios with overlapping sounds
p1=[0,3,1,3]                   # pattern1
p2=[0,[1,2,3],[0,4],5]         # pattern2
c1=chord(:C4,:M,num_octaves:2) # chord1
c2=chord(:G4,:M,num_octaves:2) # chord2
c3=chord(:A3,:m,num_octaves:2) # chord3
c4=chord(:F4,:M,num_octaves:2) # chord4

define :playChord do |c,p,s|
  p.each do |pp|
    if pp.instance_of?(Array) then # 要素が配列だった場合は、さらに1音づつ鳴らす.
      pp.each do |s|
        play c[s],amp:0.5
      end
    else
      play c[pp],amp:0.5
    end
    sleep s
  end
end

loop do
  playChord c1,p1,0.25
  playChord c1,p2,0.25
  playChord c2,p1,0.25
  playChord c2,p2,0.25
  playChord c3,p1,0.25
  playChord c3,p2,0.25
  playChord c4,p1,0.25
  playChord c4,p2,0.25
end




タブ譜をSonic Piで鳴らす方法の例


TAB(タブ)譜は、ギター等の弦の番号とフレットを押さえるポジションがわかりやすく表現されているため広く使われています。このタブ譜の見た目の並びを、なるべくそのままSonic Piで鳴らせるようにした配列を作成してみました。タブ譜からの入力が多少楽にできます。
一つの配列の中に、各弦のポジション、音符の長さ、という順番で入力します。弾かない弦はxとして、仮に999を代入していますが値に意味はありません。(この方法では、見やすいように空白や-.等の記号にはできませんでした.)

例としてイーグルスの「ホテル・カリフォルニア」のイントロの前半を入力してみました。

# TAB to #SonicPi, Eagles Hotel California intro.
tuning=[:E3,:A3,:D4,:G4,:B4,:E5]
x=999
a=[
  # Bm
  [7,9,9,7,7,7],8,
  [x,x,9,x,x,x],16,
  [x,x,x,7,x,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,x,7,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,7,x,x],16,
  [x,x,x,x,x,7],4,
  [x,x,x,7,x,x],8,
  [x,x,x,9,7,x],8,
  # F#7
  [x,x,8,x,x,x],8,
  [x,x,x,9,x,x],16,
  [x,x,x,x,7,x],16,
  [x,9,x,x,x,x],16,
  [x,x,x,x,x,9],16,
  [x,x,x,9,x,x],16,
  [x,x,x,x,7,x],16,
  [x,x,8,x,x,x],2,
  # Asus2
  [x,x,7,x,x,x],8,
  [x,x,x,9,x,x],16,
  [x,x,x,x,10,x],16,
  [x,x,x,x,10,x],16,
  [x,x,x,x,x,7],8,
  [x,x,x,x,10,x],16,
  [x,x,7,x,x,x],8,
  [x,x,x,9,x,x],16,
  [x,x,x,x,10,x],16,
  [x,7,x,x,x,x],8,
  [x,x,x,9,x,x],16,
  [x,x,x,x,7,x],16,
  # E9
  [x,11,x,x,x,x],8,
  [x,x,x,x,x,7],16,
  [x,x,x,7,x,x],16,
  [x,x,x,x,x,7],16,
  [x,x,x,x,7,x],16,
  [x,x,x,7,x,x],16,
  [x,x,12,x,x,x],16,
  [x,x,x,x,x,7],2,
  # G
  [x,10,x,x,x,x],8,
  [x,x,9,x,x,x],16,
  [x,x,x,7,x,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,x,8,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,7,x,x],16,
  [x,x,x,x,x,7],8,
  [x,10,x,x,x,x],16,
  [x,x,x,x,8,x],16,
  [x,x,x,7,x,x],16,
  [x,x,x,9,x,x],16,
  [x,x,x,x,7,x],16,
  [x,x,x,9,x,x],16,
  # D
  [x,x,7,x,x,x],8,
  [x,x,x,x,x,10],16,
  [x,x,x,x,7,x],16,
  [x,x,x,7,x,x],16,
  [x,x,x,x,x,10],16,
  [x,x,7,x,x,x],16,
  [x,x,x,x,7,x],16,
  [x,9,x,x,x,x],8,
  [x,x,x,x,x,10],16,
  [x,x,x,x,7,x],16,
  [10,9,x,x,x,x],8,
  [x,x,7,x,x,x],16,
  [x,x,x,x,7,x],16,
  # Em7
  [x,7,x,x,x,x],16,
  [x,x,x,x,8,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,7,x,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,x,8,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,x,8,x],16,
  [x,x,x,x,x,7],8,
  [x,x,9,x,x,x],16,
  [x,x,x,7,x,x],16,
  [7,x,x,x,x,x],16,
  [x,x,9,x,x,x],16,
  [x,x,9,x,x,x],16,
  [x,x,x,x,7,x],16,
  # F#7
  [x,9,x,x,x,x],8,
  [x,x,8,x,x,x],16,
  [x,x,x,9,x,x],16,
  [x,x,x,9,x,x],16,
  [x,x,x,x,7,x],16,
  [x,x,8,x,x,x],16,
  [x,x,x,9,x,x],16,
  [x,x,x,x,x,9],2
]

use_bpm 74
use_synth :pluck
with_fx :reverb,room:0.9 do
  for i in 0...a.length/2
    for j in 0...6
      play tuning[j]+a[i*2][j] if a[i*2][j] !=x
    end
    sleep 4.0/a[i*2+1]
  end
end



テキスト表示されたタブ譜をSonic Piで簡単に鳴らす方法 Easier way to play ASCII tab sheet music.


ギターなどのタブ譜をテキスト文字(ASCII)で表現する方法は、Web上で多数用いられており、多数公開されています。これを、そのままコピー&ペーストして、前後に[" "," "]等を付けて文字型配列とすることによって、容易にSonic Piで用いることができます。
この変換には、正規表現の使える環境で、行頭を表す^を"に、行末を表す$を",に置換すれば、非常に簡単に完了します。
下記の例で用いたのは、Led Zeppelin の "Stairway to Heaven"(天国への階段)の有名なイントロで、タブ譜はこれです。

このサイトでも、他の曲が多数公開されています。

下記のプログラム例では、フレットポジションの数字が、0〜9の場合のみ音を鳴らしています。また、先頭のみに弦の文字があるとし、小節線は考慮していません。チョーキング等の特殊奏法のコマンドが入っていると、文字数とリズムが合致しなくなり、その場合にはリズムがずれます。(下記の例でもズレがあり、違和感なく聞くには、不要な列を削除する必要があります。) ASCII tab譜について

#SonicPi Easier way to play ASCII tab sheet music.
# Led Zeppelin, Stairway to heaven, Intro.
t=[
  "e-------5-7-----7-8-----8-2-----2-0---------0---------------------",
  "b-----5-----5-------5-------3-------1---1-----1-------------------",
  "g---5---------5-------5-------2-------2---------2-0-2-2-----------",
  "d-7-------6-------5-------4-------3-------------------------------",
  "a-------------------------------------------------2-0-0---0--/8-7-",
  "e-----------------------------------------------------------------",
  
  "e-------5-7-----7-8-----8-2-----2-0---------0---------------------",
  "b-----5-----5-------5-------3-------1---1-----1-------------------",
  "g---5---------5-------5-------2-------2---------2-0-2-2-----------",
  "d-7-------6-------5-------4-------3-------------------------------",
  "a-------------------------------------------------2-0-0-------0-2-",
  "e-----------------------------------------------------------------",
  
  "e-------0-2-----2-0-----0-----------------3-----3-3h2-2-2---------",
  "b-----------3-------1-----1-------1-----1---0-----------3---------",
  "g-----0-------2-------2-----2-------0---------0-------------------",
  "d---2-----0-------3-------------------2-----------0-----0---------",
  "a-3-----------------------0---0-2-3---------------------------0-2-",
  "e-----------------------------------------3-----------------------",
  
  "e-------0-2-----2-0-----0-----------------------2-0-0-0-----------",
  "b-----------3-------1-----1-------------1-----3---1-1-1-----------",
  "g-----0-------2-------2-----2---------0-----2-----2-2-2-----------",
  "d---2-----0-------3-----------------2-----0-------3-3-3-----------",
  "a-3-----------------------0---0-2-3-------------------------------",
  "e-----------------------------------------------------------------"   #データの最後の行には , を入れないこと.
]
tuning=[:E3,:A3,:D4,:G4,:B4,:E5].reverse
for i in 0...t.length/6
  for j in 1...t[i*6].length
    for k in 0...6
      case t[i*6+k][j]
      when "0","1","2","3","4","5","6","7","8","9"
        play tuning[k]+t[i*6+k][j].to_i
      end
    end
    sleep 0.15
  end
end

追伸
TwitterでFaraday氏からのアドバイスがあり、 .split("\n").reject(&:empty?) を使うと、行の前後に " と ", を付ける必要がなくなり、タブ譜をコピー&ペーストし、その全体の前後に"を追加し、これを文字変数に代入すれば演奏できることがわかりました。
改良したコードの例は、下記です。
t0=
"e-------5-7-----7-8-----8-2-----2-0---------0---------------------
b-----5-----5-------5-------3-------1---1-----1-------------------
g---5---------5-------5-------2-------2---------2-0-2-2-----------
d-7-------6-------5-------4-------3-------------------------------
a-------------------------------------------------2-0-0---0--/8-7-
e-----------------------------------------------------------------"
t=t0.split("\n").reject(&:empty?)
tuning=[:E3,:A3,:D4,:G4,:B4,:E5].reverse
for i in 0...t.length/6
  for j in 1...t[i].length
    for k in 0...6
      case t[i*6+k][j]
        when "0","1","2","3","4","5","6","7","8","9"
        play tuning[k]+t[i*6+k][j].to_i
      end
    end
  sleep 0.15
  end
end




太陽光スペクトルの音 Sun Light Spectrum Sounds.


太陽光に含まれる光の波長成分を分析したデータの中では、米国のThe Renewable Resource Data Center(RReDC)で公開されているASTMG173が標準的に用いられています。
グラフ化した例が下記で、これはAudacity等の音のスペクトル表示に形としては似ています。そこで、これを音のして鳴らすため、横軸を音の周波数、縦軸をその強度と見なして、多数の正弦波を鳴らすプログラムを作成してみました。

使用したカンマ区切りのCSVファイルは、 ASTMG173.zip
ファイル中には、波長280nm〜4000nmまでの間を、0.5nm や 1nm 刻み等で計2004個のデータが入っています。それぞれの波長に対しての光の強度が、大気圏外で測定した値(AM0)、直角に入射した場合(赤道上など、AM1)、米国内の平均照射角度37°の場合(AM1.5)の3つの値が並んでいます。
ここでは、nm(ナノメータ)単位の波長の値をそのまま周波数として使用し、強度は0.1を加えて1/4して使用しました。
2004個の音を同時に鳴らすと、刻み幅による0.5秒周期や1.0秒周期のうなりが生じます。これをある程度避けるためと、低い音からだんだんと高くなってゆくという効果を出すため、音の鳴り始めを乱数でわずかにずらしました。左右のパンもランダムにし、AM0, AM1, AM1.5を間をおいて順に鳴らしています。

注意:多数の音を同時に鳴らしているため、時々Sonic Piの動作がおかしくなることがあります。その場合は再起動してみてください。
なお、この音をSonic Piで録音してから、そのWavファイルをAudacityで開き、スペクトル解析を行ったところ、太陽光スペクトルは再現されませんでした。

#SonicPi Sun Light Spectrum Sounds
#Spectrum csv data http://rredc.nrel.gov/solar/spectra/am1.5/ASTMG173/compressed/ASTMG173.zip

path=" path to ASTMG173.csv"
use_debug false
use_random_seed Time.new.usec

d=[];x=[];y1=[];y2=[];y3=[]
open(path){|f| d = f.readlines}
puts d.length,"data"
for i in 2...d.length
  x[i]=d[i].chomp.split("\t")[0].to_f
  y1[i]=d[i].chomp.split("\t")[1].to_f # AM0 spectrum
  y2[i]=d[i].chomp.split("\t")[2].to_f # AM1 spectrum
  y3[i]=d[i].chomp.split("\t")[3].to_f # AM1.5 spectrum
end
for i in (2...d.length).step(1)
  play hz_to_midi(x[i]*1),amp:(y1[i]+0.1)*0.25,sustain:20,pan:rrand(-1,1)
  sleep rrand(0.005,0.01)
end
sleep 20
for i in (2...d.length).step(1)
  play hz_to_midi(x[i]*1),amp:(y2[i]+0.1)*0.25,sustain:20,pan:rrand(-1,1)
  sleep rrand(0.005,0.01)
end
sleep 20
for i in (2...d.length).step(1)
  play hz_to_midi(x[i]*1),amp:(y3[i]+0.1)*0.25,sustain:20,pan:rrand(-1,1)
  sleep rrand(0.005,0.01)
end
sleep 20



和音の音程の同時移動 Simultaneous movement of chords

和音をリストで与え、次の和音まで、音程を連続的に変化させます。
以下の例では、C,F,C,G,Cを、1拍づつ鳴らしていますが、その内の半拍を各音の移動にあてています。
use_tuning :just
s = play [:C4,:E4,:G4], sustain: 6, note_slide: 0.5 # ドミソ
sleep 1
control s, note: [:C4,:F4,:A4] # ドファラ
sleep 1
control s, note: [:C4,:E4,:G4] # ドミソ
sleep 1
control s, note: [:B3,:D4,:G4] # シレソ
sleep 1
control s, note: [:C4,:E4,:G4] # ドミソ
sleep 1




ディープ・ノート Deep Note

ルーカス・フィルムのスター・ウォーズ・シリーズ等の映画の前に流れる効果音として、多くの人が聞いている印象的な音「Deep Note」は、1983年に2万行のコードによるC言語で書かれたそうです(下記GIGAZINE等のリンク参照)。 既に2014年にXavier RileyさんがSonic Piで作成していますが(同、下記リンク)、35周年を記念して楽譜として公表されたので、上記の和音の同時移動を活用して作成してみました。そこそこ似た音となっていますが、スペクトル(下図)を見ると大きく異なっていましたので、さらなる改良が望まれます。
開始音の周波数範囲は、200〜400Hzと明記されていますが、聴感上、より低めに変更しています。
音色は、dsawを使用して、複雑にしています。
DN[j][]の配列は、事前に値をいれておかないと、エラーとなったので、最初のforループで仮に、全ての要素として最後の和音を代入してあります。
リストによる表記を用いずに、一音づつ独立したcontrol文を使って、pan_slideを使うという方法も考えられます。


use_random_seed Time.new.usec
use_synth :dsaw
f1=20.0
f2=200.0
DN=[]
n=4
slideT=2
totalT=n*slideT*3
for j in 0..n
  DN[j]=[:F6,:D6,:A5,:D5,:A4,:D4,:A3,:D3,:A2,:D2,:D1]
end

for i in 0...DN[n].length
  DN[0][i]= hz_to_midi(rrand(f1,f2))
end

for j in 1...n
  for i in 0...DN[n].length
    DN[j][i]= DN[0][i]+(DN[n][i]-DN[0][i])/n.to_f+rrand(-n*2+j*2,n*2-j*2)
  end
end
with_fx :reverb ,room:1, mix:1 do #####
  s = play DN[0], sustain: totalT, note_slide: slideT,amp: 0.1, amp_slide: slideT
  sleep slideT
  for i in 1..n
    control s, note: DN[i],amp: (i/n.to_r)+0.5
    sleep slideT
  end
end #####


35周年を記念して公開された楽譜


オリジナル音のスペクトル(Audacityによる表示)


上記プログラムによる音のスペクトル(Audacityによる表示)
リバーブの with_fx :reverb ,room:1, mix:1 do を使用した場合は、なぜか、note_slideで与えた音程変化が見られなくなっています。


リバーブを使用しない(#####行をコメント化)した場合は、note_slideで与えた音程変化が直線的に見られます。


参考
GIGAZINE 映画上映前に流れるTHXロゴの「ブゥゥウウンン」という音の正体とは? (2013)
Xavier RileyさんのSonic Piプログラム deep_note.rb (2014)
Recreating the THX Deep Note (2009)
Music Thing TINY MUSIC MAKERS: Pt 3: The THX Sound(2005)
アカペラの多重録音で、Deep Noteを歌っている人もいました。
Enjoy This A Capella Cover of the THX ‘Deep Note’ Sound (2018)


PowerPoint 2016の画面切り替えサウンドを鳴らす PowerPoint2016 sounds


macOS版のPowerPoint2016 (アップデータで2018にしたもの)のスライドの画面切り替え用サウンドは、WAVファイルでアプリケーション内に格納されているため、このファイルを直接指定することによって、Sonic Piで鳴らすことができます。Windows版でも、WAVファイルの所在がわかれば同様に鳴らすことができると思われます。
リボンの[画面切り替え]→[サウンド]にある19の効果音を順にならすプログラム例は、
PP2016mac=["applause.wav","breeze.wav","chimes.wav","drumroll.wav","laser.wav",
           "type.wav","wind.wav","arrow.wav","camera.wav","click.wav",
           "explode.wav","push.wav","voltage.wav","bomb.wav","cashreg.wav",
           "coin.wav","hammer.wav","suction.wav","whoosh.wav"]
path="/Applications/Microsoft PowerPoint.app/Contents/Resources/Sounds/"
PP2016mac.each do |s|
  sample path+s
  sleep sample_duration path+s
  sleep 0.2
end

LibreOfficeのサウンドを鳴らす方法はこちら



MuseScoreのDrumline機能拡張のサンプリング音 1026個を鳴らす


五線譜作成オープンソースソフトウェアMuseScoreのドラム譜用の機能拡張Drumlineをインストールすると、1026個のサンプリングされたドラム音がインストールされます。これらは、macOSでは、下記に置かれています。
~/Documents/MuseScore2/拡張機能/mdl/1.1/sfzs/MDL_samples
この中にフォルダ、auxiliary,bass,bass_group,cymbals,drumset,snare,snare_group,tenor に分類されOgg形式の音声ファイルとして格納されています。
とりあえず、これらを全て鳴らしてみるには、

# Usage of 1026 samples of MuseScore Drumline Extentions on Sonic Pi
path="~/Documents/MuseScore2/拡張機能/mdl/1.1/sfzs/MDL_samples/**"
#path="~/Documents/MuseScore2/Extensions/mdl/1.1/sfzs/MDL_samples/**" # for Eng.
for i in 0...1026
  puts i
  sample path,i
  sleep 0.1
end



macOSのsayコマンドを使う


macOSでは、systemコマンドでOSの sayコマンドを呼び出してSonic Piの中から喋らせることができます。

loop do
  system("say Hello World")
  sleep 2
end
システムの声がインストールされていれば、-vで声を指定して、
system("say -v Agnes Hello World")
なども可能です。
1分間の語数を-rで指定して、早口の、
system("say -v Agnes -r 300 Hello World")
も可能です。

macOSに声がインストールされていれば、各種言語で使用できます。
声が重なると、Timing Exceptionエラーとなりました。
外部コマンドを呼び出すだけなので、Recボタンでの録音等はできないようです。

例: 5から0へのカウントダウン. ドラムロール入り(macOSのみ)
a=[5,4,3,2,1,0]

in_thread do
  for i in 0..a.length-2 do
    sample :drum_heavy_kick,amp:1
    sample :drum_roll,sustain:1,release:0.1,amp:6-a[i]
    sleep 1
  end
  sample :drum_bass_hard,amp:10
end

for i in a
  system("say -v Agnes "+i.to_s)
  sleep 1
end

sayコマンドの活用法については、マイナビニュースの新・OS X ハッキング! 第224回「Kyoko」と「Otoya」に語らせたい、あんなこと・こんなこと に興味深い解説がありました。

system("say -v Otoya 'そうさ[[slnc 120]][[rate 90]]Y [[rate 200]] MCA'")




1次元セルオートマトンによる音

Elementary Cellular Automaton Sounds

ある桁数の0と1が並んだ二進数の文字列が、世代ごとに変化して行きます。この世代間の変化は、両隣と自分の値によって決まります。この3つのセルの値が取りうる場合の数は、各0,1の2通りが3つなので2^3 = 8通りです。この8通りの変化の前後で0と1が変わるか変わらないか、という変化の中身がRuleとしてWolframによって決められています。これは8桁の二進数で表せる全て値と同じ数だけあるので、256通りとなります。(0〜255まで)
Rule 30の場合、第一世代を0001000と与えると、第二世代では0011100となり、第三世代では、0110010となります。この7つの0,1を平調子の音階に割り当て、1が割り当てられた音だけ鳴らします。これを16世代まで順に鳴らして、次のRuleについて第一世代から繰り返す、ということをSonic Piのプログラムで行っています。
macOS版のSonic Piのsystemコマンドを用い、macOSのsayコマンドによってRule番号を読み上げさせています。
音は、Soundcloud に置いてあります.
この録音は、Soundflowerを使ってMacからの音の出力をAudacityに渡して行いました。

参考:Elementary Cellular Automaton, Wolfram


use_debug false
Rules=[1,2,3,6,7,8,10,16,30,54,60,62,90,94,102,110,122,126,150,158,182,188,190,220,222,250]
data0="0001000"; # 初期値. 長さや値は任意

def c3(s,i) # 文字列sから位置iを中心に並んだ3文字を取り出す関数の定義
  if i==0 then
    return s[-1,1] +s[i,2] # 先頭の場合、最後の文字を最初にもってくる.
  elsif i==s.length()-1 then
    return s[i-1,2] +s[0,1] # 末尾の場合、先頭の文字を後ろにつける.
  else
    return s[i-1,3] # 前後を含め3文字を取り出す
  end
end

system("say Elementary Cellular Automaton Sounds")
sleep 4

pattern=[];
for i in 0...8
  pattern[i]="%03b" % i;
end

for Rule in Rules
  n=data0.length()
  RuleB="%08b" % Rule
  nR=RuleB.length()
  RuleB=RuleB.reverse # 文字列を逆順にする
  RBA=RuleB.split(//) # 各文字を要素とする配列に変換する
  
  puts "Rule=",Rule
  puts pattern;
  puts RBA
  
  dataA=[]; # old
  dataB=[]; # new
  dataA=data0.split(//); #文字列を1文字づつ配列に格納する
  puts data0;
  
  sleep 0.5
  system("say Rule "+Rule.to_s)  # macOSのみ
  sleep 1 if Rule<100
  sleep 1.5 if Rule>=100
  
  for k in 0...8
    for i in 0...n
      for j in 0...nR
        r=dataA.join
        if c3(r, i) == pattern[j] then
          dataB[i]=RBA[j]
        end
      end
    end
    puts dataB.join
    for i in 0...n
      play (scale :C4, :hirajoshi, num_octaves:9)[i] if dataA[i]=="1"
      sleep 0.01
      dataA[i]=dataB[i] #  dataA=dataB は不可。ポインタ渡しとなる??
    end
    sleep 0.5
  end
end
sleep 1
system("say The end")  # macOSのみ





徐々に倍音が加わる音

Gradually increasing harmonics sounds

正弦波の基音に対して、正弦波の倍音を徐々に加えてゆきます。何番めの倍音が加わると、どのように音色が変わるかがわかりやすいように、倍音を下から順番に、少しづつ加えるようにしています。
基音(下記ではC4)がなり続けます。hLenで指定した拍(4拍)経ってから、2倍音が徐々に加わり、hLen拍で1/2の強度となります。
次に、3倍音が4拍をかけて徐々に強くなり、hLen拍で1/3の強度となります。
さらに4倍音が同様に1/4の強度まで徐々に加えられてゆきます。
これをharmonicsの配列で指定した数の倍音まで続けて終了します。
[1,3,5,7,9,11]というような配列を用いれば、奇数次倍音によって、どのように音色が変わって行くかを聞くことができます。
なお、音の時間方向の位相についての精度は、あまり高くないようで、Audacity等の波形編集ソフトで静的に作成した波形とは少々異なっていました。(2つの同じ音を1波長の半分の微小時間だけずらして同時に鳴らして、ノイズキャンセルのように音を消す、という操作はできませんでした。)

楽器の構造から、両端の開いた楽器(フルート、尺八など)は、整数次倍音が優勢で、片側だけが開いた楽器(リード楽器、金管楽器、鼻笛等)は奇数次倍音が優勢という性質があり、これを参考にして聞いてみてください。(実際の楽器音は奏者のテクニックにより、倍音構成は自在に変化されています。)

後半の # bell & voice 以降は倍音とは関係ないので削除可能です。
macOSでは、sayコマンドにより、何倍音かを喋らしています。(Avaの声がインストールされていない場合には、他の声に変更するか、声の種類を指定している -v Ava を削除して下さい。)
Windowsでエラーするようでしたら、system( )の行をコメント化して下さい。

keyNote=:C4 # 元の音
harmonics=[1,2,3,4,5,6,7,8,9,10] # 倍音構成を整数次とする場合
#harmonics=[1,3,5,7,9,11] # 倍音構成を奇数次とする場合
#harmonics=[1,2,4,6,8,10] # (偶数次)
hLen=4 # 1つの音を延ばす拍数

hVol=[]
for i in 0...harmonics.length
  hVol[i]= 1.0/harmonics[i] # 倍音の強度
end
f0=midi_to_hz(keyNote)
len=(harmonics.length+1)*hLen

in_thread do
  play hz_to_midi(f0*harmonics[0]),sustain:len,amp:hVol[0]
  sleep hLen
  h=[]
  for i in 1...harmonics.length
    h[i]=  play hz_to_midi(f0*harmonics[i]),sustain:len-i*hLen,amp:0,amp_slide:hLen
    control h[i], amp: hVol[i]
    sleep hLen
  end
end

# bell & voice
in_thread do
  for k in 0...harmonics.length
    sample :perc_bell,amp:0.8,pan:1
    case harmonics[k]
    when 1
      sp="1st"
    when 2
      sp="2nd"
    when 3
      sp="3rd"
    else
      sp=harmonics[k].to_s+"th"
    end
    system("say -v Ava "+sp) #  "say -v Agnes " # macOS
    sleep hLen
  end
end

プログラムを実行した音(サイン波部分のみ)をAudacityでスペクトル表示した例
前半:整数次倍音、後半:奇数次倍音




sleep時間のベンチマーク, Benchmark of the "sleep" time


Rubyの処理速度を計測するBenchmark機能でsleep時間を測定してみました。
require 'benchmark'
puts Benchmark.measure{
  sleep 60
}
4回実行すると、(real:実経過時間 , stime:System CPU time , utime:User CPU time)
real=59.97406787890941 , stime=0.0028529999999999944, utime=0.0065509999999999735
real=59.98809501528740 , stime=0.00644499999999992  , utime=0.007249999999999979
real=59.98878446593881 , stime=0.005198999999999954 , utime=0.007164999999999644
real=59.98979557584971 , stime=0.004953000000000096 , utime=0.007125999999999966
となりrealは、60秒を少しだけ下回っていました。(ゼロであった子プロセス時間のcstime,cutimeは省略)
3つの値の和でも、
59.98347188
60.00179002
60.00114847
60.00187458
というばらつきがありました。
require 'benchmark' puts Benchmark.measure{ for i in 0...100 sleep 0.1 end } では、 Sonic Piの出力は、{run: 1, time: 10.0}でしたが、 real=9.980002644471824 stime=0.004908999999999997 utime=0.021179000000000003 でした。和は、10.00609064 音楽での時間精度は、この程度で問題ないことと思われます。 波長の半分だけずらした2つの音を同時に鳴らすことによって音を消すというようなことができない時間精度だということがわかります。 # stimeとutimeはrealに含まれている時間かもしれません.




ORCA(ORCΛ)からSonic Piに値を送る方法の概要.

From ORCA to Sonic Pi
ORCAは、2018年末に公開された文字ベースのグラフィカルなシーケンサでありライブコーディング等で注目されていますが、パズル的な要素も多く興味深いアプリケーションです。音源は持っておらず、標準的に推奨されているPilotの他、Sonic PiやMIDI音源などが活用できます。検索用?に ORCΛ が使われているようです。
ORCA側
ORCAで4拍おきにbang(駆動)する意味の D2 を適当な場所に入力し 2 の真下から右側に =C1AF3 と入力します。

(このとき、=を;とすると出力先が変わり、ORCA用の定番音源のPilotを起動していればそちらから音を出せます.)
ORCAでメニューの[OSC]→[Sonic Pi]を選びActiveにする。
スペースキーで動作を開始します。

 注釈:C1AF3の意味
 Cは楽器の種類を表し、0〜9,A-Fの16種類から選択できます。(データを送るだけならば他の文字でも可)
 1は音階を表し、0〜9までから選択できます。
 Aは音程を表し、12音CcDdEFfGgAaBから選択できます。
 Fは音量を表し、0〜F(省略可)
 3は長さを表し、0〜9(省略可)

Sonic Pi側
Sonic Pで、[Pref]→[入出力]で、[OSCサーバーを有効にする]と[OSCメッセージをリモートから受信する]をチエックします。
ORCA側が実行中であれば、cueウィンドウに
/osc/C [1, 10, 15, 3]
が連続して表示されます。ここで、Aが10に、Fが15と表示されています。
これをSonic Piのプログラムで受け取るには、
a=[]
live_loop :drum1 do
  use_real_time
  a=sync "/osc/C"  # 楽器をCとしているので
  puts a
  sample :drum_snare_soft  # 確認のため
end
配列の a[] から、[1, 10, 15, 3]が得られます。

・ORCA側で=C1AF3の右側に適当に、=C1AF39999 などと加えると、Sonic Pi側で [1, 10, 15, 3, 9, 9, 9, 9] として受け取ることができます。
・ORCA側の = の右側の送信行は、文字が連続していれば全てSonic Piに送信されます。
・画面の右端からWを飛ばす、または、上や下からNやSを行末に飛ばすと行末に捕捉されて、この値がSonic Piで新たに受信されます。
・下からNを通り抜けさせようとしたところ、残念ながら捕捉されてそのまま残りました。
・R(乱数)やC(カウント)を行末の上に置くことも可能でした。

ORCA
Pilot
Pilot
いずれもMITライセンスのオープンソースソフトウェアです。




順列音楽 Permutation Music


順列の数え上げを、指定したスケールの音を使って順に鳴らします。
桁数をやスケールを与え、全てを連続して演奏します。
3桁では、6通り
4桁では、24通り
5桁では、120通り
6桁では、720通り
7桁では、5040通り
8桁では、40320通り
9桁では、362880通り(Timing errorとなることが多い)
が鳴ります。

鳴っている順列がわかりやすくなるように spark 命令を使ってログ内に図示をしています。(4桁の最初の4通りの例)


古くは、メルセンヌ(Marin Mersenne,1588-1648)が発表している事柄です。(6桁の最初の20通り)


# permutation music
use_debug false
S= scale :C4,:major_pentatonic,num_octaves:9
N=4  # 8 or 9 is limit.

V=range(0,N)
P=[]
i=0
V.permutation do |x|
  P[i]=x
  i=i+1
end
puts P.length
for i in 0...P.length
  spark(P[i])
  for j in 0...N
    play S[P[i][j]]
    sleep 0.2
  end
  sleep 0.2
end



ピアノの音を伸ばす

今更ながら、気づいたこと
ピアノ合成音源を用いた場合、音を伸ばすには、decay:の値を大きくすればよい。
sustain:やrelease:の値を大きくしてもdecay:後の音量が小さいので効果がほとんどありません。
ADSRのDの例として使うには適当だと思われます。

use_synth :piano
play 60,amp:3,decay:4

なお、attack:0.03 等とするとアタックを少し柔らかくできます。




onset命令で分解可能な音

onsettable sound length.

onset命令を使うと一つの音を、その中の音量差が大きい部分で自動分割してくれ、別々の音として鳴らすことができます。どの程度の分解能があるのか一つの例で試してみました。
onsetは、打楽器の音などで活用されているようですが、以前別の方法で試してみた「般若心経」は思い通りには分割されませんでした。

Audacityの[ジェネレーター]→[DTMFトーン]で、
音は、0123456789ABCD、振幅は0.8にそれぞれ固定、継続時間を4sec前後、トーンと無音の比を80%前後で変化させてWAVファイルを作成しました。
下記のプログラムで再生し、正常に分割されたかどうか確認しました。
継続時間を3.9secに変更したり、比を82%等に変更すると正常に分割されなり、この条件では、4sec、80% が限界でした。

f="DTMF_04_800.wav"
for i in 0...14 do
  sample f, onset: i
  sleep 0.3
end

分解できた音の例(Audacity:DTMF)


音と無音の各長さは、
14の音の間に13の無音が挟まれていて、無音部分は音の20%なので、一つの音の長さxは、
0.8*14*x + 0.2*13*x = 4 (sec)
x=20/69 (=0.28985507)

音の長さは、約0.232sec
間の無音は、約0.058sec
でした。


PCの性能によっても結果が変わる可能性があります。
動作環境は、iMac(27-inchi Late 2013, 3.5GHz Core i7) OSX Yosemite 10.10.5、Sonic Pi v3.1



スティーブ・ライヒの"Reed Phase"風な鼻笛による"Nose Flute Phase"

Nose Flute Phase, Inspired by Steve Reich - Reed Phase

鼻笛のBocarinaで、スティーブ・ライヒのReed Phase(1966)の一節を吹き、これをSonic Piで微小時間ずらして3パートとして鳴らしています。当初は、pitch_stretch: で音程を変えずに長さだけを僅かに変えようと思いましたが、音が乱れるのでやめました。
Sonic Piでは、これだけ簡単に50以上年前の前衛作品がそれらしく作成できます。


私の、鼻笛によるD5,A5,G5,C6,A5の演奏音 License CC-BA
# "Nose Flute Phase" , Inspired by Steve Reich - Reed Phase
f="20111015_220614NoseFlutePhase1.wav"
lenf=sample_duration f
with_fx :reverb,room:0.8,mix:0.5 do
  i=0
  in_thread do
    114.times do
      sample f,pan:0
      sleep lenf
      i=i+1
      puts i
    end
  end

  sleep lenf*4
  in_thread do
    100.times do
      sample f,pan:-0.7
      sleep lenf+0.01
      sleep 0.01
    end
  end
  
  sleep lenf*8
  in_thread do
    100.times do
      sample f,pan:0.7
      sleep lenf+0.02
    end
  end
end

原曲は、Youtubeに数点あります。
楽器による実演は、Jutlandia Saxophone Quartet のように循環呼吸が必須ですので鼻笛では不可能です。
同 Steive Reich の Clapping Music の例は、Clapping Music on Sonic Pi



日本語変数名を使う

(今更ながら)日本語を変数名に使ってみたところ問題ありませんでした。
ド=:C4
play ド
sleep 1
和音1=chord(:C4,:M)
play 和音1

Rubyではクラス名以外は日本語が利用可能なようです。




10進数をn音階にして鳴らす

任意の長さの10進数を12進数に変換すると、12音階に当てはめることができます。
6進数に変換して6音の音階、3進数にして、3種類の打楽器を鳴らすなどが考えられます。

Rubyに用意されている関数を使っているため整数のみ入力可。
負の値の"-"の処理もしていないので正の値の自然数のみ可。

a10=1234567890123456789012345678901234567890123456789012345678901234567890

#b12=a10.to_s(12).ring # 12音階の場合
b12=a10.to_s(6).ring # 6音階の場合
c3=a10.to_s(3).ring

i=0
use_synth :pluck
with_fx :reverb, room:1 do
  in_thread do
    loop do
      # play (scale :C, :chromatic)[b12[i].to_i(10)],amp:1.5 # 12音階の場合
      play (scale :C, :hirajoshi)[b12[i].to_i(10)],amp:1.5 # 6音階の琴の平調子場合
      sleep 0.24 if i % 2 ==1
      sleep 0.76 if i % 2 ==0
      i=i+1
    end
  end
end

in_thread do
  loop do
    sample :drum_cymbal_closed if c3[i].to_i(12)==0
    sample :drum_bass_hard if c3[i].to_i(12)==1
    sample :drum_snare_soft if c3[i].to_i(12)==2
    sleep 0.5
  end
end





画像を線画SVG音楽に

任意の画像をベクトル画像化(SVG)して、座標を音程としてSonic Piで音にしました。
ビットマップ画像は、PythonのlinedrawプログラムでSVGファイルに変換できます。生成されたSVGファイルは、折れ線を記述するpolyline points要素のみできているので、ここからX,Y座標のペアを得ることができます。
Sonic Piのプログラムでは、あらかじめSVGデータを全て読み込み、X,Y座標の最大値と最小値を求めて、これを最高音と最低音の間にマッピングしています。一つの折れ線では、音程は連続したポルタメントで変化させています。XとY座標は、別の音色の音程として使用しています。X座標は、Panの値にも使用しています。

linedrwawの動作サンプルにあったlennaは、画数が多いSVGとなる(図中央)ので、これを簡略化(右側)したlenna_simple.svg演奏した音は、これ(mp3ファイル)です。(165本の折れ線, 再生時間97秒) このままでは面白みはありませんので、もう一工夫が必要です。
なお、SVGファイルは、Inkscape等で編集できますが、編集後に書き出すとヘッダー等のタグが付け足されてしまうため、下記のプログラムでは読み込めなくなります。

---source code---
path="./lenna_simple.svg" # linedrawで変換生成したSVGファイルへのパス
f=File.open(path).read

use_debug false
d = []
dt=0.05 # 折れ線の一つの直線を鳴らす時間

MidiMin=:C3.to_i  # 最低音
MidiMax=:C7.to_i  # 最高音

Xmin=10000
Xmax=-10000
Ymin=10000
Ymax=-10000

open(path){|f| d = f.readlines}  #  座標の最大値、最小値を見つける
for i in 0...d.length-1
  s0=d[i].index("<polyline points=")+19-1
  s1=d[i].index("stroke")-3
  s=d[i][s0..s1]
  d[i]=s.split(",")
  for j in 0...d[i].length/2
    t0=d[i][j*2].to_f
    t1=d[i][j*2+1].to_f
    Xmin=t0 if(t0Xmax)
    Ymin=t0 if(t1Ymax)
  end
end

open(path){|f| d = f.readlines}
for i in 0...d.length-1
  s0=d[i].index("<polyline points=")+19-1
  s1=d[i].index("stroke")-3
  s=d[i][s0..s1]
  d[i]=s.split(",")
  sleep dt
  for j in 0...d[i].length/2
    t0=d[i][j*2].to_f
    t1=d[i][j*2+1].to_f
    a=(MidiMax-MidiMin)/(Xmax-Xmin)
    MidiX=(t0-Xmin)*a+MidiMin
    panX=(t0-Xmin)*a/(MidiMax-MidiMin)*1.99-1
    MidiY=(t1-Ymin)*a+MidiMin
    
    use_synth :saw  # Xの音色
    p0 = play MidiX,sustain: d[i].length/2*dt, release: 0.1, note_slide: d[i].length/2*dt, pan_slide: d[i].length/2*dt if j==0
    control p0, note: MidiX, pan: panX
    
    use_synth :square  # Yの音色
    p1 = play MidiY,sustain: d[i].length/2*dt, release: 0.1, note_slide: d[i].length/2*dt if j==0
    control p1, note: MidiY
    
    sleep dt
  end
end
-----
linedraw (MIT-License) LingDongさん作
Linedraw (MoonGiftでの紹介)
linedrawの使い方
python linedraw.py -i input.jpg -o output.svg

他にも画像の可聴化の例は多数ありましたが、ベクトル化を経るものは見つかりませんでした。
他の例
・画像を左から右にスキャンして縦一列のデータを得て白部分を周波数にして音とする。
 モノクロ画像を音に変換する「ピクセル・シンセ」で奇妙なアンビエントを
 PIXELSYNTH
写真を音に変換できるユニークなシンセ・アプリ「Pollisynth」が現在無償で配布中 (iOS)
・画像の色情報を音楽へ変換する「RGB MusicLab」(Win)
 画像のピクセルを読み取ってRGBそれぞれの値を音の高さに変換 (MIDIファイル化)
VIDEOVOXは画像から音声を生成する、想定外のソフトシンセ! : SUPERBOOTH16
 VIDEOVOX
1枚の画像が音楽に自動変換! 元・三木道三のDOZAN11が開発した音楽ソフト「PhotoMusic 2」が斬新すぎる
シュトックハウゼンの『Studie II』(1954)
VST Instrumentプラグイン Coagula (macOS/Win)
 Industrial Strength Color-Note Organ
How FL Studio’s BeepMap Synth Converts Images into Sounds





新型コロナウィルス遺伝子配列音楽

新型コロナウイルス(SARS-CoV-2) の遺伝子配列を音にしました。 既出の下記とほぼ同じ内容です。
DNA ゲノム音楽 (MIT-Media Lab.所長伊藤穣一氏の遺伝子塩基配列を使用) (DNA Gene music)

新型コロナウイルス(SARS-CoV-2) のゲノム情報
のGenBank MN908947

Severe acute respiratory syndrome coronavirus 2 isolate Wuhan-Hu-1, complete genome の
GenBank: の最初のデータ、中国で解析されて2019.12に登録されたデータMN908947を用いました。
ORIGIN 以下の
        1 attaaaggtt tataccttcc caggtaacaa accaaccaac tttcgatctc ttgtagatct
から
    29881 aaaaaaaaaa aaaaaaaaaa aaa
までを、コピペ等でテキストファイルに保存して使用しました。coronaGen.txt
塩基配列のACGTを:A4,:C4,:G4,:E4の音程と打楽器音として順番に鳴らしているだけですので、音楽とは言い難いものです。

CoronaVirusSound.mp3 MP3ファイル

# Corona Virus Sound
path="coronaGen.txt"
d = []
open(path){|f| d = f.readlines}
for i in 0...d.length
  for j in 0...6
    for k in 0...10
      g=d[i][j*10+j+10+k]
      play :a, amp:1.5, pan: rrand(-1,1) if g=="a"
      play :c, amp:1.5, pan: rrand(-1,1) if g=="c"
      play :g, amp:1.5, pan: rrand(-1,1) if g=="g"
      play :e, amp:1.5, pan: rrand(-1,1) if g=="t"
      sleep 0.1
      sample :drum_cymbal_closed if g=="a"
      sample :drum_heavy_kick if g=="c"
      sample :drum_snare_hard if g=="g"
      sample :drum_tom_hi_hard if g=="t"
      sleep 0.1
    end
  end
end
stop
最後まで鳴らすことはまずないと思われますが、最後の行のデータが短いので、エラーで終了すると思います。


より優れた音楽化されている例は、
Scientists have turned the structure of the coronavirus into music



QueenのPlay The Gameのイントロのシンバル音の逆再生をSonic Piで

NHK-FM 2021年12月5日「ディスカバー・クイーン:クイーンズ・クロニクル~ザ・ゲーム サイドA~」で作編曲家の西脇辰弥さんが、QUEENのアルバム「The GAME」1曲目「Play The Game」のイントロが、チャイナシンバル音の逆再生で作られているという解説をしていました。これをSonic Piに内蔵されているサンプル音源 :drum_cymbal_open を使って試してみました。最初は速くだんだんゆっくりに、音は交互に左右から出て、音程を微妙にズラすようにしました。Sonic Piでは、一つの逆再生音の再生中に速度を変化させることはできないので、一つのシンバル音の逆再生中は一定速度としています。
放送では、開始12分30秒くらいからが当該の部分でした。
番組サイト https://www4.nhk.or.jp/queen2021/5/ YouTube


Queenによる「Play The Game」




画像を変換して、スペクトログラムが元の画像となるような音を生成するプログラム

A program that transforms an image to generate sounds such that the spectrogram is the original image.

「14平米にスーベニア 広川恵一 Remix」と言う曲のスペクトログラムを見ると久川凪というキャラクターが現れるということがTwitter等で話題となっていました。とあるアイドルの楽曲に画像が仕込まれていた話」など。 そこで、任意の画像で同様なことをやってみたいと思い、音を容易に扱えるSonic Piで検討してみました。Rubyの機能を使いSonic Piのみで画像ファイルを読み込みピクセル毎の色を取得することもできると思われますが、Rubyについては詳しくないので音生成に必要な数値のテキストファイル作成までの過程にProcessing言語を使い、その後Sonic Piで音を生成することにしました。Processingは、Sonic Pi同様、アプリケーションとしての実行環境を持っているので、下記のソースリストを貼り付けるだけで実行ができます。

画像の縦方向が周波数に、横方向が時間、ピクセルの色情報が音量に対応させます。 Proessingで画像ファイルを読み込み、1ピクセルずつの輝度を数値化したスペース区切りのテキストファイルを生成します。 その後、そのテキストファイルをSonic Piで読み込み、画像の左端に縦に並んだドット数に対応する周波数の正弦波を同時に鳴らします。 これを一定時間(1秒等)鳴らした後、左から二番目のドット列に対応した音を同時に鳴らします。これを画像の右端まで続けます。Sonic Piは同時発音数が増えると発音タイミングがずれ、さらに増えるとエラー終了してしまいます。そこで、画像の縦幅は100ピクセル程度以下が適当でした。画像の横幅は時間軸となるので長さに制限はありません。 プログラムでは、白を音量ゼロ側にしているので、背景色が白色の画像が適当です。

使い方
1) 100×100以下程度の画像を用意します。大きい画像の場合はGIMP等で縮小します。
白を音量0側としているので、背景色が白い画像が適当です。
プログラム中では輝度の最大値と最小値を調べてから最大値(白)を音量ゼロとしています。
2) ProcessingのプログラムImage2Spectrogram.pdeのソースリスト中の画像ファイル名(フルパス)を変更します。(画像毎にファイル名を変更のこと)
3) Processingプログラムを実行すると、Processingのソースファイルのあるフォルダ内にImage2Spectrogram.txtが生成されます。
4) Sonic Piのプログラム中でImage2Spectrogram.txtへのフルパスを与えます。(以降変更不要)
SonicPiのソースリスト中の変数freqMinとfreqMaxに、画像が生成される最小周波数と最大周波数を与えます。
Sonic PiのプログラムをRecボタンを押してから実行します。
1ピクセル1秒としているので横幅100ピクセルの画像の場合100秒かかります。終了後、再度Recボタンを押すと保存するファイル名を聞いてきます。
5) Sonic Piで生成されたWAVファイルをAudacityで読み込み、スペクトルグラム表示にし、スペクトルグラムのパラメータを適当に変更して画像を得ます。

補足
・画像を反転させたい場合にには、Processingプログラム中のコメント行にしてある"画像を反転させる場合"の行を生かして下さい。 ・ステレオの左右を別々の画像にしたい場合には、Sonic Piでpanを-1または1として、それぞれ録音してからAudacityでMIXしてください。ステレオで2つ作成して、Audacityで左右チャンネルを分ける等でも可。
・低音域と高音域(可聴周波数以上等)で2つの音を生成してからAudacityでMIXすれば、2つの画像を同時に表示することができます。
・縦長の画像も縦100ドット以下に横2分割してMIXすれば一つの大きな画像として得ることができます。
・画像の横幅を短くするためAudacityのエフェクトでテンポの変更を使うと、スペクトルグラムで得られる画像が乱れます。
・Sonic Piでの発音時間を0.1秒、その後sleep 0.9で無音を作り、この繰り返しの断続音で音を作成しておき、Audacityの[エフェクト]→[無音の切り詰め]によって時間軸を短くすることもできます。このとき、発音時間の比tRatio=0.1であれば1ドットの音の長さtStep=0.5秒程度でも処理の遅れは見られませんでした。

以上で、任意の画像をスペクトラグラム中に表示することはできますが、音として聴き応えのあるものにするにはパラメータの調整等が必要です。

Processingプログラム 最初に使用します。
// Image2Spectrogram.pde
PImage img;
void setup() {
  int w, h;
  color c;
  size(200, 200);  // 画像ファイルのサイズより大きくする size(横,縦)
  img=loadImage("Nagi.jpg");  // 画像ファイル名、Processingの画面上にドロップする。
  w=img.width;
  h=img.height;
  String[] data=new String[1];
  data[0]=w+" "+h;

  image(img, 0, 0);
  loadPixels();
  float maxB=-1,minB=999;

  for(int i=0;i<h*w;i++) {
    if(brightness(pixels[i])< minB) minB=brightness(pixels[i]);
    if(brightness(pixels[i])> maxB) maxB=brightness(pixels[i]);
  }
  println("Brightness=",minB," ",maxB);
  for (int i=0; i<w; i++) {
    for (int j=0; j<h; j++) {
      c=get(i, j);
      float k=(map(brightness(c), minB, maxB, 1, 0)); // SonicPiでのamp値となる.
//      float k=(map(brightness(c), minB, maxB, 0, 1)); // SonicPiでのamp値となる. 画像を反転させる場合
      data[0]=data[0]+" "+nf(k, 0, 2);
    }
    data[0]=data[0]+"#";
  }
  saveStrings("Image2Spectrogram.txt", data); // 出力テキストファイル名。Sonic Piでこれを読み込みます。
  println("Size= ",w, h);
}


Sonic Piプログラム 2番目に実行します。

use_debug false

freqLow=50; # 周波数の下限Hz 0や1は不可。10Hz以上が適当
freqHigh=8000; # 周波数の上限Hz
tStep=1.0 # 画像の縦方向の解像度が大きい場合には、同時発音数が多すぎるため、一音の長さ1秒程度まで長くしないと処理速度が追いつかず発音が遅れたりエラーします。

sazae=File.open("/Users/???/Documents/Processing3/Image2Spectrogram/Image2Spectrogram.txt").read.split(" ")  # Processingで出力したファイル名をフルパスで指定する
w=sazae[0].to_i;
h=sazae[1].to_i;
freqStep=(freqHigh-freqLow)/h.to_f
puts "w,h=",w,h
puts "freqStep=",freqStep
for i in 0...w
  for j in 0...h
    k=i*h+j+2;
    # attach,sustain,release,ampの値は要検討
    play hz_to_midi((h-j-1)*freqStep+freqLow),amp: sazae[k].to_f/20.0,attack:tStep*0.00,sustain:tStep*1,release:tStep*0.0
  end
  sleep tStep
  puts i,"/",w
end


上記のプログラムは、1ドットあたり1秒で再生されます。これを短くするため、1秒間隔の0.1秒の断続音として作成し、後からAudacityの[エフェクト]→[無音の切り詰め]で総再生時間を短縮した画像を作成するためのプログラムは、下記です。
断続音version
use_debug false

freqLow=50; # 周波数の下限Hz 0,1は不可。10Hz以上
freqHigh=8000; # 周波数の上限Hz
tStep=1.0 # 画像の縦方向の解像度が大きい場合には、同時発音数が多すぎるため、一音の長さ1秒程度まで長くしないと処理速度が追いつかず発音が遅れたりエラーします。
tRatio=0.1 # 断続音の比率

sazae=File.open("/Users/???/Documents/Processing3/Image2Spectrogram/Image2Spectrogram.txt").read.split(" ")  # Processingで出力したファイル名をフルパスで指定する
w=sazae[0].to_i;
h=sazae[1].to_i;
freqStep=(freqHigh-freqLow)/h.to_f
puts "w,h=",w,h
puts "freqStep=",freqStep
for i in 0...w
  for j in 0...h
    k=i*h+j+2;
    # attach,sustain,release,ampの値は要検討
        play hz_to_midi((w-j-1)*freqStep+freqLow),amp: sazae[k].to_f/20.0,attack:tStep*0.00*tRatio,sustain:tStep*1*tRatio,release:tStep*0.0*tRatio
  end
  sleep tStep
  puts i,"/",w
end
初音ミクとさざえさんの元画像


初音ミクを低音領域、さざえさんを高音領域(若者にしか聞こえない音)に作成した例。この2つの音をミックスして上下に並べて表示することもできます。(Audacityのスペクトラグラム表示)
これは少々横長ですが、縦、横のサイズはAudacityの画面サイズを変えることによって自由になります。
「14平米にスーベニア 広川恵一 Remix」から現れる画像に対して反転しています。同じようにするには、上記の補足のようにしてください。
作成したWAVファイルの例は、このリンクです。 下記の初音ミクとサザエさんをミックスしたWAVファイルです。


久川凪さんの縦200ドットの画像を上下に分割して別々に音にしてからミックスして一つの絵にした例(Audacityのスペクトラグラム表示)


Audacityのスペクトラグラム設定例
ゲインやレンジの設定を変えることによって色合い等を変えることができます。窓関数サイズも影響します。
Sonic Piのプログラム中で指定した最低周波数、最高周波数に合わせて下さい。




Sonic Piの全てのスケール151を鳴らし、OSCでProcessingに送って五線譜表示をする

Sound all 151 scales of the Sonic Pi and send them to Processing in OSC for stave display.


scale_namesからscale_names.length個のスケール名を取得してplay_pattern_timedで鳴らしています。
このスケールの音程をOSCでProcessingに渡して、スケール名と五線譜上に音符として表示しています。
このとき、スケール名をmacOSのsayコマンドで読み上げています。この部分はWindowsでは動作しません。

Sonic Pi側のプログラム
system('say Sonic Pi version 4.4.0.  151scales.')
sleep 6
use_synth :piano
scale_names.length.times do
  s1=scale_names.tick
  
  puts s1
  use_osc "localhost", 4563
  osc "/message", (scale :C, s1).to_s
  s2='say '+s1.to_s
  system(s2)
  sleep 1.5
  play_pattern_timed(scale :C, s1),0.3
  sleep 1
end
sleep 1
system('say Thats all.')



ハノンピアノ教本の1番から20番を鳴らす

Hanon piano exercises 1-20
ハノンピアノ教本の1番から20番は、ほぼ同じパターンで上昇と下降を繰り返すため、プログラムで記述するのに適当です。例外は、1番と20番だけです。1番は下降が1小節多く、20番は最後の音が異なります。
黒鍵を使わないため、キーがCの:majorスケール内の音の順番だけで全ての音を出すことができます。


1番から10番までは、


1番から20番までを連続して鳴らすプログラムは、

# HANON No.1-20 Hanon piano exercises
use_synth :piano
use_bpm 600  # 600のとき演奏時間8分1秒, 900のとき5分20秒


#for num in 1..20 do
(1..20).each do |num|
  case num
  when 1
    up=(ring 1,3,4,5,6,5,4,3)
    down=(ring 5,3,2,1,0,1,2,3)
  when 2
    up=(ring 1,3,6,5,4,5,4,3)
    down=(ring 5,2,0,1,2,1,2,3)
  when 3
    up=(ring 1,3,6,5,4,3,4,5)
    down=(ring 5,2,0,1,2,3,2,1)
  when 4
    up=(ring 1,2,1,3,6,5,4,3)
    down=(ring 5,4,5,2,0,1,2,3)
  when 5
    up=(ring 1,6,5,6,4,5,3,4)
    down=(ring 1,2,1,3,2,4,3,5)
  when 6
    up=(ring 1,6,5,6,4,6,3,6)
    down=(ring 5,0,1,0,2,0,3,0)
  when 7
    up=(ring 1,3,2,4,3,5,4,2)
    down=(ring 5,3,4,2,3,1,2,3)
  when 8
    up=(ring 1,3,5,6,4,5,3,4)
    down=(ring 5,3,1,0,2,1,3,2)
  when 9
    up=(ring 1,3,4,3,5,4,6,5)
    down=(ring 5,3,2,3,1,2,0,1)
  when 10
    up=(ring 1,6,5,4,3,4,3,4)
    down=(ring 5,0,1,2,3,2,3,2)
  when 11
    up=(ring 1,3,6,5,6,5,4,5)
    down=(ring 5,2,0,1,0,1,2,1)
  when 12
    up=(ring 6,1,3,2,1,2,3,1)
    down=(ring 0,5,3,4,5,4,3,5)
  when 13
    up=(ring 3,1,4,2,5,3,4,5)
    down=(ring 3,5,2,4,3,1,2,3)
  when 14
    up=(ring 1,2,4,3,4,3,5,4)
    down=(ring 5,4,2,3,2,3,1,2)
  when 15
    up=(ring 1,3,2,4,3,5,4,6)
    down=(ring 5,3,4,2,3,1,2,0)
  when 16
    up=(ring 1,3,2,3,6,5,4,5)
    down=(ring 5,2,3,2,0,1,2,1)
  when 17
    up=(ring 1,3,6,5,7,6,5,6)
    down=(ring 5,2,0,1,-1,0,1,-1)
  when 18
    up=(ring 1,2,4,3,5,4,2,3)
    down=(ring 5,4,2,3,1,2,4,3)
  when 19
    up=(ring 1,6,4,5,6,4,3,5)
    down=(ring 5,0,2,1,0,2,3,1)
  when 20
    up=(ring 3,5,8,10,8,7,8,6)
    down=(ring 10,8,5,3,5,4,5,3)
  end
  
  num=0
  i=0
  j=7
  num=1
  
  14.times do
    up.length.times do
      # stop
      play scale(:C3,:major,num_octaves: 5)[up[i]-1+j],release:3
      play scale(:C2,:major,num_octaves: 5)[up[i]-1+j],release:3
      sleep 1
      i=i+1
    end
    j=j+1
  end
  
  i=0
  j=7+7+7
  ndown=14
  ndown=15 if num==1  # 1番の下降回数は例外
  ndown.times do
    down.length.times do
      # stop
      play scale(:C3,:major,num_octaves: 5)[down[i]-1+j],release:3
      play scale(:C2,:major,num_octaves: 5)[down[i]-1+j],release:3
      sleep 1
      i=i+1
    end
    j=j-1
  end
  sleep 0.5
  play [:C3,:C4],amp:3,sustain:3,release:3
  play [:E4,:C5],amp:3,sustain:3,release:3 if num==20  #最後の20番の終わり
  sleep 8
end



SonicPiの10個のバッファの中身をSonicPi_日付.txtというファイル名でカレントディレクトリにバックアップする方法。

Backup 10 buffers of SonicPi to a single text file with a file name of the date.

Sonic Piの0-9までの10個のBufferを無造作に使っていると、いっぱいになってしまい消去しないと新たなプログラムを作成できなくなってしまいます。どれを消去するか迷うよりも、全部のバックアップを取って消してしまう方が楽です。バッファの中身は、ホームディレクトリにある.ピリオドで始まる隠しディレクトリの中に入っています。これをcatコマンドでつなげて一つのファイルに書き出します。
macOSのターミナルコマンドでは、(bashとzshで確認)
cat ~/.sonic-pi/store/default/*.spi > SonicPi_`date +%Y%m%d`.txt
とすると、カレントディレクトリにその日の日付のついた "SonicPi_20230905.txt" 等というファイルができ、Buffer0-9の内容が全てつなげて格納されます。

WindowsでもWSL等で同様の操作ができると思われます。



正弦波の場合 amp:2.5 を越えると波形が歪み、音も濁ります。

For sine waves, exceeding amp:2.5 will distort the waveform.

デフォルト設定、または、use_synth :beep または :sine の場合、
play 60, amp:2.5
のとき、波形の振幅がちょうど1.0となります。(下図、録音してAudacityで確認)


これをこえると、波形が保てなくなります。 わかりやすいようにampの値を大きく3.0とすると、
サイン波の頭が切り取られて台形となり、音にも濁りが現れます。

さらにamp:100とすると、ほぼ矩形の波形となります。
:squareの矩形波は、矩形からずれているので、サイン波のampを大きくした方が矩形波として適当だと思われます。


このような現象は、2つの音が同時に鳴って重なった結果振幅が大きくなった場合にも当てはまりますので、意図的に歪ませたい場合以外には注意が必要です。
play 60
play 60
play 60
この場合、振幅が最大3になり、波形が崩れます。
位相差によって打ち消されて振幅が小さくなる場合もあります。
他の音色の場合には、amp:2.5より小さい値でも振幅が振り切れることがあります。





ハノンピアノ教本60番

Hanon Piano Lessons No.60
ハノンピアノ教本の最後の曲60番を入力してみました。1〜20番と異なり決まったパターンは少なく、曲としても壮大なミニマルミュージックです。

強弱等は入力していません。左右どちらかをstopして片手の音を聞くこともできます。
1小節の前半後半を2つの配列に格納しています。配列の後ろの#数字が小節番号です。
パターンから外れる例外をtype 0〜6として処理しています。
誤りがありましたらお知らせください。


# HANON No.60
use_bpm 60   #60 90 100
use_debug false
use_synth :piano
panR=0.8
panL=-0.8
a=[]
b=[]
a0=[]
a1=[]
b0=[]
b1=[]
type=[]

type[1]=0
a[1]=[[:E4,:G4],:C4] #1 小節番号 measure number
b[1]=[[:C3,:E3],:G3]
type[2]=0
a[2]=[[:F4,:G4],:D4]
b[2]=[[:B2,:D3],:G3]

type[3]=0
a[3]=a[1] #2
b[3]=b[1]
type[4]=5
a[4]=[[:A4,:C5],:E4]
b[4]=[[:A2,:E3],:A3]
b1[4]=[[:C3,:E3],:A3]

type[5]=0
a[5]=[[:G4,:B4],:D4] #3
b[5]=[[:D3,:G3],:B3]
type[6]=0
a[6]=[[:D4,:Fs4,:A4],:C4]
b[6]=[:D2,:D3]

type[7]=0
a[7]=[[:D4,:G4],:B3]#4
b[7]=[:G2,:G3]
type[8]=0
a[8]=a[7]
b[8]=[:G2,:F3]

type[9]=0
a[9]=a[1]#5
b[9]=b[1]
type[10]=0
a[10]=[[:E4,:Gs4],:D4]
b[10]=[[:B2,:D3],:E3]

type[11]=0
a[11]=[[:E4,:A4],:C4]#6
b[11]=[[:A2,:C3],:E3]
type[12]=0
a[12]=[[:A4,:D5],:F4]
b[12]=[[:F2,:A2],:D3]

type[13]=0
a[13]=[[:G4,:C5],:E4]#7
b[13]=[[:G2,:C3],:E3]
type[14]=0
a[14]=[[:G4,:B4],:F4]
b[14]=[[:G2,:D3],:G3]

type[15]=0
a[15]=a[13]#8
b[15]=b[1]
type[16]=0
a[16]=a[13]
b[16]=b[1]

type[17]=0
a[17]=[[:C5,:E5,:G5],:G4]#9
b[17]=[[:C3,:E3,:G3],:C4]
type[18]=0
a[18]=[[:D5,:F5,:G5],:G4]
b[18]=[[:B2,:D3,:G3],:B3]

type[19]=0
a[19]=a[17]#10
b[19]=b[17]
type[20]=0
a[20]=[[:E5,:A5,:C6],:C5]
b[20]=[[:A2,:E3],:A3]

type[21]=0
a[21]=[[:D5,:G5,:B5],:B4]#11
b[21]=[[:D3,:G3,:B3],:D4]
type[22]=0
a[22]=[[:D5,:Fs5,:A5],:C5]
b[22]=[[:D3,:Fs3,:A3],:D4]

type[23]=0
a[23]=[[:B4,:D5,:G5],:G4]#12
b[23]=[[:G2,:B2,:D3],:G3]
type[24]=0
a[24]=a[23]
b[24]=[[:G2,:B2,:D3],:F3]

type[25]=1
a[25]=a[17]#13
b[25]=[[:C3,:E3,:G3],:C4]
b1[25]=[:C3,:E3]
type[26]=0
a[26]=[[:D5,:E5,:Gs5],:Gs4]
b[26]=[[:B2,:D3,:E3],:B3]

type[27]=0
a[27]=[[:C5,:E5,:A5],:A4]#14
b[27]=[[:A2,:C3,:E3],:A3]
type[28]=5
a[28]=[[:A5,:D6,:F6],:F5]
b[28]=[[:D2,:A3],:D3]
b1[28]=[[:F2,:A3],:D3]

type[29]=0
a[29]=[[:G5,:C6,:E6],:E5]#15
b[29]=[[:G2,:C3,:E3],:G3]
type[30]=0
a[30]=[[:G5,:B5,:D6],:F5]
b[30]=[[:G2,:B2,:D3],:G3]

type[31]=0
a[31]=[[:E5,:G5,:C6],:C5]#16
b[31]=[[:C3,:E3,:G3],:C4]
type[32]=2
a[32]=[:E5,:G5,:C6]
b[32]=[:C3,:E3,:G3]

type[33]=0
a[33]=[[:C5,:E5],:E4]#17
b[33]=[[:A3],:C4]
type[34]=3
a[34]=[[:D5,:F5],:F4]
b[34]=[[:Gs3],:B3]
a1[34]=[[:C5,:E5],:E4]
b1[34]=[[:A3],:C4]

type[35]=0
a[35]=[[:A4,:D5],:D4]#18
b[35]=[[:F3],:A3]
type[36]=0
a[36]=a[35]
b[36]=b[35]

type[37]=0
a[37]=[[:A4,:C5],:C4]#19
b[37]=[[:Ds3],:Fs3]
type[38]=0
a[38]=[[:B4],:C4]
b[38]=b[37]

type[39]=0
a[39]=[[:E4,:Gs4],:B3]#20
b[39]=[[:E3],:Gs3]
type[40]=0
a[40]=[[:G4],:E4]
b[40]=[[:E3,:G3],:B3]

type[41]=0
a[41]=[[:C5,:E5],:E4]#21
b[41]=b[33]
type[42]=3
a[42]=[[:D5,:F5],:F4]
b[42]=b[34]
a1[42]=a[41]
b1[42]=b[41]

type[43]=0
a[43]=[[:A4,:D5],:D4]#22
b[43]=[[:Fs3],:A3]
type[44]=0
a[44]=[[:A4,:C5],:Ds4]
b[44]=[[:F3],:A3]

type[45]=0
a[45]=[[:A4,:A5],:E4]#23
b[45]=[[:E3,:A3],:C4]
type[46]=4
a[46]=[[:E4,:Gs4,:C5],:D4]
b[46]=[[:E2],:E3]
a1[46]=[[:E4,:G4,:B4],:D4]

type[47]=0
a[47]=[[:E4,:A4],:C4]#24
b[47]=[[:C3,:E3,:G3],:C4]
type[48]=2
a[48]=[:E4,:A4]
b[48]=[:C3,:E3,:G3]

type[49]=0
a[49]=[[:C5,:E5],:E4]#25
b[49]=[[:A3],:C4]
type[50]=3
a[50]=[[:C5,:F5],:F4]
b[50]=[[:A3],:C4]
a1[50]=[[:C5,:Fs5],:Fs4]
b1[50]=[[:Af3],:C4]

type[51]=0
a[51]=[[:C5,:G5],:G4]#26
b[51]=[[:G3,:C4],:E4]
type[52]=0
a[52]=[[:C5,:A5],:A4]
b[52]=[[:Fs3,:C4],:Ds4]

type[53]=0
a[53]=[[:C5,:E5],:G4]#27
b[53]=[[:G3,:C4],:E4]
type[54]=0
a[54]=[[:G4,:B4,:E5],:F4]
b[54]=[[:G2],:G3]

type[55]=0
a[55]=[[:E4,:G4,:C5],:C4]#28
b[55]=[[:C2],:C3]
type[56]=2
a[56]=[:E4,:G4,:C5]
b[56]=[:C2]

type[57]=0
a[57]=[[:A5,:C6],:C5]#29
b[57]=[[:F3,:A3],:C4]
a1[57]=[[:A5,:Ds6],:Ds5]
type[58]=4
a[58]=[[:A5,:D6],:D5]
b[58]=[[:F3,:A3],:C4]
a1[58]=[[:A5,:Ds6],:Ds5]

type[59]=0
a[59]=[[:A5,:E6],:E5]#30
b[59]=[[:E3,:A3],:C4]
type[60]=0
a[60]=[[:A5,:F6],:F5]
b[60]=[[:Ds3,:A3],:C4]

type[61]=0
a[61]=[[:A5,:C6,:E6],:E5]#31
b[61]=[[:E3,:A3],:C4]
type[62]=4
a[62]=[[:E5,:Gs6,:C6],:D5]
b[62]=[[:E2],:E3]
a1[62]=[[:E5,:Gs6,:B5],:D5]

type[63]=0
a[63]=[[:C5,:E5,:A5],:A4]#32
b[63]=[[:A2],:A3]
type[64]=2
a[64]=[:C5,:E5,:A5]
b[64]=[:A2]

type[65]=0
a[65]=[[:C5,:E5],:A4]#33
b[65]=[[:A3,:C4],:E4]
type[66]=4
a[66]=[[:C5,:F5],:A4]
b[66]=b[65]
a1[66]=a[65]

type[67]=4
a[67]=[[:E5,:B5],:C5]#34
b[67]=[[:A3,:C4],:E4]
a1[67]=[[:E5,:G5],:C5]
type[68]=3
a[68]=[[:A4,:F5],:F4]
b[68]=[[:D3,:A3],:D4]
a1[68]=[[:A4,:D5],:F4]
b1[68]=[[:F3,:A3],:D4]

type[69]=0
a[69]=[[:A4,:C5],:E4]#35
b[69]=[[:E3,:A3],:C4]
type[70]=0
a[70]=[[:Gs4,:B4],:E4]
b[70]=[[:E3,:Gs3],:B3]

type[71]=0
a[71]=[[:A4,:D5],:F4]#36
b[71]=[[:F3],:A3]
type[72]=0
a[72]=[[:A4,:C5],:E4]
b[72]=[[:A3],:C4]

type[73]=0
a[73]=[[:C5,:E5],:A4]#37
b[73]=[[:A2,:C3],:E3]
type[74]=4
a[74]=[[:C5,:F5],:A4]
b[74]=[[:A2,:C3],:E3]
a1[74]=[[:C5,:E5],:A4]

type[75]=4
a[75]=[[:E5,:C6],:C5]#38
b[75]=[[:A2,:C3],:E3]
a1[75]=[[:E5,:A5],:C5]
type[76]=3
a[76]=[[:A4,:F5],:F4]
b[76]=[[:D2,:A2],:D3]
a1[76]=[[:A4,:D5],:F4]
b1[76]=[[:F2,:A2],:D3]

type[77]=0
a[77]=[[:A4,:C5],:E4]#39
b[77]=[[:E2,:A2],:C3]
type[78]=4
a[78]=[[:E4,:Gs4,:C5],:D4]
b[78]=[[:E2,:Gs4,:B2],:C3]
a1[78]=[[:E4,:Gs4,:B4],:D4]

type[79]=0
a[79]=[[:C4,:E4,:A4],:A3]#40
b[79]=[[:A2,:C3],:E3]
type[80]=5
a[80]=[[:C4,:E4,:A4],:A3]
b[80]=[[:E2],:E3]
b1[80]=[[:C2],:C3]

type[81]=0
a[81]=[[:C4,:E4,:A4],:A3]#41
b[81]=[[:A2,:C3],:E3]
type[82]=5
a[82]=[[:C4,:E4,:A4],:A3]
b[82]=[[:E2],:E3]
b1[82]=[[:C2],:C3]

type[83]=0
a[83]=[[:C4,:E4,:A4],:A3]#42
b[83]=[[:A2,:C3],:E3]
type[84]=2
a[84]=[:C4,:E4,:A4]
b[84]=[[:E2],:E3]
a1[84]=[:C4,:E4,:A4]
b1[84]=[:C2]

type[85]=0
a[85]=[[:E4,:G5],:C4]#43==#1
b[85]=[[:C3,:E3],:G3]
type[86]=0
a[86]=[[:F4,:G4],:D4]
b[86]=[[:B2,:D3],:G3]

for ii in 85..112 # ここで変数iを使うとiがグローバル変数になってしまい、in_thred内のiに干渉してしまいます.
  type[ii]=type[ii-84]#43==1 , #56==14
  a[ii]=a[ii-84]
  b[ii]=b[ii-84]
  a1[ii]=a1[ii-84]
  b1[ii]=b1[ii-84]
end

type[113]=0
a[113]=[[:G5,:C6,:E6],:E5]#57
b[113]=[[:G2,:C3,:E3],:G3]
type[114]=0
a[114]=[[:G5,:B5,:D6],:F5]
b[114]=[[:G2,:B2,:D3],:G3]

type[115]=0
a[115]=[[:E5,:G5,:C6],:C5]#58
b[115]=[[:C3,:E3,:G3],:C4]
type[116]=5
a[116]=a[115]
b[116]=[[:E3,:G3,:C4],:E4]
b1[116]=b[115]

type[117]=0
a[117]=[[:G5,:C6,:E6],:E5]#59
b[117]=[[:G2,:C3,:E3],:G3]
type[118]=5
a[118]=a[117]
b[118]=[[:C3,:E3,:G3],:C4]
b1[118]=b[117]

type[119]=0
a[119]=[[:C5,:E6,:G6],:G4]#60
b[119]=[[:E2,:G2,:C3],:E3]
type[120]=5
a[120]=a[119]
b[120]=[[:G2,:C3,:E3],:G3]
b1[120]=b[119]

type[121]=0
a[121]=[[:E5,:G5,:C6],:C5]#61
b[121]=[[:C2,:E2,:G2],:C3]
type[122]=0
a[122]=a[121]
b[122]=b[121]

type[123]=6
a[123]=[:E5,:G5,:C6]#62
b[123]=[:C2,:E2,:G2]

n1=1  #1
n2=123  #123

# 左手
in_thread do
  #stop #コメントを解除すると左手だけとなる
  with_fx :reverb do
    for i in n1..n2 do
      puts "######## #{i} ############ #{i}"
      if type[i]==2  # 左右2小節目の最後の四分音符のタイのとき
        play a[i],release:2,amp:0.8,decay:1,pan: panR
        sleep 2.5 ##
      elsif type[i]==3 ||type[i]==4 # 3拍目と4拍目が異なるとき
        4.times do
          play_pattern_timed a[i],0.125,amp:0.8,pan: panR
        end
        4.times do
          play_pattern_timed a1[i],0.125,amp:0.8,pan: panR
        end
      elsif type[i]==6
        play a[i],decay:2,release:3,amp:0.8,pan: panR,amp:2
        sleep 4
      else # type==0のとき
        8.times do
          play_pattern_timed a[i],0.125,amp:0.8,pan: panR
        end
      end
      #  else
      #  end
    end
  end
end

# 右手
in_thread do
  #stop #コメントを解除すると右手だけとなる
  with_fx :reverb do
    for i in n1..n2 do
      if type[i]==1 then # 左の先頭が特殊
        play_pattern_timed b1[i],0.125,amp:0.6,pan: panL
        7.times do
          play_pattern_timed b[i],0.125,amp:0.6,pan: panL
        end
      elsif type[i]==2 # 左右2小節目の最後の四分音符がタイのとき
        play b[i],release:2,amp:1,decay:1,pan: panL
        sleep 2.5 ##
      elsif type[i]==3 ||type[i]==5 # 3拍目と4拍目が異なるとき
        4.times do
          play_pattern_timed b[i],0.125,amp:0.6,pan: panL
        end
        4.times do
          play_pattern_timed b1[i],0.125,amp:0.6,pan: panL
        end
      elsif type[i]==6
        play b[i],decay:2,release:3,amp:0.6,pan: panL, amp:2
        sleep 4
      else # type==0のとき
        8.times do
          play_pattern_timed b[i],0.125,amp:0.6,pan: panL
        end
      end
    end
  end
end










Prof. Dr. Hiroshi Tachibana

戻る