それでは、強烈なベースラインとかっこいいビートを作った場合、どのようにしてそれらを同時に鳴らしたらいいでしょう? 1つの回答としては、手動でそれらを同時に鳴らす事です ― まず、いくつかのベースを演奏し、その後にいくつかのドラム、またその後にベースというように…しかしながら、すぐに沢山の楽器を処理することが難しいことに気づくでしょう。
もし、Sonic Piが自動的にそれらを作り出せるとしたらどうでしょう? thread(スレッド)と呼ばれる特別な命令によってそれが可能になります。
例を単純にするために、以下のコードを強烈なベースラインとかっこいいビートだと思ってください。
loop do
sample :drum_heavy_kick
sleep 1
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
end
ループはプログラムのブラックホールのようだと以前にお話しました。一度ループを入れると、stopボタンを押さない限り、そこから抜け出せなくなります。では、どうしたら同時にふたつの繰り返しを演奏することが出来るでしょう? 私たちは、同時にそれらのコードをタイミングを合わせスタートさせるようにSonic Piに伝えなくてはいけません。これがスレッドを使った解決方法なのです。
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
はじめのdo/endブロックをin_thread
で囲むことで、次にくるdo/endブロックをぴったりと同時にループさせるようにSonic Piに命令することができます。それではドラムとベースラインを同時に鳴らすことに挑戦してみましょう!
そして、もう1つの音を追加したいので、先ほどのように繰り返しを入れてみましょう。
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
loop do
use_synth :zawa
play 52, release: 2.5, phase: 2, amp: 0.5
sleep 2
end
前と同じ問題が出てきましたね。in_thread
によって最初の繰り返しと2つ目の繰り返しが同時に演奏されています。しかし3番目の繰り返しが演奏されません。ですので以下のように、もう1つのスレッドが必要となります。
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
驚くべきことにRun
ボタンを押すということは、実際にはコードを実行するための新しいスレッドを作っていることになります。そのために複数回Run
ボタンを押すことは、互いの上に音を階層化することになります。Run
それ自体がスレッドであるために、音を自動的に紡ぎ合わせることになるのです。
Sonic Piをマスターしようとするとき、スレッドが、音楽のために最も重要な構成要素であることに気がつくでしょう。スレッドの重要な役割の1つとして、他のスレッドから現在の設定を分離することがあります。どういうことかというと、例えばuse_synth
を使ってシンセの種類を変更する時、現在のスレッド中にあるシンセだけを変更します。他のどのスレッドも変更しません。そのことを確認してみましょう。
play 50
sleep 1
in_thread do
use_synth :tb303
play 50
end
sleep 1
play 50
真ん中の音だけがほかのものと違うことに注目してみましょう。use_synth
の宣言はスレッドの中だけに影響し、スレッドの外にあるものには影響しません。
in_thread
を使って新しいスレッドを作ると、新しいスレッドには現在のスレッドの全ての設定が自動的に継承されます。ではその機能を見てみましょう。
use_synth :tb303
play 50
sleep 1
in_thread do
play 55
end
2番目の音符は、それが別のスレッドから再生されたにもかかわらず:tb303
シンセで演奏されることに注目してください。use_*
関数を使ったいかなる設定も同様に作用するでしょう。
スレッドが新規に作成されると、元のスレッドからすべての設定を継承しますが、スレッド作成以降の変更を共有することはありません。
最後に、スレッドに名前つける機能を覚えましょう。
in_thread(name: :bass) do
loop do
use_synth :prophet
play chord(:e2, :m7).choose, release: 0.6
sleep 0.5
end
end
in_thread(name: :drums) do
loop do
sample :elec_snare
sleep 1
end
end
このコードを実行した際、ログ画面を見てみましょう。ログの中にスレッドの名前が表示されることを確認できましたか?
[Run 36, Time 4.0, Thread :bass]
|- synth :prophet, {release: 0.6, note: 47}
名前付きのスレッドについて知っておくべき最後のひとつは、ある名前の付いたスレッドは同時に1つだけ実行されることです。では以下を見てみましょう。次のコードを考えてみてください。
in_thread do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Bufferに上のコードを貼り付けて、Run
ボタンを押します。数回押してみましょう。複数のアーメン・ブレイクが不協和音として反復されるでしょう。もういいですよね。Stop
ボタンを押しましょう。
この動作はこれまで何度も見てきました。Runボタンを押すと、既に鳴っているサウンドのレイヤーの一番上にサウンドを追加します。このためループが含まれている場合、Runボタンを3回押すと、3つのレイヤーが一斉に再生されます。
ただし、名前付きのスレッドでそれは異なります。
in_thread(name: :amen) do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
このコードでRunボタン複数回、押してみてください。ひとつのアーメン・ブレイクのループのみが聞こえるでしょう。そして下記のテキストがログ画面に表示されます。
==> Skipping thread creation: thread with name :amen already exists.
Sonic Pi は、:amen
という名前があるスレッドが既に存在するため、別のものを作成しませんと伝えています。
この動作はすぐに使う必要性はないように思えますが、ライブコーディングを始めると、非常に便利なものになるでしょう。