Sonic Pi でのいろいろな音の鳴らし方についてのメモ（自分用まとめ その2）

以下のまとめの続きです。

●Sonic Pi での音をシンプルに鳴らす方法の情報メモ（自分用まとめ その1） - Qiita
　https://qiita.com/youtoy/items/f82d2c350bc60a4e5816

## ファイルを利用して音を鳴らす
PC内の wavファイルを利用することもできるようです。

以下、公式から抜粋したファイルの指定方法です。

```ruby
# Raspberry Pi, Mac, Linux
sample "/Users/sam/Desktop/my-sound.wav"
# Windows
sample "C:/Users/sam/Desktop/my-sound.wav" 
```

また、上記のファイル利用の場合にも、オプションの指定が以下のようにできたりするようです。

```ruby
# Raspberry Pi, Mac, Linux
sample "/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3
# Windows
sample "C:/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3 
```

## 乱数を使う
乱数を使う方法についてです。

以下は、50 から 95 の間でランダムな数値が得られますが、毎回同じ数値が選ばれます。
乱数を使った音の再現性を考慮して、毎回同じ乱数列が生成されるようです（以下は、その乱数列の 1つ目を毎回取得）。

```ruby
play rrand(50, 95) 
```

以下のように、ループの中で何度も呼び出すと、乱数列の中から 1つずつ取得されるため、全て同じ音とはならない形です。
ただし、音を止めて再び再生した場合は、同じ音の組み合わせが選ばれていく形です。

```ruby
loop do
  play rrand(50, 95)
  sleep 0.5
end  
```

生成される乱数列を変更するには、シードの値としていろいろと異なる値を指定してやれば OK です。
例えば以下の例では、 `use_random_seed` の後の 40 という値を、別の値に変更してやる形です。

```ruby
use_random_seed 40
3.times do
  play rrand(50, 100)
  sleep 0.5
end 
```

なお、上記の `rrand(50, 100)` は 50 と 100 を含まない、その間の浮動小数点数の値が得られるようです。
これを整数にしたい場合は、以下のような指定をすれば良いようです。なお `rrand_i(20, 110)` の場合は、20 と 110 を含んだ整数が得られるようです。

```ruby
rrand_i(20, 110)
```

その他に ``rand` や `rand_i` などもあるようです。

```ruby
# 0以上、10未満の浮動小数点数
rand(10)
# 0以上、1未満の浮動小数点数
rand
# 0以上、10未満の整数
rand_i(10)
```

### 乱数のさらなる活用
上記の乱数を活用した例を、以下に記載します。

以下は、ベルの音にオプションで指定した rate の部分と、sleep で指定する時間の部分で乱数が使われています。

```ruby
loop do
  sample :perc_bell, rate: (rrand 0.125, 1.5)
  sleep rrand(0.2, 2)
end 
```

また、以下のような活用事例も掲載されていました。

```ruby
use_synth :tb303
loop do
  play 50, release: 0.1, cutoff: rrand(60, 120)
  sleep 0.125
end
```

以下の聞き比べてみると、 `cutoff: rrand(60, 120)` の部分との違いが良く分かります。

```ruby
use_synth :tb303
loop do
  play 50, release: 0.1
  sleep 0.125
end
```

#### cutoff
ここで突如登場した `cutoff` については、以下のブログ記事などをご参照ください。

●[音楽をプログラミングしよう] #06 - 音色変化であそぼう | なるーらぼ
　https://nalu-labo.amebaownd.com/posts/638054/

## その他のランダムな選択
### リスト内からランダムに選ぶ
また、 `choose([60, 65, 72]) ` といった書き方で、あらかじめリストで用意した複数の値の中から、何れかをランダムに選択する、という処理もできるようです。

```ruby
loop do
  play choose([60, 65, 72])
  sleep 1
end 
```

こちらも、上記の乱数と同様に `use_random_seed 【数値】` を一緒に使うことで、ランダムな選ばれ方の規則が変わるようです。

### サイコロ的なもの
1 から 6 までの目のサイコロを振る、というのに相当するものが、以下で実行できるようです。

```ruby
dice(6)
```

この数字を変えると、20面のサイコロといったようになり、得られる最大の値を変えることができるようです。

### 一定確率で true/false を返す
以下のような書き方で、6分1の確率で true、それ以外の場合は false を返す、といった処理もできるようです（if文で非常に有用です、と紹介されています）。

```ruby
one_in(6)
```

## 繰り返しや条件文
### 繰り返し
以下は 特定の処理の集まりを 3回繰り返す例です。

```ruby
3.times do
  play 50
  sleep 0.5
  sample :elec_blup
  sleep 0.5
  play 62
  sleep 0.25
end 
```

### if文
上で出てきた `one_in` を使った条件分岐の例です。

```ruby
loop do
  if one_in(2)
    sample :drum_heavy_kick
    sleep 0.5
  else
    sample :drum_cymbal_closed
    sleep 0.25
  end
  
end 
```

また、以下のような if文の書き方もあるようです。
以下は、最大で 4つの音が同時に鳴りますが、そのうち 3つはそれぞれ異なる確率で鳴るか鳴らないかが決まる、という動作をするようです。

```ruby
use_synth :dsaw
loop do
  play 50, amp: 0.3, release: 2
  play 53, amp: 0.3, release: 2 if one_in(2)
  play 57, amp: 0.3, release: 2 if one_in(3)
  play 60, amp: 0.3, release: 2 if one_in(4)
  sleep 1.5
end
```

### ループの同時実行（スレッド）
ループ処理の固まりを 2つ作成し、それらを同時並行で処理させる場合はスレッドを使うというやり方になるようです。

以下が、2つのループを同時並行で処理させる例です。

```ruby
in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end 
```

以下のようにすれば、3つ同時というのもできるようです。

```ruby
in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
in_thread do
  loop do
    use_synth :fm
    play 40, release: 0.2
    sleep 0.5
  end
end
loop do
  use_synth :zawa
  play 52, release: 2.5, phase: 2, amp: 0.5
  sleep 2
end 
```

#### スレッドの同期
2つのスレッドの同期、ということもできるようです。
以下の例では、 `cue :tick` と `sync :tick` があることで、1つ目のスレッドの処理（音は鳴らさず、メトロノームのような機能として 1秒ごとに `:tick` というビートメッセージを送信）が、2つ目の処理タイミングを決めるような動作をしています。

```ruby
in_thread do
  loop do
    cue :tick
    sleep 1
  end
end
in_thread do
  loop do
    sync :tick
    sample :drum_heavy_kick
  end
end 
```

## データ構造
### リング
配列を以下のようにリングという形にすることができるようです。

```ruby
# リングの作成1
(ring 52, 55, 59) 
# リングの作成2： 通常のリストから作成
[52, 55, 59].ring 
```

具体的には、以下のように扱える形になるようです。

> (ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59 

#### リングの活用
以下のように、リングを反転させたり、一部のみを取り出したり等もできるようです。

> 次のような単純なリングを作成します。 
(ring 10, 20, 30, 40, 50) 
リングを逆にしたいときにはどうしたらよいでしょう？ リングを反転させるには、チェインコマンドの.reverseを使います。 
(ring 10, 20, 30, 40, 50).reverse  #=> (ring 50, 40, 30, 20, 10) 
では次に、リングから最初の3つの値を取得するにはどうしたらよいでしょう？ 
(ring 10, 20, 30, 40, 50).take(3)  #=> (ring 10, 20, 30) 
最後に、リングをシャッフルするにはどうしたらよいでしょう？ 
(ring 10, 20, 30, 40, 50).shuffle  #=> (ring 40, 30, 10, 50, 20) 

## おわりに
今回、まとめ1 に続き記事を作りました。

そして、Sonic Pi の機能をまだまとめきれてなく、その3 の記事とか特定の機能を扱う別記事が何らかできそうな予感がします。