はじめに
当方、子ども向けのプログラミング教室を運営しているものですが、近くの中学生に「プログラムで演奏できないの」と聞かれました。
きらきらした目で聞かれたので、試してみることにしました。
SonicPi
手軽そうで、無償利用可能。久しぶりに Ruby を触ってみようか。
ということで、SonicPi を触ることにしました。
心配なところ
以前に Scratch3 で 「強風オールバックみたいなの」、「BlingBangBangBornみたいなの」を演奏させてみたことがあるのですが、次の点で苦労しています。
(1) 1音ごとに入れるためコードが大量になる
(2) 和声の演奏(同時に鳴らす)ときの小節のずれ
大量コードは 曲が長くなればしょうがないことなのですが、小節のずれがあると曲として成立しなくなるので、SonicPiでうまく回避できるか心配です。回避方法を試してみましょう。
入力に利用した楽譜
「Art Studio まほろば」さんサイトより
https://score.logical-arts.jp/item/203/
今回の楽譜では、ヴォーカル部、伴奏ピアノ高音部、伴奏ピアノ低音部があるものです。
SonicPi コードの要点
BPM
use_bpm 74
楽譜にある テンポ 74 は上記で決めることができます。
楽譜にあるテンポの指示は、四分音符が1分間に74個ですので、bpm = 74 となるように設定します。
( bpm はテンポのひとつの表現方法のひとつです。2024/12/6 修正)
SonicPi : 同期(sync)
同期をとるための live_loop を次のように作っておきます。
live_loop :metro do
sleep 4
end
1小節に4つの四分音符の構成の曲なので、sleep 4 です。
なお、sleep は 停止する秒数ではなく、停止する『拍数』であることに注意しましょう。
use_bpm 74 のテンポのときは、1分間に 74拍あるので、sleep 4 は、(60.0 / 74) × 4 の秒数分停止することになります。
SonicPi : live_loop
ヴォーカル部、伴奏ピアノ高音部、伴奏ピアノ低音部の3個に対応した live_loop
を作ることにします。
############################################
# ヴォーカル部
############################################
live_loop :vocal, sync: :metro do
# ここでヴォーカル部-1小節分の音符を鳴らす
end
sync :metro により、live_loop :metro と同期をとり実行されまる。
これで1小節づつの開始がそろうはず。
############################################
# piano 高音部
############################################
live_loop :p1, sync: :metro do
# ここで伴奏ピアノ高音部-1小節分の音符を鳴らす
end
############################################
# piano 低音部
############################################
live_loop :p2, sync: :metro do
# ここで伴奏ピアノ低音部-1小節分の音符を鳴らす
end
音の記述
だらだらと1曲全体をかくと訳がわからなくなるので、1小節ずつを定義したいと思います。
こんな感じ。
define :v000 do
play :e4, amp:1, attack: 0, attack_level: 1.0, sustain: 0.1, sustain_level: 0.5, release: 0
sleep 1
play :e4, amp:0.3, attack: 0, attack_level: 1.0, sustain: 0.1, sustain_level: 0.5, release: 0
sleep 1
play :e4, amp:0.3, attack: 0, attack_level: 1.0, sustain: 0.1, sustain_level: 0.5, release: 0
sleep 1
play :e4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
play :g4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
end
amp
音の大きさ。強調したくない音は amp:0.3 ぐらいで。
attack
音が立ち上がるときの長さ。ここでは基本的に attack : 0 として すぐに音が立ち上がるように意識している。
sustain
立ち上がった音が続く長さ。基本的に音符の長さ(拍数)とした。
release
音が減衰していく長さ。ここでは基本的に release : 0 として すぐに音が切れるように意識している。
定義した小節を鳴らす方法
上の例では define :v000
と名前をつけていますが、v001
, v002
といった感じで小節番号に対応した名前をつけることにします(小節ごとに音を定義する)。このとき、live_loopの繰り返しごとに 番号をつけた define を実行すればよいわけです。
番号を変数で用意しておき +1 しながら 小節の定義名を作りだすことができそうです。
名前を決めることができたら send
で該当する小節の定義を呼び出すことにします。
v_counter = 0
live_loop :vocal, sync: :metro do
v_name = toName("v", v_counter)
send v_name # v_name に入っている名前の定義を呼び出す。
v_counter += 1
end
ここで、toName メソッドは次のような感じで定義しておく
def toName(prefx, count)
"#{prefx}#{sprintf('%03d', count)}"
end
実際には 諸事情あって 上記メソッドは少しだけ複雑になりましたが、構想的には上記の感じです。
演奏プログラムのデバッグ
これはひたすら聴くしかないのでがんばりましょう。曲が長いとそれだけデバッグには時間がかかります。
そのため、デバッグ用には Temp (use_bpm)を速くしておくとよいですね。
よく間違える点
sleep の合計 = 4.0 でないと、曲進行中に音がずれていきます。細かい音符の小節のときは 特に注意すること!。
1つの小節の最後の音符の後ろには 必ず sleep をつけて 小節の長さを確保しましょう。
define :p2_007 do
play [:b2,:e2], attack: 0, attack_level: 0.5, sustain: 1.0, sustain_level: 0.2, release: 0
sleep 1.0
sleep 1.0
play [:b1,:e2,:g2], attack: 0, attack_level: 0.5, sustain: 1.0, sustain_level: 0.2, release: 0
sleep 1.0
play [:b1,:fs2,:a2], attack: 0, attack_level: 0.5, sustain: 1.0, sustain_level: 0.2, release: 0
sleep 1.0
end
上記の例では、sleep 1 が2行続くところがありますが、これは休符(四分休符)がある例です。
3連符
sleep 1.0/3 として 調整しましょう。 sustain は 0.3 で良い感じ。
define :v007 do
play :a4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
play :g4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
play :g4, attack: 0, attack_level: 1.0, sustain: 0.3, sustain_level: 0.5, release: 0
sleep 1.0/3
play :fs4, attack: 0, attack_level: 1.0, sustain: 0.3, sustain_level: 0.5, release: 0
sleep 1.0/3
play :e4, attack: 0, attack_level: 1.0, sustain: 0.3, sustain_level: 0.5, release: 0
sleep 1.0/3
play :b4, attack: 0, attack_level: 1.0, sustain: 1.5, sustain_level: 0.5, release: 0
sleep 1.5
play :ds4, attack: 0, attack_level: 1.5, sustain: 0.5, sustain_level: 0.5, release: 0, amp: 1.5
sleep 0.5
end
アウフタクト
4拍目から始まるとき、1拍目~3拍目の音はないのですが、1つの小節として考えると小節の長さは4拍分を確保しておかないといけません。
define :v000 do
sleep 1
sleep 1
sleep 1
play :e4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
play :g4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
end
実際のコードでは、1拍目~3拍目に 意図的に小さな音を鳴らして拍子をとっています。
これは、「カラオケ」的にしたかったためです。
「演奏」を聴いて楽しみたい!というだけであれば、sleep 1 × 3 で十分です。
曲のキーを変更する
use_transpose -1
上の例では、キーを 1つ下げます。
今回の「ニーナ」の実装では使用していませんが、カラオケとして利用するときは、歌い手さんのキーにあわせることができそうですね。
Github
イタリアの曲で「ニーナ」を作りこんだ。28小節程度の短い曲だが、それなりにコード量(音符量)が多く、それなりに面倒くさく単調な作業が続く。試す気がある方にはもっと短い曲をおすすめする。
ソース例はここ ==> Github
動画
演奏している様子を動画にしてアップしている
動画はここ ==> Youtube
感想
当方は、子ども向けプログラミング教室を運営しているものですが、『SonicPi』は教材としては面白そうだと感じました。課題を10~20程度作って、曲を作りながらプログラミングを学習できそうです。
【特徴】
- Ruby でコードプログラミングを体験できる
- 始めるときのハードルはそんなに高くない
- 簡単に音を鳴らすことができる
- 曲を演奏できる
- いろんな音を選べる
- 音に効果をつけられる
- それっぽく自作曲を作ることができる
【対象】
音楽に興味がある「生徒さん」が対象になります。興味がないと食いつきが悪いかもしれません。
SonicPi を使った教材集(課題集)を用意していきたいと思います。みんなにプログラミングを楽しんでもらいたいです。
追伸
『曲のキーを変更』することができると書きましたが、live_loop のなかで宣言すると、宣言したlive_loopの中だけがキーが変わります。あとでオクターブをあげたり下げたりしたくなったときに便利です。
こんな感じで書きます
############################################
# ヴォーカル部
############################################
v_counter = Start_bar_no
live_loop :vocal, sync: :metro do
use_synth :piano
#################################
# ヴォーカルだけ 1オクターブあげる
#################################
use_transpose +12 # <----- 12音で1オクターブ( -12 : マイナスのときは 1オクターブ下がる )
v_name = toName("v", v_counter)
if v_name == "" then
stop # live_loop 停止
else
send v_name # <--- ここで v_nameにある名前により defineで定義した演奏を実行します。
end
v_counter += 1
end
define :v027 do
play :e4, attack: 0, attack_level: 1.0, sustain: 2.0, sustain_level: 0.5, release: 0
sleep 2.0
sleep 1.0
play :e4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
play :g4, attack: 0, attack_level: 1.0, sustain: 0.5, sustain_level: 0.5, release: 0
sleep 0.5
end