Трекинг ритма

В прошлом месяце в этой серии мы углубились в систему рандомизации, на которой базируется Sonic Pi. Мы исследовали, как мы можем использовать это для детерминированного добавления новых уровней динамического контроля над нашим кодом. В этом месяце мы продолжим наше техническое погружение и обратим внимание на уникальную систему тиков Sonic Pi. К концу этой статьи вы пройдете через ритмы и риффы на пути к тому, чтобы стать лайвкодером.

Счетчик тактов

При создании музыки мы часто хотим делать разные вещи с учетом текущего такта. Sonic Pi имеет специальную систему подсчета тактов, которая называется tick, чтобы дать вам контроль над тем, какой в точности сейчас такт, и даже поддерживает работу нескольких тактов одновременно с их собственными темпами.

Давайте поиграем - чтобы сдвинуть такт во времени, нам просто нужно вызвать tick. Откройте свободный буфер, введите следующий текст и нажмите Выполнить:

puts tick #=> 0

Это вернет нам текущий такт: 0. Обратите внимание, что даже если вы нажмете кнопку Выполнить несколько раз, вам всегда вернется 0. Это связано с тем, что каждый цикл начинает новый отсчет тактов с 0. Однако, пока цикл все еще активен, мы можем сдвигать такт во времени столько раз, сколько захотим:

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

Всякий раз, когда вы видите символ # => в конце строки кода, это означает, что эта строка будет записывать в журнал текст, расположенный справа от этого символа. Например, put foo # => 0 означает, что код puts foo, напечатает 0 в журнале.

Проверка такта

Мы видели, что tick делает две вещи. Он увеличивает (+1) и возвращает нам значение текущего такта. Иногда мы просто хотим посмотреть текущий такт, не увеличивая его. Мы можем сделать это с помощью look:

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

В этом коде мы делаем два хода такта во времени, а затем дважды вызываем look. В журнале мы увидим следующие значения: 0, 1, 1, 1. Первые два tick вернули 0 и 1, как и ожидалось, затем два look просто дважды вернули значение последнего такта, которое было равно 1.

Кольцевые списки

Теперь мы можем сдвигать такт во времени с помощью tick и узнавать его текущее значение с помощью look. Что дальше? Нам пригодится кое-что еще. Sonic Pi использует кольца, чтобы представлять через них рифы, мелодии и ритмы, а система тиков была специально разработана для тесного взаимодействия с ними. На самом деле у колец есть собственная версия такой системы, это tick с добавленной точкой. Он делает две вещи: во-первых, он действует как обычный tick и увеличивает значение такта. Во-вторых, он ищет значение кольца, используя такт в качестве индекса. Давайте взглянем:

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

.tick - это специальная версия tick с точкой, которая будет возвращать первое значение кольца : 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. Обратите внимание, что look возвращает 3. Вызовы .tick действуют так же, как и вызовы привычного tick - они увеличивают локальный такт во времени.

Арпеджиатор живого цикла

Настоящая мощь проявляется, когда вы смешиваете tick с кольцами и live_loop. В совокупности у нас есть все инструменты, необходимые для создания простого арпеджиатора. Нам нужно всего четыре вещи:

  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

Давайте посмотрим на каждую из этих строк. Сначала мы определяем кольцо нот, которые мы будем играть. Затем мы создаем live_loop с именем: arp, который обеспечит нам цикл. Каждый раз проходя цикл live_loop, мы устанавливаем наш синтезатор в: dpulse, а затем проигрываем следующую ноту в нашем кольце, используя .tick. Помните, что это увеличивает наш счетчик тактов и использует последнее значение тактов в качестве индекса в нашем кольце из нот. Наконец, мы ждем восьмой такт, прежде чем снова начать цикл.

Работа нескольких тактов одновременно

Очень важно знать, что tick связан с live_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 заключается в том, что люди используют сразу несколько счетчиков наименованных тактов для несколько колец в одном и том же live_loop:

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 имеет свой собственный независимый счетчик ударов, мы вызываем .tick дважды в одном и том же live_loop. Это означает, что такт будет увеличиваться дважды на каждый шаг времени. Это может привести к некоторым интересным полиритмам, но часто это не то, что вы хотите. Есть два решения этой проблемы. Один из вариантов - вручную вызвать tick в начале live_loop, а затем использовать .look для поиска текущего такта в каждом live_loop. Второе решение заключается в передаче уникального имени каждому вызову .tick, например, .tick (: foo) . 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