【SonicPi】楽譜をもとにして演奏してみた

# はじめに

当方、子ども向けのプログラミング教室を運営しているものですが、近くの中学生に「プログラムで演奏できないの」と聞かれました。

きらきらした目で聞かれたので、試してみることにしました。

# SonicPi

手軽そうで、無償利用可能。久しぶりに Ruby を触ってみようか。
ということで、SonicPi を触ることにしました。

## 心配なところ

以前に Scratch3 で 「強風オールバックみたいなの」、「BlingBangBangBornみたいなの」を演奏させてみたことがあるのですが、次の点で苦労しています。

(1) １音ごとに入れるためコードが大量になる
(2) 和声の演奏（同時に鳴らす）ときの小節のずれ

大量コードは 曲が長くなればしょうがないことなのですが、小節のずれがあると曲として成立しなくなるので、SonicPiでうまく回避できるか心配です。回避方法を試してみましょう。

# 入力に利用した楽譜

「Art Studio まほろば」さんサイトより
https://score.logical-arts.jp/item/203/

今回の楽譜では、ヴォーカル部、伴奏ピアノ高音部、伴奏ピアノ低音部があるものです。

# SonicPi コードの要点

## BPM

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/bd7f5ac1-dff8-5e56-27a9-b0ef66f9c375.png)

```ruby
use_bpm 74
```
~~楽譜にある テンポ 74 は上記で決めることができます。~~
楽譜にあるテンポの指示は、四分音符が１分間に７４個ですので、bpm = 74 となるように設定します。
( bpm はテンポのひとつの表現方法のひとつです。2024/12/6 修正)

# SonicPi : 同期(sync)

同期をとるための live_loop を次のように作っておきます。
```ruby
live_loop :metro do
    sleep 4
end
```
１小節に４つの四分音符の構成の曲なので、sleep 4 です。
なお、sleep は 停止する秒数ではなく、停止する『拍数』であることに注意しましょう。
use_bpm 74 のテンポのときは、１分間に 74拍あるので、sleep 4 は、(60.0 / 74) × 4 の秒数分停止することになります。

# SonicPi : live_loop

ヴォーカル部、伴奏ピアノ高音部、伴奏ピアノ低音部の３個に対応した `live_loop` を作ることにします。

```ruby
############################################
# ヴォーカル部
############################################
live_loop :vocal, sync: :metro do
    # ここでヴォーカル部-１小節分の音符を鳴らす
end
```
sync :metro により、live_loop :metro と同期をとり実行されまる。
これで１小節づつの開始がそろうはず。

```ruby
############################################
# piano 高音部
############################################
live_loop :p1, sync: :metro do
    # ここで伴奏ピアノ高音部-１小節分の音符を鳴らす
end
```
```ruby
############################################
# piano 低音部
############################################
live_loop :p2, sync: :metro do
    # ここで伴奏ピアノ低音部-１小節分の音符を鳴らす
end
```

## 音の記述
だらだらと１曲全体をかくと訳がわからなくなるので、１小節ずつを定義したいと思います。
こんな感じ。

```ruby: ヴォーカル部、最初の小節の例
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` で該当する小節の定義を呼び出すことにします。

```ruby
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 メソッドは次のような感じで定義しておく

```ruby
def toName(prefx, count)
    "#{prefx}#{sprintf('%03d', count)}"
end
```
実際には 諸事情あって 上記メソッドは少しだけ複雑になりましたが、構想的には上記の感じです。

# 演奏プログラムのデバッグ
これはひたすら聴くしかないのでがんばりましょう。曲が長いとそれだけデバッグには時間がかかります。
そのため、デバッグ用には Temp (use_bpm)を速くしておくとよいですね。

## よく間違える点
sleep の合計 = 4.0 でないと、曲進行中に音がずれていきます。細かい音符の小節のときは 特に注意すること！。
１つの小節の最後の音符の後ろには 必ず sleep をつけて 小節の長さを確保しましょう。

```ruby
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 が２行続くところがありますが、これは休符（四分休符）がある例です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/07cd0221-0339-582d-503e-28323ea29316.png)

## ３連符
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/8c8b6111-8af8-5653-bf69-ee81d28eb816.png)

sleep 1.0/3 として 調整しましょう。 sustain は 0.3 で良い感じ。

```ruby
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
```


## アウフタクト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/d5c07b09-f29c-8835-bc58-4bc245dbc7b3.png)

４拍目から始まるとき、１拍目～３拍目の音はないのですが、１つの小節として考えると小節の長さは４拍分を確保しておかないといけません。

```ruby
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
```
実際のコードでは、１拍目～３拍目に 意図的に小さな音を鳴らして拍子をとっています。
これは、「カラオケ」的にしたかったためです。
「演奏」を聴いて楽しみたい！というだけであれば、sleep 1 × 3 で十分です。

## 曲のキーを変更する

```
use_transpose -1
```

上の例では、キーを １つ下げます。
今回の「ニーナ」の実装では使用していませんが、カラオケとして利用するときは、歌い手さんのキーにあわせることができそうですね。

# Github

イタリアの曲で「ニーナ」を作りこんだ。28小節程度の短い曲だが、それなりにコード量（音符量）が多く、それなりに面倒くさく単調な作業が続く。試す気がある方にはもっと短い曲をおすすめする。

ソース例はここ ==> [Github](https://github.com/amami-harhid/SonicPi_Tre_giorni_son_che_Nina/tree/main)

# 動画

演奏している様子を動画にしてアップしている

動画はここ ==> [Youtube](https://www.mirai-logic.com/ow31)

# 感想

当方は、子ども向けプログラミング教室を運営しているものですが、『SonicPi』は教材としては面白そうだと感じました。課題を１０～２０程度作って、曲を作りながらプログラミングを学習できそうです。

### 【特徴】
- Ruby でコードプログラミングを体験できる
- 始めるときのハードルはそんなに高くない
- 簡単に音を鳴らすことができる
- 曲を演奏できる
- いろんな音を選べる
- 音に効果をつけられる
- それっぽく自作曲を作ることができる

### 【対象】
音楽に興味がある「生徒さん」が対象になります。興味がないと食いつきが悪いかもしれません。

SonicPi を使った教材集（課題集）を用意していきたいと思います。みんなにプログラミングを楽しんでもらいたいです。

# 追伸

『曲のキーを変更』することができると書きましたが、live_loop のなかで宣言すると、宣言したlive_loopの中だけがキーが変わります。あとでオクターブをあげたり下げたりしたくなったときに便利です。

こんな感じで書きます

```ruby: サンプル
############################################
# ヴォーカル部
############################################
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
```

```ruby: define の例( 名前を変えて小節ごとに用意しています）
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
```