それでは、強烈なベースラインとかっこいいビートを作った場合、どのようにしてそれらを同時に鳴らしたらいいでしょう?一つの回答としては、手動でそれらを同時に鳴らす事です―まず、いくつかのベースを演奏し、その後にいくつかのドラム、またその後にベースというように…しかしながら、すぐに沢山の楽器を処理することが難しいことに気づくでしょう。
もし、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に命令することができます。
それではドラムとベースラインを同時に鳴らすことに挑戦してみましょう!
そして、もう一つの音を追加したいので、先ほどのように繰り返しを入れてみましょう。
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番目の繰り返しが演奏されません。ですので以下のように、もう一つのスレッドが必要となります。
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をマスターしようとするとき、スレッドが、音楽のために最も重要な構成要素であることに
気がつくでしょう。重要な役割の一つとして、他のスレッドから現在の設定セッティングを
分離することがあります。どういうことかというと、例えば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
ワークスペースに上記のスレッドを貼り付けて、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
という名前があるスレッドが既に存在するため、別のものを作成しませんと伝えています。この動作はすぐに使う必要性はないように思えますが、ライブコーディングを始めると、非常に便利なものになるでしょう。