Sonic Piを触ってみた

## 概要

Live Coding Musicを行うためのアプリである[Sonic Pi][4]を試してみた。

## インストール

以下のコマンドでインストールすると、開発環境も同時にインストールされる。  
※ Mac以外は[公式HP][4]からダウンロードできる。

```sh
brew install sonic-pi
```

## 文法など

- Rubyベースなので、Rubyの関数は基本的に扱える
- Sonic Pi独自の関数もいくつか存在する
- 音量や速度に関してはSonic Pi側の関数やその引数で指定する

### defとdefine

`def`は通常のRubyの関数定義に利用する。  
`define`はSonic Pi独自の関数定義キーワードで、ライブ中に動的に変更することが可能。  
基本的には `define` の利用を推奨。

### 速度

`rate`を指定する

```ruby
# 2倍速で再生
sample :drum_heavy_kick, rate: 2
# 逆再生
sample :drum_heavy_kick, rate: -1
```

### 音量

`amp`を指定する

```ruby
sample :bd_haus, amp: 2
```

### Duration and Envelop

`attack`とか`release`とかの指定

- 公式のマニュアルの図がわかりやすい → [2.4][1]

### 音のパニング

`pan`で音を左右に振る設定ができる

```sh
# 右
sample :sn_dolf, pan: 1
# 左
sample :sn_dolf, pan: -1
```

### シンセサイザー

`use_synth`でブロック内で利用するシンセサイザーを指定できる


```ruby
# live_loop(baseline)内は`tb303` を利用して演奏する
live_loop :bassline do
  use_synth :tb303
  notes = [:e2, :e2, :g2, :b2]
  play_pattern_timed notes, [0.25, 0.25, 0.5, 0.5], release: 0.15, cutoff: 80, res: 0.9, amp: 2
  sleep 2
end

# live_loop(baseline2)内は `dsaw` を利用して演奏する
live_loop :bassline2 do
  use_synth :dsaw
  notes = [:e2, :e2, :g2, :b2]
  play_pattern_timed notes, [0.25, 0.25, 0.5, 0.5], release: 0.15, cutoff: 80, res: 0.9, amp: 2
  sleep 2
end
```

### サンプリング

`sample`を利用してデフォルト曲や外部ファイルの再生が可能

```ruby
# Sonic Piでデフォルトインストールされているスネアを再生する
sample :sn_dolf
# ローカルディレクトリのパスを直接指定して音楽ファイルを再生する
sample "~/Desktop/card.wav", amp: 30
```

利用できる拡張子は[マニュアル][2]によると以下の3つ

- wav
- aiff
- flac

他の拡張子から変換したい場合は、`ffmpeg`などを利用する必要あり。  
以下はMacのボイスメモで録音したデータ(`m4a`形式)を`wav`に変換する例

```sh
ffmpeg -i file.m4a file.wav
```

### loopとlive_loopの違い

`loop`はRuby標準のループ処理。

`live_loop`はSonic Piの組み込みループ処理。非同期で実行される。  
作曲を行う際には、複数の音を同時に鳴らしたいことが多いので、基本的に`live_loop`の利用が推奨される。

```ruby
# play 70は永遠に実行されない
loop do
  play 60
  sleep 0.5
end

loop do
  play 70
  sleep 0.5
end
```

```ruby
# play 60とplay 70がそれぞれ非同期に実行され続ける
live_loop :loop1 do
  play 60
  sleep 0.5
end

live_loop :loop2 do
  play 70
  sleep 0.5
end
```

### その他

`one_in`

引数には自然数(N)を指定する  
N分の1の確率でtrueになる。

`in_thread`

通常の同期処理を非同期化するために利用する。  
通常の `loop` の非同期化もできるが、`live_loop` が存在するので、そちらの利用を推奨

## サンプルコード

とりあえずChatGPTで出力した適当なコード

```ruby
use_bpm 170

live_loop :drums do
  sample :bd_haus, amp: 2
  sleep 0.5
  sample :sn_dolf, amp: 1.5
  sleep 0.5
  sample :drum_cymbal_closed, amp: 1
  sleep 0.25
  sample :drum_cymbal_closed, amp: 1
  sleep 0.25
end

live_loop :arpeggio do
  use_synth :blade
  play_pattern_timed chord(:e3, :minor), [0.125, 0.125, 0.25], release: 0.1, amp: 1.5
  play_pattern_timed chord(:g3, :major), [0.125, 0.125, 0.25], release: 0.1, amp: 1.5
  play_pattern_timed chord(:b3, :minor), [0.125, 0.125, 0.25], release: 0.1, amp: 1.5
  play_pattern_timed chord(:c4, :major), [0.125, 0.125, 0.25], release: 0.1, amp: 1.5
end

live_loop :melody do
  use_synth :piano
  use_transpose 0
  ##| notes = [:A1, :F, :D, :A1, :F, :D, :A1, :F, :D, :A1, :E, :D]
  notes = [:F0, :C, :B, :C, :G0, :A, :C, :C, :A, :G0, :F0]
  play_pattern_timed notes, [0.5, 0.5, 0.25, 0.5, 0.5, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25], release: 0.7, amp: 2
  sleep 2
end

live_loop :chords do
  use_synth :prophet
  chords = [chord(:e3, :minor), chord(:c3, :major), chord(:d3, :major), chord(:g3, :major)]
  play chords.tick, release: 2, amp: 1.5
  sleep 2
end
```

## まとめ

公式が提供しているIDEにコードを打ち込めば、即再生されるので、初心者でもすぐに試すことができる点は非常に良い。  
ただし、何かそれなりの曲を作ろうと思うと、音楽理論に関する知識が無いと厳しい。

とりあえず、公式の[チュートリアル][5]を斜め読みして使い方を覚えた後は、
コード譜とかを読んで打ち込むのが良いのでは無いかと思う。

[1]: https://sonic-pi.net/tutorial.html#section-2-4
[2]: https://sonic-pi.net/tutorial.html#section-3-6
[3]: https://qiita.com/inukai-masanori/items/47d39e8a6b2e5466f6e7
[4]: https://sonic-pi.net/
[5]: https://sonic-pi.net/tutorial.html