ビートを追跡する

このシリーズでは先月、Sonic Piを支えるランダム化のシステムについて技術的に詳しく見ました。そして、コードを動的に制御する新しい基準を、どのように決定論的に追加できるか探索しました。今月は、引続きSonic Piのユニークなチック(tick)システムに焦点を当て、技術的に詳しく見てみたいと思います。この記事の終わりまでに、あなた自身のやり方で、ライブコーディングDJに必要なリズムやリフのチックができるようになるでしょう。

ビートをカウントする

音楽を作るときに、何ビート目であるかによって何か異なることをしたいことがよくあるでしょう。Sonic Piには、tickと呼ばれるビートをカウントする特別なシステムがあって、ビートが実際にいつ起こるかを正確に制御でき、またそれぞれ独自のテンポを持った複数のビートにも対応しています。

早速遊んでみましょう。ビートを進めるのに必要なことは、単にtickを呼ぶだけです。新しいBufferを開いて、次のコードを入力してRunを叩いてみてください:

puts tick #=> 0

これは現在のビートの0を返すでしょう。Runボタンを数回押しているにも関わらず、これが常に0を返すことに注意してください。これは、それぞれの実行で新しいビートのカウントが0から開始するためです。しかし、実行がアクティブのままであれば、ビートを好きなだけ進めることができます:

puts tick #=> 0
puts tick #=> 1
puts tick #=> 2

コードの行の末尾に#=>シンボルがあるときは、そのコードが右側のテキストをログ出力することを意味しています。例えば、puts foo #=> 0puts fooがプログラムのその場所で0をログ出力することを意味します。

ビートを確認する

ここまでで、tickが2つのことをしているのを見てきました。それは、ビートを増やし(1を加算し)、ビートの値を返しています。場合によっては、ビートを増やさずにただ値を見たいことがあるかもしれませんが、それはlookで実現できます:

puts tick #=> 0
puts tick #=> 1
puts look #=> 1
puts look #=> 1

このコードではtickでビートを2回増加させ、その後lookを2回呼んでいます。実行すると、ログに0, 1, 1, 1の値が表示されるでしょう。最初の2つのtick01を返し、次の2つのlookはビートの最新の値である1を単純に返しています。

リング

tickでビートを進め、lookでビートを確認できるようになりました。次は何でしょう? tickで何かを進める必要がありそうですね。Sonic Piはリフやメロディーやリズムを表すのにリングを使っていて、tickシステムはこれと密接に連携するよう設計されています。実際に、リングは.の付いたtickの独自のバージョンを持っていて、それは2つのことをします。最初に、それは通常のtickと同じようにビートを増加させます。次に、ビートをインデックスとして使用して、リングの値にアクセスします。次を見てみましょう:

puts (ring :a, :b, :c).tick #=> :a

.ticktick.付きの特別なバージョンで、これはリングの最初の値である:aを返します。次のように、.tickを複数回呼ぶことで、リングの値をそれぞれ掴むことができます:

puts (ring :a, :b, :c).tick #=> :a
puts (ring :a, :b, :c).tick #=> :b
puts (ring :a, :b, :c).tick #=> :c
puts (ring :a, :b, :c).tick #=> :a
puts look                   #=> 3

ログを見ると、:a, :b, :cが表示され、その後再び:aが表示されているでしょう。look3を返しているのに注目してください。.tickの呼び出しは、tickの通常の呼び出しとちょうど似た振る舞いをしていますが、それは独自のビートを増加させているのです。

ライブループ・アルペジエーター

‘tick’は、リングとlive_loopと組み合わせることによって、本当の力が発揮されます。それらを組み合せると、シンプルなアルペジエーターを構築して理解するために必要な全ての道具を手に入れたことになります。必要なものは、次の4つです:

  1. ループしたい音符を保持するリング
  2. ビートを増加したり保持したりする手段
  3. ビートに応じて音符を演奏する機能
  4. アルペジエーターを繰り返し続けるループ構造

これらの概念のすべてを、次のコードで見つけることができます:

notes = (ring 57, 62, 55, 59, 64)
live_loop :arp do
  use_synth :dpulse
  play notes.tick, release: 0.2
  sleep 0.125
end

各行を順に見ていきましょう。最初に、繰り返し演奏される音符のリングを定義しています。次に、:arpと名付けられたlive_loopを作ってループさせています。live_loopを繰り返す度に、シンセを:dpulseに設定し、.tickと使ってリング内の次の音符を演奏しています。これにより、ビートのカウンタを増加させ、最新のビートの値を音符のリングのインデックスとして使っている点に注意してください。最後に、1/8拍待ってループしています。

複数の同時ビート

本当に知っておいて欲しい大切なことは、ticklive_loopでローカルなことです。これは、それぞれのlive_loopがそれ自身の独立したビートのカウンタを持っていることを意味します。これは、グローバルなメトロノームとビートよりもはるかに強力です。実際に動いているところを見てみましょう:

notes = (ring 57, 62, 55, 59, 64)
with_fx :reverb do
  live_loop :arp do
    use_synth :dpulse
    play notes.tick + 12, release: 0.1
    sleep 0.125
  end
end
live_loop :arp2 do
  use_synth :dsaw
  play notes.tick - 12, release: 0.2
  sleep 0.75
end

ビートを壊す

Sonic Piのtickシステムに関する混乱の大きな原因は、live_loopに複数のリングでtickをしようとする際に生じるものです:

use_bpm 300
use_synth :blade
live_loop :foo do
  play (ring :e1, :e2, :e3).tick
  play (scale :e3, :minor_pentatonic).tick
  sleep 1
end

live_loopには独自のビートのカウンタがありますが、ここでは同じlive_loop内で.tickを2回呼び出しています。これは、ループする毎にビートが2回増加されることを意味しています。これは何か面白いポリリズムを生み出すことができるかもしれませんが、多くの場合あなたが望むものではないでしょう。この問題には2つの解決策があります。1つめは、live_loopの開始時に手動でtickを呼び出し、.lookを使って各live_loopの現在のビートを確認することです。2つめは、.tick(:foo)のように、.tickの呼び出しにユニークな名前を渡すことです。Sonic Piは、名前付きチック毎に別々のビートのカウンタを作成し、追跡します。そうすれば、必要なだけ多くのビートで作業できます! 詳細については、チュートリアルの9.4の名前付きチックに関するセクションを参照してください。

まとめ

tick, ring, live_loopの知識を使って、最後に楽しい例を紹介しましょう。いつものように、これを完成された曲として扱わないようにしてください。これで遊びながら色々と変更して、どこまで変えることができるか見てみてください。ではまた次回お会いしましょう…

use_bpm 240
notes = (scale :e3, :minor_pentatonic).shuffle
live_loop :foo do
  use_synth :blade
  with_fx :reverb, reps: 8, room: 1 do
    tick
    co = (line 70, 130, steps: 32).tick(:cutoff)
    play (octs :e3, 3).look, cutoff: co, amp: 2
    play notes.look, amp: 4
    sleep 1
  end
end
live_loop :bar do
  tick
  sample :bd_ada if (spread 1, 4).look
  use_synth :tb303
  co = (line 70, 130, steps: 16).look
  r = (line 0.1, 0.5, steps: 64).mirror.look
  play notes.look, release: r, cutoff: co
  sleep 0.5
end