Добро пожаловать в мир Sonic Pi. Надеюсь, что вам настолько же не терпится начать создавать безумные звуки, насколько мне не терпится показать вам, как это делается. Это будет веселое путешествие, в котором ты узнаешь много нового о музыке, синтезе, программировании и производительности программ, композиции и о много другом.
Постойте, как же я мог быть таким невоспитанным! Позвольте мне представиться - я Sam Aaron - тот самый парень, который создал Sonic Pi. Меня можно найти по имени @samaaron в Твиттере, и я был бы очень счастлив обменяться там с вами приветствиями. Вам, возможно, также было бы интересно узнать больше о моих лайв-кодинг выступлениях, где я сам пишу на Sonic Pi перед зрителями.
Если у вас появятся какие-либо мысли или идеи о том, как улучшить Sonic Pi, то, пожалуйста, передайте мне их. Обратная связь - это очень полезно. Никогда не знаешь, вдруг ваша идея может вырасти в нечто действительно большое!
Этот учебник разделён на главы, сгруппированные по категориям. Несмотря на то, что я написал его от простого к сложному, можно свободно прыгать туда-сюда как вам удобно. Если вам кажется, что здесь чего-то не хватает, обязательно дайте мне об этом знать, и я посмотрю, что можно сделать для следующей версии.
Наконец, наблюдать за чужим кодингом в режиме реального времени это отличный способ учиться. Я регулярно вещаю в прямом эфире на http://youtube.com/samaaron, так что не забывайте появляться там, чтобы поприветствовать всех и задать все свои многочисленные вопросы :-)
Что ж, давайте начнём…
Одним из самых захватывающих аспектов Sonic Pi является то, что для создания музыки, вы можете писать и изменять код здесь и сейчас. Это похоже на настоящее выступление с гитарой. Значит, при достаточной тренировке, вы сможете взять Sonic Pi с собой на сцену и выступать с ней.
Прежде, чем мы перейдем к деталям того, как Sonic Pi работает, я бы хотел поделиться с вами личным опытом того, что значит “лайв-кодинг”. Не переживайте, если вы пока чего-то из этого (или ничего) не понимаете. Просто держитесь крепче за стул и наслаждайтесь…
Для начала скопируйте следующий код в пустой буфер:
live_loop :flibble do
sample :bd_haus, rate: 1
sleep 0.5
end
Теперь нажмите кнопку Выполнить
, и вы услышите приятный быстрый барабанный бой. В любой момент нажмите кнопку Остановить
, чтобы остановить звук. Но не нажимайте её пока что… Вместо этого сделайте вот что:
Убедитесь, что барабаны по-прежнему звучат
Измените значение sleep
с 0.5
на значение побольше, например 1
.
Еще раз нажмите кнопку Выполнить
Можно заметить, что темп барабанов изменился.
И, наконец, запомните этот момент - это первый, и, наверняка, не последний ваш лайв-кодинг на Sonic Pi…
Ладно, это было довольно просто. Давайте добавим что-нибудь ещё в наш микс. Сверху от sample :bd_haus
добавьте строку sample :ambi_choir, rate: 0.3
. Ваш код должен выглядеть так:
live_loop :flibble do
sample :ambi_choir, rate: 0.3
sample :bd_haus, rate: 1
sleep 1
end
Время поиграться. Поменяйте частоту. Что происходит, когда вы используете высокие, малые, или отрицательные значения? Посмотрите, что произойдет, когда вы поменяете значение rate:
для сэмпла :ambi_choir
на незначительную величину (например до 0.29
). Что произойдет, если вы выберите очень маленькое значение для sleep
? Проверьте, получится ли заставить его играть так быстро, что ваш компьютер прекратит свою работу и выдаст ошибку из-за того, что он не справится с этим (если это всё же произошло, то просто выберите значение побольше для sleep
и снова нажмите Выполнить
).
Попробуйте закомментировать одну из строк sample
. Для этого добавьте #
в ее начало:
live_loop :flibble do
sample :ambi_choir, rate: 0.3
# sample :bd_haus, rate: 1
sleep 1
end
Обратите внимание, компьютер проигнорировал её, поэтому мы её не слышим. Это называется комментарием. В Sonic Pi мы можем использовать комментарии, чтобы убирать или добавлять штуки в микс.
Напоследок, позвольте мне оставить вам кое-что забавное, с чем можно поиграть. Возьмите код, приведенный ниже, и скопируйте его в свободный буфер. Не пытайтесь пока полностью разобраться в нем. Просто обратите внимание, что в нём два цикла - то есть две вещи играют по кругу одновременно. Теперь ваш черёд делать то, что получается у вас лучше всего - экспериментировать и развлекаться. Вот пара советов:
Попробуйте изменить синее значение rate:
, чтобы услышать, как изменится звук.
Попробуйте изменить время для sleep
и вы услышите, как оба цикла повторяются по кругу с разными темпами.
Раскомментируйте строку примера (удалите знак #
) и наслаждайтесь звуками гитары на заднем плане.
Попробуйте поменять синее значение любого из mix:
на число в промежутке от 0
(что соответствует исключению из общего микса) до 1
(полностью сочетается).
Не забывайте нажимать Выполнить
, и вы услышите изменения в следующий раз, когда петля начнётся заново. Не расстраивайтесь, если в конце музыка будет испорчена. Нажмите Остановить
, удалите код из буфера, вставьте свежую копию, и вы снова готовы к творчеству. На ошибках научиться можно быстрее всего…
Не забывайте нажимать Выполнить
, вы будете слышать изменения на каждой следующей итерации цикла. Не бойтесь ломать музыкальную композицию. Всегда можно нажать Остановить
, удалить код из буфера и вставить свежую копию. Не забывайте - процесс творчества тесно связан с совершением ошибок…
live_loop :guit do
with_fx :echo, mix: 0.3, phase: 0.25 do
sample :guit_em9, rate: 0.5
end
# sample :guit_em9, rate: -0.5
sleep 8
end
live_loop :boom do
with_fx :reverb, room: 1 do
sample :bd_boom, amp: 10, rate: 1
end
sleep 8
end
Продолжайте играть и экспериментировать до тех пор, пока вам не станет любопытно, как это на самом деле работает, и вы не начнёте думать, что ещё можно сделать. Тогда вы будете готовы к чтению оставшейся части этого учебника.
Так чего же вы ждёте…
У Sonic Pi очень простой интерфейс для кодирования музыки. Мы потратим совсем немного времени на его изучение.
A - Управление воспроизведением B - Управление редактором C - Помощь и справка D - Редактор кода E - Панель настроек F - Просмотр сообщений G - Справочная система F - Просмотр сообщений I - Cue Viewer
Эти розовые кнопки - главные элементы для запуска и остановки звука. Есть кнопка Выполнить для запуска кода из редактора, Остановить для остановки всего выполняющегося кода, Сохранить для сохранения кода в файл и Запись для создания записи того, что вы слышите в звуковой файл в формате WAV.
These orange buttons allow you to manipulate the code editor. The Size + and Size - buttons allow you to make the text bigger and smaller.
Данные синие кнопки дают вам доступ к информации и настройкам. Кнопка Информация открывает справочное окно, в котором находится информация о самом Sonic Pi - главной команде разработчиков, истории, помощниках и сообществе. Кнопка Помощь включает систему помощи (F), а кнопка Параметры включает панель настроек, где можно менять некоторые базовые параметры приложения.
Это область, в которой вы будете писать свой код и сочинять/исполнять музыку. Это простой текстовый редактор, где можно написать код, удалить его, вырезать, вставить и так далее. Представьте, что это простая версия Word или Google Docs. Редактор автоматически раскрасит слова в зависимости от их значения в коде. Поначалу это может казаться странным, но скоро вы увидите, насколько это помогает. К примеру, глядя на что-то синее ты будешь знать, что это число.
В Sonic Pi есть множество настраиваемых параметров. Доступ к ним можно получить, нажав кнопку Параметры в наборе кнопок “Помощь и справка”. Она переключит видимость панели настроек, в которой представлено множество вариантов, доступных для изменения. Примерами являются режим моно, инвертированное стерео, включение вывода детальных сообщений, ползунок громкости и выбор аудиовыхода Raspberry Pi.
Когда твой код выполняется, информация о том, что делает программа, будет выводиться в лог сообщений. По умолчанию, ты будешь видеть новое сообщение для каждого воспроизводимого звука с точным указанием времени, когда он начался. Это очень полезно для отладки кода и понимания того, что он делает.
Наконец, одна из самых важных частей интерфейса Sonic Pi - это справочная система, которую можно увидеть в нижней части окна приложения. Её можно выводить и прятать, нажимая синюю кнопку Помощь. В справочную систему входит помощь и информация обо все аспектах Sonic Pi, включая этот учебник, список доступных синтезаторов, сэмплов, эффектов, примеры и полный перечень всех функций Sonic Pi для кодирования музыки.
В области видимости можно наблюдать за воспроизводимым звуком. Вы с лёгкостью заметите, что пилообразная волна действительно напоминает пилу, а простейшие сигналы выглядят как синусоидальные волны. Вы также можете увидеть разницу между громкими и тихими звуками, глядя на размер выводимых линий. Существует три области видимости, с которыми можно повозиться - стандартная (комбинация левого и правого каналов), стерео (каждый канал обособлен) и, наконец, область видимости фигур Лиссажу, которая показывает отношения фаз левого и правого каналов, а также позволяет создавать красивые изображения при помощи звука. (https://ru.wikipedia.org/wiki/%D0%A4%D0%B8%D0%B3%D1%83%D1%80%D1%8B_%D0%9B%D0%B8%D1%81%D1%81%D0%B0%D0%B6%D1%83).
All internal and external events (called cues in Sonic Pi) are automatically logged in the Cue Viewer. For example, if you have a MIDI controller connected and press one of its buttons, you’ll see a new cue event in the Cue Viewer telling you the name of the controller and which button you pressed. Once you’ve mastered the basics of making and producing sounds, you’ll start to want to cue sounds or whole sections of sounds based on events such as these. A cue event is just an indication that something happened. For example, every time a live loop spins round, it sends a cue event out which is logged in the Cue Viewer. Also, external events such as MIDI messages from connected MIDI equipment and OSC messages from other programs or computers are also displayed in the Cue Viewer. It is also possible to directly generate cue events using the cue
function. Anything that appears in the Cue Viewer can be used to trigger something happening. This is covered in more detail in Sections 10 to 12 of this tutorial.
Sonic Pi стремится воодушевить вас изучать компьютеры и музыку через игру и экспериментирование. Самое главное, чтобы вам было весело, и тогда, прежде, чем вы это поймёте, вы случайно научитесь кодировать, сочинять и исполнять.
Коль скоро мы об этом заговорили, позвольте дать вам один совет, который я усвоил за годы занятий лайв-кодингом - ошибок нет, есть только возможности. Часто мне приходилось слышать это про джаз, но для лайв-кодинга это так же справедливо. Неважно, насколько велик ваш опыт - от полного новичка до бывалого Алго-Рейвера - вы будете запускать код с совершенно неожиданным результатом. Он может звучать безумно круто, тогда вы можете гордиться им. Однако, он также может получиться совершенно невыносимым для слуха и быть не к месту. Не важно, что так произошло. Важно, что вы сделаете с этим потом. Возьмите звук, умело обработайте его, и превратите в нечто ошеломляющее. Публика будет неистовствовать.
Когда вы только учитесь, очень хочется делать удивительные вещи уже сейчас. Но попридержите эту мысль и смотрите на нее, как на далекую цель, которую вы достигнете позже. Пока что, вместо этого думайте о самом простом, что вы можете написать, что было бы забавно и приносило бы некое удовлетворение. Каждый раз это будет небольшим шагом к тому поразительному, что есть в вашем воображении. Как только у вас появилась идея о простом шаге, попробуйте сделать его, играйте с тем, что получилось и разбирайтесь, какие новые идеи он дает вам. Вскоре у вас появится огромное количество способов повеселиться, а обучение пойдет в гору.
Но не забывайте делиться своими достижениями с другими!
Довольно вступлений. Пора экспериментировать со звуком.
В этой главе мы будем рассматривать основы запуска и управления синтами. Синт - это сокращение от синтезатор, что само по себе означает модное словечко для чего-то, что издает звук. Обычно, синты довольно сложны в использовании (особенно аналоговые, в которых много соединений проводами и модулей). Sonic Pi предоставляет такие же возможности, но очень простым и доступным способом.
Не обманывайтесь кажущейся простотой интерфейса Sonic Pi. С ним, если захочется, можно добраться до самых потаенных глубин очень сложной манипуляции звуком. Итак, придержите свои шляпы…
Посмотрите на этот код:
play 70
Отсюда всё берет свое начало. Давайте, скопируйте и вставьте его в окно кода вверху приложения (большое белое пространство под кнопкой Выполнить
). Затем, нажмите Выполнить
…
Впечатляет. Нажмите заново. Снова. И снова…
Ого, с ума сойти, уверен, вы бы могли просидеть так целый день. Но подождите, до того, как вы растворитесь в бесконечном потоке звуков, попробуйте изменить число:
play 75
Слышите разницу? Попробуйте число поменьше:
play 60
So, lower numbers make lower pitched beeps and higher numbers make higher pitched beeps. Just like on a piano, the keys at the lower part of the piano (the left hand side) play lower notes and the keys on the higher part of the piano (the right hand side) play higher notes.
play 60
Не волнуйтесь, если для вас это ничего не значит - у меня было то же самое, когда я только начинал. Сейчас важно то, что меньшие числа дают более низкие звуки, а большие числа дают более высокие звуки.
Играть одну ноту весьма забавно, но играть несколько нот сразу ещё лучше. Попробуйте:
play 72
play 75
play 79
Звучит джазово! Итак, когда вы пишете play
много раз, все ноты играют в одно и то же время. Попробуйте самостоятельно - какие числа звучат вместе хорошо? Какие звучат ужасно? Экспериментируйте, исследуйте и вы выясните это сами.
Играть ноты и аккорды весело, а как насчет мелодий? Что, если вы хотите играть одну ноту за другой, а не все вместе? Что же, это легко. Просто нужно вставить sleep
между ними:
play 72
sleep 1
play 75
sleep 1
play 79
Как мило, маленькое арпеджио. Что же значит 1
в sleep 1
? Ну, это означает продолжительность паузы. Вообще-то, это означает задержку на время одной доли такта, но, пока что будем считать, что это значит спать одну секунду. А вдруг мы захотим, чтобы наше арпеджио стало немного быстрее? Тогда надо указать значение для паузы покороче. Как насчет половины, то есть 0.5
:
play 72
sleep 0.5
play 75
sleep 0.5
play 79
Можно заметить: мелодия стала играть быстрее. Попробуйте сами поменять время и используйте разные продолжительности и ноты.
Интересно попробовать значения между нотами, например play 52.3
или play 52.63
. Совсем не нужно держаться стандартных целых чисел. Развлекайтесь и получайте удовольствие.
Для тех, кто уже немного знаком с нотной грамотой (не волнуйтесь, если вы не знаете о чём речь - для веселья она вам не нужна), может быть интересно записать мелодию, используя названия нот, такие как “До” (C) и “Фа-диез” (F#), а не числа. Sonic Pi предусмотрел это. Можно делать так:
play :C
sleep 0.5
play :D
sleep 0.5
play :E
Просто помните, что перед нотой должно стоять двоеточие :
. Тогда она станет розовой. Ещё можно указывать октаву, добавляя её номер после названия ноты:
play :C3
sleep 0.5
play :D3
sleep 0.5
play :E4
Если хотите сделать ноту на полтона выше, поставьте s
после её имени, то есть play :Fs3
. А когда нужен бемоль, обозначьте это при помощи b
, то есть play :Eb3
.
А теперь, дайте себе волю, и как следует повеселитесь, придумывая собственные мелодии.
В дополнение к возможности выбрать какую ноту играть или какой сэмпл включать, Sonic Pi предоставляет целый арсенал настроек для создания и управления звуком. Многие из этих настроек описаны в этом учебнике, и есть обширная документация по каждой из них в справочной системе. Пока что, мы познакомимся всего лишь с двумя самыми полезными: амплитуда и панорамирование. Вначале посмотрим, что же такое эти настройки на самом деле.
Sonic Pi поддерживает регулировки для своих синтезаторов. Они представляют собой элементы управления, для управления которыми вы передаёте атрибуты функции play
. Эти атрибуты изменяют и контролируют выводимый звук. У каждого синтезатора свой собственный набор регулировок для тонкой настройки звука. Но, есть общие наборы регулировок, одинаковые для разных синтезаторов, такие как amp:
, pan:
и параметры огибающей (обсуждается в другой главе).
Каждая регулировка состоит из двух частей: название регулировки (элемента управления) и её значение (деление, на которое вы хотите установить ручку регулировки). Например, может быть настройка с названием cheese:
, а ее желаемым значением будет 1
.
Настройки передаются вызовам play
после запятой ,
далее следует название, например amp:
(не забудьте двоеточие :
), а потом ее значение. Например:
play 50, cheese: 1
(Замечание: cheese:
- не настоящая настройка, мы просто используем ее для примера).
Можно передавать много настроек, разделяя их запятыми:
play 50, cheese: 1, beans: 0.5
Порядок регулировок не важен, так что следующий пример ничем не отличается:
play 50, beans: 0.5, cheese: 1
Регуляторы, о которых синтезатор не знает, попросту пропускаются (такие как cheese
и beans
- очевидно нелепые названия для настроек!)
Если вы случайно укажите одну и ту же настройку с разными значениями, то победит последнее. Например, значением beans:
будет 2
, а не 0.5
:
play 50, beans: 0.5, cheese: 3, eggs: 0.1, beans: 2
Множество вещей в Sonic Pi гибко регулируемо, потратьте немного времени на изучение того, как использовать их, и будете “настроены”! Давайте позабавимся с нашим первым регулятором - amp:
.
Амплитуда - компьютерное представление громкости звука. Высокая амплитуда даёт громкий звук, а низкая амплитуда даёт тихий звук. Так же, как Sonic Pi использует числа для обозначения нот, числами обозначается и амплитуда. При значении амплитуды 0 получается тишина (ничего не будет слышно), а амплитуда 1 - это нормальная громкость. Можно, также, увеличить амплитуду до 2, 10 или 100. Но стоит отметить, что когда общая амплитуда становится слишком высокой, то Sonic Pi включает так называемый компрессор, чтобы сжать ее и не дать звуку сделаться слишком громким для ваших ушей. Часто это может делать звук непонятным и странным. Так что постарайтесь использовать значения амплитуды в промежутке от 0 до 0.5, чтобы избегать компрессии.
Чтобы изменить амплитуду звука, можно воспользоваться настройкой amp:
. Например, передай 0.5, чтобы играть на половинной громкости:
play 60, amp: 0.5
Чтобы играть на удвоенной громкости, передай 2:
play 60, amp: 2
Регулировка amp:
изменяет тот вызов play
, с которым она идёт вместе. Поэтому в следующем примере первый вызов произойдет на половинной громкости, а второй вернется к значению по умолчанию (1):
play 60, amp: 0.5
sleep 0.5
play 65
Конечно, можно задавать разные значения amp:
для каждого вызова play
:
play 50, amp: 0.1
sleep 0.25
play 55, amp: 0.2
sleep 0.25
play 57, amp: 0.4
sleep 0.25
play 62, amp: 1
Еще одной забавной настройкой, которую стоит использовать, является pan:
. Она контролирует смещение звука в стереобазе. Смещение звука влево означает, что вы услышите его из левого динамика, а смещение вправо - что он будет выходить из правого динамика. Мы используем -1 для полного смещения влево, 0 для центра, а 1 - для полного смещения вправо в стереобазе. Безусловно, мы можем указывать любое значение в промежутке между -1 и 1 для точного позиционирования нашего звука.
Давай получим звук из левого динамика:
play 60, pan: -1
Теперь, повторим его из правого:
play 60, pan: 1
Наконец, выведем его снова по центру (позиция по умолчанию):
play 60, pan: 0
Попробуйте сами сделать что-нибудь весёлое, меняя амплитуду и панорамирование ваших звуков!
До сего момента мы, по большей части, развлекались с простыми звуками. Однако, простые тона уже начали вас утомлять. Разве это все, что Sonic Pi может предложить? Определенно, у лайвкодинга есть больше возможностей, чем просто гудение. Да, есть. И в этой главе мы познакомимся с захватывающим набором звуков, доступных в Sonic Pi.
В Sonic Pi есть ряд инструментов, называемых синтами, что есть сокращение от термина “синтезатор”. В то время, как сэмплы представляют собой предварительно записанные звуки, синты могут генерировать новые звуки в зависимости от того, как вы ими управляете (это мы изучим далее в этом учебнике). Синты Sonic Pi - очень могущественные и яркие инструменты. Играть с ними очень весело. Вначале, давайте научимся выбирать какой синтезатор мы будем использовать.
Пилообразная волна - забавный звук. Давайте попробуем его:
use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25
Попробуйте другой - prophet:
use_synth :prophet
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25
Как насчет смешивания обоих. Сначала один, а потом другой:
use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25
Now multiple sounds at the same time (by not sleeping between successive calls to play
):
use_synth :tb303
play 38
sleep 0.25
use_synth :dsaw
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25
Как вы могли заметить, команда use_synth
влияет только на следующие вызовы play
. Представьте, что это большой выключатель - новые вызовы play
будут играть только на используемом синте. На новый синт можно переключиться с помощью use_synth
.
Чтобы увидеть, какие синты есть в Sonic Pi, загляните во вкладку Synths в меню слева внизу (рядом с Fx). Там их больше 20 на выбор. Вот несколько моих любимых:
:prophet
:dsaw
:fm
:tb303
:pulse
Попробуйте попереключаться между синтами, пока ваша музыка играет. Позабавьтесь со смешиванием синтов, чтобы получать новые звуки. Еще можно использовать разные синтезаторы для разных частей музыки.
В одной из предыдущих глав мы изучали, как можно использовать команду sleep
для того, чтобы контролировать, когда начинается звук. Однако, до этого момента мы не могли настраивать продолжительность наших звуков.
В качестве простого и мощного способа управления длительностью наших звуков Sonic Pi предоставляет нам понятие ADSR амплитудной огибающей (Дальше в этой главе - ADSR). Амплитудная огибающая предлагает контроль по двум параметрам:
управление длительностью звука управление амплитудой звука
Длительность - это отрезок времени, в течении которого продолжается звук. Большая продолжительность означает, что вы слышите звук дольше. Все звуки в Sonic Pi имеют контролируемую продолжительность. Поэтому, управляя огибающей, вы управляете продолжительностью.
ADSR-огибающая задает не только длительность, но еще и позволяет тонкую настройку амплитуды сигнала. Все слышимые звуки начинаются и заканчиваются тишиной, а в промежутке находится изменяющаяся часть звука. Огибающие дают вам возможность плавно изменять и удерживать амплитуду разных частей звука. Это похоже на написание инструкции о том, в каком порядке понижать и повышать громкость гитарного усилителя. Например, вы можете попросить “начать с тишины, потом медленно повышать до полной громкости, держать её на этой отметке короткое время, а потом быстро вернуть на тихий уровень”. Sonic Pi дает возможность запрограммировать такое поведение очень точно с помощью огибающих.
Итак, как мы видели раньше, амплитуда 0 - это тишина, а амплитуда 1 - нормальная громкость.
Теперь, пришла пора взглянуть на каждую часть огибающей по порядку.
Единственная часть огибающей, установленная по умолчанию, - это время затухания. Оно обозначает продолжительность времени, за которое звук полностью исчезнет. У всех синтов затухание настроено на 1, что значит по умолчанию звук длится в течение одной доли такта (что при темпе по умолчанию в 60 составляет 1 секунду):
play 70
Ноту будет слышно одну секунду. Можете измерить сами :-) В полной, и более явной записи, то же самое будет выглядеть так:
play 70, release: 1
Заметьте, что звук получился точно таким же (длился ровно 1 секунду). Очень легко изменять длительность, изменяя значение регулировки release:
:
play 60, release: 2
Можно cделать звучание синта крайне непродолжительным, указав очень маленькое значение затухания:
play 60, release: 0.2
Длительность затухания звука называется фазой затухания (release phase) и, по умолчанию, представляет из себя линейный переход (т.e. прямую линию). Следующая диаграмма иллюстрирует такой переход:
Вертикальная линия на левом краю диаграммы показывает, что звук начинается при амплитуде 0, но сразу после этого начинает выводиться на полной громкости (это фаза атаки, которую мы рассмотрим далее). Как только достигнута максимальная амплитуда, она спадает прямой линией до нуля, занимая время, указанное для release:
. Чем продолжительнее время затухания, тем дольше будет стихать синт
Таким образом, вы можете менять длительность звучания своих звуков, изменяя время затухания. Потратьте немного времени, пробуя добавлять время затухания к собственной музыке.
По умолчанию фаза атаки равна 0 для всех синтов, что значит их амплитуда меняется от 0 до 1 мгновенно. Поэтому начальный звук синта похож на удар. Но вам может понадобиться плавно вывести звук. Этого можно добиться при помощи регулировки attack:
. Попробуйте плавно извлекать какие-нибудь звуки:
play 60, attack: 2
sleep 3
play 65, attack: 0.5
Можно пользоваться несколькими регуляторами в одно и то же время. Например, для короткой атаки и долгого затухания попробуйте:
play 60, attack: 0.7, release: 4
Эта краткая атака и длинное затухание иллюстрируются следующей диаграммой:
Конечно, можно и наоборот. Попробуйте долгую атаку и короткое затухание:
play 60, attack: 4, release: 0.7
В конце-концов, для кратких звуков можно сделать короткими и атаку, и затухание.
play 60, attack: 0.5, release: 0.5
Вдобавок, к заданию времени атаки и затухания, можно указать время задержки, чтобы управлять фазой задержки. Это отрезок времени, в течение которого звук остается на полной громкости в промежутке между фазами атаки и затухания.
play 60, attack: 0.3, sustain: 1, release: 1
Задержка полезна для важных звуков, которые вы хотели бы полностью выделить при сведении, прежде чем они перейдут в необязательную фазу затухания. Конечно же, совершенно допустимо устанавливать и attack:
и release:
в 0 и попросту использовать задержку, чтобы не иметь абсолютно никакого нарастания и затухания у звука. Но стоит заметить, что затухание 0 может давать щелчки в аудио, и часто лучше все-таки указывать очень маленькое значение, такое как 0.2.
Для дополнительного уровня контроля можно указать время спада. Это фаза огибающей, которая помещается между фазами атаки и задержки. Она задает участок времени, когда амплитуда будет падать от уровня attack_level:
до decay_level:
(если явно не установить его, то он будет совпадать с sustain_level:
). По умолчанию, уровни decay:
и attack:
установлена в 0, а уровень затухания в 1, поэтому надо указывать время спада, чтобы оно имело какой-либо эффект:
play 60, attack: 0.1, attack_level: 1, decay: 0.2, sustain_level: 0.4, sustain: 1, release: 0.5
Еще один, последний трюк, состоит в том, что хотя настройки decay_level:
изначально совпадают со значением sustain_level:
, вы можете явно присвоить им разные значения для полного контроля над огибающей. Это позволяет создавать огибающие наподобие следующей:
play 60, attack: 0.1, attack_level: 1, decay: 0.2, decay_level: 0.3, sustain: 1, sustain_level: 0.4, release: 0.5
Можно, к тому же, устанавливать decay_level:
выше, чем sustain_level:
:
play 60, attack: 0.1, attack_level: 0.1, decay: 0.2, decay_level: 1, sustain: 0.5, sustain_level: 0.8, release: 1.5
Итак, подведем итог. ADSR-огибающие в Sonic Pi состоят из следующих фаз:
Attack - атака - время, за которое амплитуда растет от 0 до attack_level
,
Decay - спад - время, когда амплитуда переходит от attack_level
до decay_level
,
Sustain - задержка - время изменения амплитуды с decay_level
на sustain_level
,
Release - затухание - время падения амплитуда с sustain_level
до 0
Важно помнить, что длительность звука - это сумма продолжительностей всех фаз. Соответственно, такой звук будет длиться 0.5 + 1 + 2 + 0.5 = 4 доли такта:
play 60, attack: 0.5, attack_level: 1, decay: 1, sustain_level: 0.4, sustain: 2, release: 0.5
Теперь пришло время поиграть с огибающими, добавляя их в свои звуки…
Другой отличный способ сочинять музыку - использовать заранее записанные звуки. В лучших традициях хип-хопа, мы называем такие записанные звуки сэмплами. То есть, если вы возьмёте микрофон, выйдете наружу и запишете мягкие звуки ударов дождя о навес, вы создадите сэмпл.
В Sonic Pi можно делать много забавных вещей с сэмплами. Помимо 90 встроенных сэмплов со свободной лицензией, программа даёт вам работать и играть с собственными. Перейдем же к делу..
Простые звуки - это только начало. Кое-что весьма весёлое - это проигрывание сэмплов. Попробуйте:
sample :ambi_lunar_land
Sonic Pi включает множество сэмплов. Их можно использовать так же, как вы используете команду play
. Чтобы проиграть несколько сэмплов и нот, просто запишите их друг под другом:
play 36
play 48
sample :ambi_lunar_land
sample :ambi_drone
Если их нужно разделить во времени, используйте команду sleep
:
sample :ambi_lunar_land
sleep 1
play 48
sleep 0.5
play 36
sample :ambi_drone
sleep 1
play 36
Обратите внимание, что Sonic Pi не ждёт, пока закончится один звук, прежде чем начать играть следующий. Команда sleep
всего лишь описывает разделение моментов, когда звуки начинаются. За счет этого их можно легко совмещать, создавая интересные эффекты наложения. Далее в этом учебнике мы рассмотрим управление длительностью звуков при помощи огибающих.
Есть два способа познакомиться с набором сэмплов, включённых в Sonic Pi. Во-первых, вы можете воспользоваться системой помощи. Щелкните Samples в левом нижнем меню, выберите желаемую категорию, и после этого вы увидите список доступных звуков.
С другой стороны, можно задействовать систему автодополнения. Просто начните набирать название группы сэмплов, например sample :ambi_
, и появится выпадающее меню с названиями сэмплов на выбор. Попробуйте такие варианты приставки:
:ambi_
:bass_
:elec_
:perc_
:guit_
:drum_
:misc_
:bd_
Попробуйте создать собственные композиции из сэмплов!
Также, как и с синтами, мы можем легко контролировать наши сэмплы при помощи параметров. Механизм передачи параметров сэмплам точно такой же. Вспомним наших друзей amp:
и pan:
.
Можно менять амплитуду сэмплов точно так же, как и синтов:
sample :ambi_lunar_land, amp: 0.5
Ещё один параметр сэмплов, доступный для использования - pan:
. Например, вот так мы бы сыграли амен-брейк в левом канале, а потом на середине проиграли бы его снова, но в правом канале:
sample :loop_amen, pan: -1
sleep 0.877
sample :loop_amen, pan: 1
Обратите внимание, что 0.877 - это половина продолжительности сэмпла в секундах.
Наконец, если вы сбросите регулировки какого-нибудь синта на настройки по умолчанию, (как это сделать при помощи use_synth_defaults
, рассмотрим далее), то сэмпл не обратит на это внимания.
Раз уж теперь мы умеем играть на разнообразных синтах и воспроизводить всевозможные сэмплы, пришло время научиться управлять ими обоими, чтобы музыка получалась ещё более уникальной и интересной. Вначале, давайте рассмотрим возможность растягивать и сжимать сэмплы.
Сэмплы - это предварительно записанные звуки в виде чисел, описывающих, как колеблется мембрана динамика, чтобы воспроизвести звук. Мембрана движется внутрь и наружу, так что числами всего лишь нужно задать насколько втянутой или выпуклой она должна быть в каждый момент времени. Для правдоподобного воспроизведения звука, обычно сэмпл хранит много тысяч чисел для каждой секунды! Sonic Pi берет список этих чисел и передаёт их с нужной скоростью, чтобы двигать мембраной динамика наружу и внутрь так, чтобы получился нужный звук. Но можно неплохо поразвлечься, меняя звук за счет изменения скорости, с которой числа идут в динамик.
Попробуем проверить это на одном из природных звуков: :ambi_choir
. Чтобы воспроизвести его с обычной скоростью, можно передавать команде sample
настройку rate:
:
sample :ambi_choir, rate: 1
Этот пример воспроизводит сэмпл с нормальной скоростью (1). Пока что ничего особенного. Однако, мы можем свободно изменить это число на что-то другое. Как насчет 0.5
:
sample :ambi_choir, rate: 0.5
Ого! Это что такое происходит? Ну, две вещи. Во-первых - сэмпл воспроизводится в два раза дольше. Во-вторых - звук стал ниже на октаву. Давайте разберём это более детально.
Сэмпл, который забавно растягивать и сжимать, - это амен-брейк. С нормальной скоростью мы можем легко себе представить его в составе трека драм-н-бейс:
sample :loop_amen
Но, задавая скорость, можно переключать и жанры. Попробуй половинное значение, чтобы получить старый-добрый хип-хоп:
sample :loop_amen, rate: 0.5
А если ускориться, то мы попадаем на территорию джангл:
sample :loop_amen, rate: 1.5
А теперь гвоздь программы - проверим, что произойдет, если мы зададим отрицательную скорость:
sample :loop_amen, rate: -1
Ничего себе! Он стал играть задом-наперёд! Попробуйте воспроизвести разные сэмплы на разных скоростях. Попробуйте очень быстрые скорости. Попробуйте несуразно медленные. Узнайте, какие интересные звуки можно создать.
Полезная мысленная аналогия сэмплам - пружина. Темп воспроизведения - это как сжатие и растягивание пружины. Если воспроизводить сэмпл со скоростью 2, то вы будете сжимать пружину до половины ее нормальной длины. Следовательно, воспроизведение сэмпла займёт половину времени, ведь он стал короче. Если играть сэмпл на половине обычной скорости, то вы растягиваете пружину в два раза. Поэтому сэмпл длится в два раза дольше, ведь он стал длиннее. Чем больше вы сдавливаете, тем короче он получается (скорость выше), а чем больше вы растягиваете, тем длиннее он становится (скорость ниже).
Сжатие пружины увеличивает ее плотность (число витков на сантиметр) - это совпадает с тем, почему сэмпл начинает звучать с высокой частотой. Растягивание пружины снижает ее плотность, и это похоже на то, как частота звука понижается.
(Эта часть приведена для тех, кому интересны детали. Всем остальным её можно пропустить…)
Как мы видели раньше, представление сэмпла - это очень длинный список чисел, которые описывают движение мембраны динамика во времени. Можно взять эту последовательность чисел и нарисовать по ней график, который будет выглядеть примерно так:
Вы могли видеть похожие картинки до этого. Они называются волновой формой сэмпла. Это просто числовой график. Обычно подобные формы включают 44100 точек с данными на каждую секунду времени (из-за теоремы сэмплирования Найквиста-Шэннона). Итак, если сэмпл длится две секунды, то форма волны будет состоять из 88200 чисел, которые мы бы передавали динамической головке со скоростью 44100 значения в секунду. Конечно, мы могли бы удвоить темп передачи, тогда воспроизведение бы заняло всего одну секунду. А еще мы могли бы проигрывать его в два раза медленнее, что означало бы 22500 точек в секунду, и весь процесс бы занял четыре секунды.
На длительность сэмпла влияет скорость воспроизведения:
Удвоение темпа уполовинивает время воспроизведения, Сокращение темпа вдвое удваивает время воспроизведения, Если задать темп, равный четверти от нормального, то время учетверится, Если скорость воспроизведения равна 1/10 от нормальной, то время воспроизведения увеличится в 10 раз.
Мы можем представить это отношение формулой:
новая_длительность_сэмпла = (1 / скорость) * длительность_сэмпла
Изменение темпа воспроизведения, к тому же, влияет на высоту сэмпла. Частота формы сигнала и высота звука определяются тем, как часто сигнал движется вверх и вниз. Наш мозг каким-то образом превращает быстрые перемещения мембраны в высокие ноты, а медленные - в низкие. Именно поэтому иногда вы можете видеть вибрации большого басового динамика, когда он издает чрезвыйчайно низкие звуки. На самом деле он перемещается намного медленнее внутрь и наружу, чем динамик, воспроизводящий высокие ноты.
Если взять форму сигнала и сжать ее, то она будет колебаться вверх и вниз большее количество раз за секунду. За счет этого звук получится более высоким. Выходит, что удвоение движений вверх-вниз (колебаний) удваивает частоту. Поэтому проигрывание сэмпла на удвоенной скорости удваивает его слышимую частоту. Точно так же половинная скорость уменьшает частоту вдвое. Другие значения скорости влияют на частоту соответствующим образом.
Также возможно изменять длительность и амплитуду сэмпла, используя ADSR-огибающие. Но это работает немного по-другому, чем ADSR-огибающие синтов. Огибающие сэмплов позволяют уменьшать громкость и длительность, но не увеличивать их. Сэмпл остановится, либо когда его воспроизведение завершено, либо когда огибающая закончилась - в зависимости от того, что произошло раньше. Так что если задать очень долгое затухание, то звучание сэмпла не удлинится.
Вернемся к нашему верному другу амен-брейку:
sample :loop_amen
Без дополнительных регулировок мы слышим полный сэмпл на полной громкости. Если мы хотим его постепенно усиливать в течение одной секунды, то можно задейстовать параметр attack:
:
sample :loop_amen, attack: 1
Для более краткого нарастания, выберите значение атаки поменьше:
sample :loop_amen, attack: 0.3
Отличие поведения ADSR-огибающей сэмпла от стандартной огибающей синта лежит в значении сустейна. В обычной огибающей синта сустейн сам по себе устанавливался в 0, если мы не указывали его вручную. Для сэмплов оно также настраивается “автомагически”, и равняется времени, необходимому для завершения сэмпла. Поэтому мы слышим полный сэмпл, когда никаких настроек не задаётся. Если бы значения атаки, спада, удержания и затухания равнялись 0, то мы бы и намёка на сэмпл не услышали. Так что Sonic Pi вычисляет сколько времени длится сэмпл, вычитает длительности атаки, спада и затухания, и присваивает результат фазе удержания. Если атака, спад и затухание вместе дают значение больше продолжительности сэмпла, то удержание устанавливается в 0.
Для изучения этого явления рассмотрим наш амен-брейк более детально. Если спросить Sonic Pi сколько длится сэмпл:
print sample_duration :loop_amen
Он напечатает 1.753310657596372
, что означает собственное время звучания сэмпла в секундах. Просто для удобства округлим его до 1.75
. Затем, если установить затухание в 0.75
, произойдет кое-что неожиданное:
sample :loop_amen, release: 0.75
Первая секунда сэмпла будет воспроизводиться на полной громкости, а потом последует постепенное затухание в течение 0.75 секунды. Это и есть пример автоудержания в действии. Само по себе затухание всегда работает с конца сэмпла. Если бы наш сэмпл длился 10.75 секунды, то первые 10 секунд он бы играл с полной амплитудой, а потом затухал оставшиеся 0.75 секунды.
Запомните: по умолчанию release:
отсчитывает затухание от конца сэмпла.
Можно использовать вместе attack:
, release:
и поведение автоудержания для постепенного усиления и затухания при воспроизведении сэмпла:
sample :loop_amen, attack: 0.75, release: 0.75
Так как полная продолжительность равняется 1.75 секунды, а наши фазы атаки и затухания суммарно дают 1.5 секунды, то удержание автоматически устанавливается в 0.25 секунды. Так мы легко можем плавно усиливать и гасить сэмпл.
Вернуться к нормальному режиму ADSR-огибающей довольно просто: достаточно вручную задать 0 для sustain:
:
sample :loop_amen, sustain: 0, release: 0.75
После этого сэмпл звучит в общей сложности всего лишь 0.75 секунды. При обычных нулевых значениях attack:
и decay:
громкость сэмпла сразу же достигает полного значения, удерживается там в течение 0 секунд, а потом за 0.75 секунды полностью затихает во время фазы затухания.
Хороший эффект от данного поведения получается, если мы хотим превратить продолжительные сэмплы в более короткие. Это даст им более отрывистое ударное звучание. Рассмотрим сэмпл :drum_cymbal_open
:
sample :drum_cymbal_open
Можно слышать, что тарелка продолжает звенеть некоторое время. С помощью огибающей можно сделать её более резкой:
sample :drum_cymbal_open, attack: 0.01, sustain: 0, release: 0.1
А еще можно изображать удар по тарелке и его глушение за счет увеличения периода удержания:
sample :drum_cymbal_open, attack: 0.01, sustain: 0.3, release: 0.1
А теперь, ступайте, и как следует позабавьтесь, добавляя огибающие к сэмплам. Попробуйте изменять и скорость, чтобы получить действительно интересные результаты.
Этот раздел станет заключительным в нашем исследовании воспроизведения сэмплов в Sonic Pi. Давайте кратко повторим уже изученное. Пока мы только разбирались в том, как включать сэмплы:
sample :loop_amen
Потом мы рассмотрели то, как мы можем менять темп сэмплов, например для воспроизведения их на половине скорости:
sample :loop_amen, rate: 0.5
Затем, мы увидели, как можно постепенно усиливать сэмпл (совместим это с уменьшённой вдвое скоростью):
sample :loop_amen, rate: 0.5, attack: 1
Еще мы узнали как сделать начало сэмпла более резким за счет задания sustain:
явного значения и установки коротких атаки и затухания:
sample :loop_amen, rate: 2, attack: 0.01, sustain: 0, release: 0.35
Однако, вам бы понравилось, если бы не надо было всякий раз начинать сэмпл с начала? Разве не здорово было бы, если бы можно было играть сэмпл не до конца?
Возможно выбрать произвольную начальную точку для сэмпла, задавая ее в качестве значения в диапазоне от 0 до 1. 0 - начало сэмпла, 1 - его конец, а 0.5 - это середина. Попробуем сыграть только вторую половину амен-брейка:
sample :loop_amen, start: 0.5
А как насчет последней четверти:
sample :loop_amen, start: 0.75
Похожим образом разрешается выбирать конечную точку сэмпла как значение между 0 и 1. Прервем амен-брейк на середине:
sample :loop_amen, finish: 0.5
Естественно, мы можем комбинировать оба произвольных фрагмента звукового файла. Как насчет выбрать небольшой участок в центре:
sample :loop_amen, start: 0.4, finish: 0.6
Что случится, если установить старт после финиша?
sample :loop_amen, start: 0.6, finish: 0.4
Круто! Он играет задом-наперед!
Можно объединить эту новую способность играть выбранные сегменты аудио с нашим знакомым rate:
. Например, таким образом воспроизведется очень маленькая секция из середины амен-брейка очень медленно:
sample :loop_amen, start: 0.5, finish: 0.7, rate: 0.2
Наконец, все это возможно соединить с известными нами ADSR-огибающими, чтобы получить интересный результат:
sample :loop_amen, start: 0.5, finish: 0.8, rate: -0.2, attack: 0.3, release: 1
Попробуйте также комбинировать сэмплы, не ограничивайте свою фантазию…
Хотя встроенные сэмплы помогут вам быстро приступить к работе, вы можете поэкспериментировать с другими записанными звуками в своей музыке. Sonic Pi полностью поддерживает эту функцию. Но сперва кратко обсудим переносимость вашего произведения.
Когда ты сочиняешь свои композиции только с использованием встроенных синтов и сэмплов, то программный код - это все что нужно для надежного исполнения твоей музыки. Просто задумайся над этим на минуту - это же просто удивительно! Простой кусок текста, который можно отправить по электронной почте или засунуть в Gist являет собой все, что нужно для воспроизведения твоих звуков. Поэтому их очень легко распространять среди твоих друзей, потому что им всего лишь нужно заполучить код.
С другой стороны, если начинать использовать собственные записанные сэмплы, то такая переносимость теряется. Это происходит из-за того, что для воспроизведения твоей музыки другим людям не только нужен твой код, но также и сэмплы. Этот факт ограничивает других в их возможностях изменять и экспериментировать с твоими работами. Конечно, знание этого не должно тебя останавливать от использования собственных сэмплов. Просто помни об этом.
Так как все-таки проиграть любой WAV, AIFF или FLAC с твоего компьютера? Все что нужно, это передать путь к его файлу команде sample
:
# Raspberry Pi, Mac, Linux
sample "/Users/sam/Desktop/my-sound.wav"
# Windows
sample "C:/Users/sam/Desktop/my-sound.wav"
Sonic Pi автоматически загрузит и воспроизведет сэмпл. Вместе с этим можно передавать все стандартные параметры, которые ты привык использовать с sample
:
# 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
Замечание: этот раздел руководства рассказывает о расширенных возможностях работы с большими директориями ваших собственных сэмплов. Рекомендуем ознакомится с ним в тех случаях, если вы загрузили или купили набор сэмплов и хотите использовать их в Sonic Pi
Вы можете смело пропустить этот раздел, если вам хватает встроенных сэмплов
Работая с большими папками внешних сэмплов, вы можете ощутить неудобства при набирании полного пути к каждому отдельному сэмплу.
Например, предположим, что на вашем компьютере у вас есть папка:
/path/to/my/samples/
Когда мы посмотрим в директорию, то увидим следующие сэмплы:
100_A#_melody1.wav
100_A#_melody2.wav
100_A#_melody3.wav
120_A#_melody4.wav
120_Bb_guit1.wav
120_Bb_piano1.wav
Как правило, для того, чтобы проиграть сэмпл пианино, мы можем использовать полный путь:
sample "/path/to/my/samples/120_Bb_piano1.wav"
Если мы хотим проиграть гитарный сэмпл, мы также можем использовать его полный путь:
sample "/path/to/my/samples/120_Bb_guit.wav"
Тем не менее, оба этих вызова требуют от нас знания имён сэмплов внутри нашей директории. Что если мы просто хотим быстро прослушать каждый сэмпл по очереди?
Если мы хотим проиграть первый сэмпл в директории, мы просто должны указать имя директории в sample
и установить индекс в значение 0
следующим образом:
sample "/path/to/my/samples/", 0
Мы также можем создать ярлык (shortcut) нашей директории, используя переменную:
samps = "/path/to/my/samples/"
sample samps, 0
Теперь, если мы хотим проиграть второй сэмпл в директории, нам нужно прибавить 1 к нашему индексу:
samps = "/path/to/my/samples/"
sample samps, 1
Заметьте, что нам больше не нужно знать имени сэмпла в директории - мы просто должны знать название директории (или иметь её ярлык). Если мы запросим индекс, больший, чем количество сэмплов в директории, порядок сэмплов в директории будет замкнут и пойдёт по следующему кругу. Таким образом, вне зависимости от номера, мы получим один из сэмплов в директории.
Обычно, индексирования достаточно, но иногда нам необходимо сортировать и организовывать сэмплы. К счастью, большинство наборов сэмплов структурированы. Давайте ещё раз взглянем на имена сэмплов в нашей директории:
100_A#_melody1.wav
100_A#_melody2.wav
100_A#_melody3.wav
120_A#_melody4.wav
120_Bb_guit1.wav
120_Bb_piano1.wav
Заметьте, что в их именах содержится некоторая информация. Во-первых, у нас есть BMP сэмпла (удары в секунду) в начале имени. Таким образом, сэмпл пианино имеет BPM равный 120, а первые три мелодии - 100 BPM. Имена сэмплов также содержат тональность. Таким образом, гитарный сэмпл имеет тон Bb а мелодии A#. Эта информация очень полезна для сведения этих сэмплов в нашем коде. Например, мы знаем, что сэмпл пианино содержит 120 BPM и тональность Bb.
Оказывается, мы можем использовать это конкретное соглашение об именах наших наборов сэмплов в коде, чтобы помочь нам отфильтровать те, которые нам нужны. Например, если мы работаем с 120 BPM, мы можем отфильтровать все образцы, содержащие строку 120
, со следующим:
samps = "/path/to/my/samples/"
sample samps, "120"
Первое совпадение будет проиграно. Если мы хотим, чтобы заиграло второе совпадение, нам нужно просто изменить индекс:
samps = "/path/to/my/samples/"
sample samps, "120", 1
Более того, мы можем использовать несколько фильтров сразу. Например, если мы хотим сэмпл, имя которого содержит подстроки “120” и “A#”, мы можем легко добиться этого следующим кодом:
samps = "/path/to/my/samples/"
sample samps, "120", "A#"
Наконец, мы по-прежнему можем добавлять свойства к вызову нашего сэмпла
:
samps = "/path/to/my/samples/"
sample samps, "120", "Bb", 1, lpf: 70, amp: 2
Система аргументов фильтров сэмплов понимает два типа информации: источники и фильтры. Источники представляют собой информацию, используемую для создания списка потенциальных совпадений. Источники бывают двух видов:
“/path/to/samples” - строка, представляющая относительный путь к директории “/path/to/samples/foo.wav” - строка, представляющая действительный путь к примеру
Функция sample
сначала собирает все источники и использует их для создания большого списка совпадений. Этот список создается, сначала добавляя все допустимые пути, а затем добавляя все допустимые файлы .flac
, .aif
, .aiff
, .wav
, .wave
, содержащиеся в каталогах.
Например, посмотрите на следующий код:
samps = "/path/to/my/samples/"
samps2 = "/path/to/my/samples2/"
path = "/path/to/my/samples3/foo.wav"
sample samps, samps2, path, 0
Например, здесь мы комбинируем сэмплы из двух каталогов и добавляем конкретный сэмпл. Если "/path/to/my/samples/"
содержит 3 сэмпла и "/path/to/my/samples2/"
содержит 12, в сумме мы получим 16 потенциальных сэмплов на индексирование и фильтрацию (3 + 12 + 1).
По умолчанию в список совпадений попадают только файлы примеров в каталоге. Иногда у вас может быть несколько вложенных папок с сэмплами, которые вы хотите искать и фильтровать внутри. Поэтому вы можете выполнить рекурсивный поиск всех образцов во всех подпапках конкретной папки, добавив **
в конец пути:
samps = "/path/to/nested/samples/**"
sample samps, 0
Обратите внимание, что поиск в очень большом наборе папок может занять много времени. Однако, содержимое всех источников папок кэшируется, поэтому задержка будет выполняться только в первый раз.
Наконец, заметьте, что источники должны идти первыми. Если не передан источник, тогда набор встроенных сэмплов будет выбран как список совпадений по умолчанию.
Как только вы получили список совпадений, вы можете использовать следующие фильтры, чтобы уменьшить выборку:
"foo"
Строки будут фильтроваться при появлении подстроки в имени файла (минус путь к каталогу и расширение).
/fo[oO]/
Регулярное выражение будет фильтровать соответствие имени файла шаблону (минус путь к каталогу и расширение).
:foo
- Ключевое слово будет фильтровать совпадения по тому, является ли ключевое слово прямым соответствием имени файла (минус путь к каталогу и расширение).
lambda{|a| ... }
- Процесс с одним аргументом будет обрабатываться как фильтр списка совпадений или функция-генератор. Он принимает текущий и должен вернуть новый список совпадений (список действительных путей к сэмплам).
1
- Числа будут выбирать совпадение с этим индексом (зацикливаться, если необходимо).
Например, мы можем отфильтровать все образцы в каталоге, содержащем строку "foo"
, и воспроизвести первый совпадающий образец на половинной скорости:
sample "/path/to/samples", "foo", rate: 0.5
См. Справку по sample
для множества подробных примеров использования. Обратите внимание, что порядок фильтров соблюдается.
Наконец, вы можете использовать списки везде, где вы можете разместить источник или фильтр. Список будет автоматически сплющиваться, и содержимое будет рассматриваться как обычные источники и фильтры. Поэтому следующие вызовы sample
семантически эквивалентны:
sample "/path/to/dir", "100", "C#"
sample ["/path/to/dir", "100", "C#"]
sample "/path/to/dir", ["100", "C#"]
sample ["/path/to/dir", ["100", ["C#"]]]
Это был расширенный раздел для людей, которым нужны дополнительные возможности для манипулирования и использования наборов сэмплов. Если большая часть этого раздела не имела особого смысла, не беспокойтесь. Скорее всего, вам пока не нужна какая-либо из этих функций. Однако, вы будете знать, когда это понадобится, и вы можете вернуться и перечитать это, когда начнете работать с большими каталогами сэмплов.
Отличный способ сделать вашу музыку несколько более интересной - это использовать случайные числа. В Sonic Pi есть замечательная функция добавления случайности в музыку, но прежде, чем мы начнем, нужно усвоить неприятную истину: в Sonic Pi случайности не являются по-настоящему случайными. Что же, спрашивается, это значит? Давайте разберёмся.
Очень полезная случайная функция называется rrand
. Она вернет случайное значение в диапазоне двух чисел - минимума и максимума (rrand
это сокращение от “ранжированный генератор случайных чисел”). Попробуем проиграть какую-нибудь случайную ноту:
play rrand(50, 95)
Ого, получился неожиданный звук. Он воспроизвел ноту 83.7527
. Прекрасная случайная нота в промежутке между 50 и 95. Постойте-ка, я только что точно предсказал случайную ноту, которая и у вас получилась? Что-то тут нечисто. Попробуем снова. Что? Он снова выбрал 83.7527
? Это явно не случайно!
Правда в том, что выбор не случаен, он псевдо-случаен. Sonic Pi выдаёт повторяющиеся псевдо-случайные числа, чтобы быть уверенным, что музыка, которую вы создаёте на своей машине, будет звучать точно так же на всех других машинах. Это очень полезное свойство, даже если вы добавляете совсем немного случайности в свои композиции.
Конечно же, в конкретном музыкальном произведении, если бы 83.7527
“случайно” выбиралась каждый раз, это было бы не очень интересно. Но все-таки этого не происходит. Попробуйте следующее:
loop do
play rrand(50, 95)
sleep 0.5
end
Ура! Наконец-то это звучит случайно. В течение одного запуска, последующие вызовы функции генератора случайных чисел будут возвращать случайные значения. Однако, следующий прогон создаст точно такую же последовательность случайных чисел и будет звучать идентично. Это как если бы код Sonic Pi всякий раз возвращался назад во времени в тот момент, когда нажимается кнопка Run. Это День Сурка для музыкального синтеза!
Прекрасной иллюстрацией случайности в действии является пример колоколов, в которые как будто вселились призраки. Он повторяет пример :perc_bell
, выбирая случайную скорость и задержку между звуками:
loop do
sample :perc_bell, rate: (rrand 0.125, 1.5)
sleep rrand(0.2, 2)
end
Еще один забавный пример рандомизации - управление частотой среза фильтра синта случайным образом. Отличный синт, на котором можно это попробовать, - это эмулятор :tb303
:
use_synth :tb303
loop do
play 50, release: 0.1, cutoff: rrand(60, 120)
sleep 0.125
end
Что, если вам не нравится последовательность случайных чисел, сгенерированная Sonic Pi? Ну, очень легко выбрать другую начальную точку, если использовать use_random_seed
.Начальная точка по умолчанию равна 0, так что для другого случайного результата выбирайте другую точку!
Сравните следующее:
5.times do
play rrand(50, 100)
sleep 0.5
end
Каждый раз, когда этот код выполняется, вы будете слышать одну и ту же последовательность из 5 нот. Чтобы получить другой порядок просто поменяйте начальную точку:
use_random_seed 40
5.times do
play rrand(50, 100)
sleep 0.5
end
В итоге получится другая последовательность из 5 нот. Изменяя начальную точку и слушая результат, можно выбрать что-тона свой вкус. Потом, когда вы поделитесь результатом с другими, они услышат в точности то же самое, что и вы.
Давайте познакомимся с некоторыми другими случайными функциями.
Очень часто приходится выбирать что-то из списка случайным образом. Например, мне бы могло захотеться проиграть одну ноту из набора: 60, 65 и 72. Я могу достичь этого с помощью функции choose
, которая позволяет мне выбрать элемент из списка. Вначале, надо добавить мои числа в список, что достигается заключением их в квадратные скобки и разделением запятыми: [60, 65, 72]
. Затем, надо просто передать их choose
:
choose([60, 65, 72])
Послушаем, как это звучит:
loop do
play choose([60, 65, 72])
sleep 1
end
Мы уже видели rrand
, но пробежимся по ней вновь. Она возвращает случайную величину в промежутке двух чисел, не включая границы. Это значит, что никогда не будет выбрано самое большое или самое маленькое значение - всегда нечто между ними. Число всегда будет дробным, то есть не целым. Примеры дробных чисел, возвращаемых rrand(20, 110)
:
87.5054931640625 86.05255126953125 61.77825927734375
Время от времени вам может понадобится получить целое случайное число, а не дробное. Тут-то и придёт на помощь rrand_i
. Она работает так же, как rrand
, но включает граничные значения (то есть она может выбирать минимальные и максимальные числа). Примеры, полученные из rrand_i(20, 110)
:
88 86 62
Вернет случайное дробное число от 0 (включительно), до максимального указанного вами. По умолчанию числа лежат в промежутке от 0 до 1. Такая функция полезна для выбора случайного усиления:
loop do
play 60, amp: rand
sleep 0.25
end
Относится к rrand_i
, как rrand_i
к rrand
. То есть она выбирает случайное целое число в диапазоне от 0 до максимального значение, которое вы укажете.
Иногда нужно изобразить бросание игральных костей - это частный случай rrand_i
, когда минимальное значение всегда 1. В вызов dice
требуется передать количество сторон кости. Стандартная игральная кость имеет 6 сторон, так что dice(6)
будет работать очень похожим образом - возвращать 1, 2, 3, 4, 5 или 6. Однако, прямо как в ролевых играх в стиле фэнтези, пользу может принести и кость с 4 сторонами, и с 12 сторонами или с 20 сторонами. Может даже потребуется кость со 120 гранями!
Наконец, может потребоваться сымитировать вероятность выпадания наибольшей из граней игральной кости, например, 6 для обычной кости. Функция one_in
возвращает истину с вероятностью один к числу сторон кости. Следовательно, для one_in(6)
шанс получить истину составит 1 к 5. В остальных 5 из 6 случаев вернётся ложь. Истинные и ложные значения очень полезны для логических выражений if
, которые мы рассмотрим в одной из следующих глав нашего учебника.
А теперь, пришла пора добавить немного неразберихи в вашу музыку за счет случайностей!
После того, как мы изучили основы создания звука при помощи play
и sample
, и сочинения простых мелодий и ритмов, расставляя задержки между ними, вам могло стать интересно, а что же ещё мир программирования может нам предложить…
Скажем так, вас ожидает захватывающее путешествие! Оказывается, что основные структуры программирования, такие как циклы, условные выражения, функции и потоки выполнения, предлагают нам очень мощные инструменты для выражения собственных музыкальных идей.
Ограничимся лишь основами…
Структура, которая будет попадаться вам в Sonic Pi особенно часто, - это блок. Блоки позволяют нам делать разные полезные вещи с большими участками кода. Например, при помощи параметров синтов и сэмплов мы могли изменять что-то, что происходило в одной строке. Однако, иногда нам нужно сделать что-то значительное, что касается множества строк кода. Например, мы можем решить играть их по кругу, добавить эффект реверберации всего к одному из пяти повторов и так далее. Рассмотрим следующий код:
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
Чтобы сделать что-то с куском кода, нам надо сказать Sonic Pi, где этот блок кода начинается, и где он заканчивается. Для его начала мы используем do
, а для обозначения конца - end
. Пример:
do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Все же он ещё не является завершённым и не будет работать (попробуйте и получите сообщение об ошибке), так как мы не сообщили Sonic Pi, что мы хотим делать с этим блоком *do/end. Этого можно добиться, если написать некий специальный код перед do
. Далее мы увидим много примеров этих специальных кусочков кода. Пока лишь важно понять, что оборачивание вашего кода в do
и end
сообщает Sonic Pi, что вы хочтите сделать что-то особенное с этим блоком.
До этого момента мы потратили немало времени, пробуя разные звуки, которые можно производить внутри блоков play
и sample
. Мы также изучили как разносить эти звуки во времени, используя sleep
.
Как мы уже смогли выяснить, даже с этими простейшими блоками кода можно долго забавляться. Однако, совершенно новое измерение веселья откроется для вас, когда вы начнёте использовать мощь блоков кода для структурирования вашей музыки. В нескольких последующих главах мы рассмотрим некоторые из этих новых инструментов. Вначале идут итерации и циклы.
Доводилось ли вам писать код, который вы бы хотели повторить несколько раз? Например, у вас могло получиться нечто подобное:
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
Что, если мы захотим повторить это три раза? Что ж, можно было бы выбрать простейший путь и попросту продублировать код трижды:
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
Этот код просто огромен! Как быть, если нам захочется поменять сэмпл на :elec_plip
? Придется найти все места с изначальным :elec_blup
и переписать их. Что ещё важнее, каким образом повторить кусок кода 50 раз или 1000? Это было бы и впрямь целая куча кода. Гигантское число строк пришлось бы изменять для каждой правки.
На самом деле сделать повторение кода должно быть не сложнее, чем сказать сделай это три раза. В общем-то, так оно и есть. Помните ли вы о нашем старом знакомом, блоке кода? Его можно использовать для отметки начала и конца кода, который необходимо повторить три раза. Мы добавим специальную конструкцию 3.times
. Так что, вместо записи делай это три раза, мы напишем 3.times do
. Это не очень сложно. Просто не забывайте указать end
в конце кода, который надо повторить:
3.times do
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
end
Ну, разве это не лучше дублирования? Много красивых структур может быть создано с использованием этой инструкции:
4.times do
play 50
sleep 0.5
end
8.times do
play 55, release: 0.2
sleep 0.25
end
4.times do
play 50
sleep 0.5
end
Еще можно поместить итерации внутрь других итераций и получить интересный рисунок. Например:
4.times do
sample :drum_heavy_kick
2.times do
sample :elec_blip2, rate: 2
sleep 0.25
end
sample :elec_snare
4.times do
sample :drum_tom_mid_soft
sleep 0.125
end
end
Если потребуется повторить что-то много раз, придётся указывать очень большие значения, такие как 1000.times do
. В этом случае, наверное, лучше попросить Sonic Pi повторять код до бесконечности (или, как минимум, до того момента, пока вы не нажмёте кнопку “Остановить”!). Давайте зациклим амен-брейк:
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
О циклах важно знать то, что они работают как чёрные дыры внутри кода. Как только исполнение кода попадает в цикл, оно не cможет покинуть его до тех пор, пока вы не остановите его. Код просто будет повторяться по кругу снова и снова вечно. Это значит, что вы никогда не услышите код, написанный после цикла. К примеру, тарелка после этого цикла никогда не прозвучит:
loop do
play 50
sleep 1
end
sample :drum_cymbal_open
Теперь, пришла пора создать интересные структуры из вашего кода при помощи итераций и циклов!
Часто, помимо игры произвольных нот (см. предыдущую главу), вы также будете хотеть принимать произвольные решения и выполнять либо одну, либо другую ветку кода, в зависимости от результата. Например, вы можете решить случайным образом сыграть звук барабана или звук тарелки. Мы можем достичь этого при помощи выражения if
.
Итак, давайте подбросим монетку: орел - играем на барабане, решка - бьём по тарелке. Это просто. Можно сымитировать это действие, используя функцию one_in
(представлена в разделе, посвящённом случайности) с вероятностью один к двум: one_in(2)
. Затем, мы можем использовать результат, чтобы выбрать один из двух участков кода: один - для звука барабана, другой - для тарелки:
loop do
if one_in(2)
sample :drum_heavy_kick
else
sample :drum_cymbal_closed
end
sleep 0.5
end
Отметим, что выражение if
состоит из трёх частей:
Вопрос, на который нужно получить ответ Первый вариант исполняемого кода (выбирается, если ответ на вопрос “Да”) Второй вариант исполняемого кода (если ответ “Нет”)
Обычно, в программных языках ответ “Да” представлен термином true
(истина), а false
(ложь) означает “Нет”. То есть нам нужно задать вопрос, который даёт true
или false
ответ. Это именно то, что делает one_in
.
Обратите внимание, что первый вариант действия размещается между if
и else
, а второй вариант находится между else
и end
. Как и в блоках do/end, допускается многострочный код. Например:
loop do
if one_in(2)
sample :drum_heavy_kick
sleep 0.5
else
sample :drum_cymbal_closed
sleep 0.25
end
end
В этом случае мы добавляем задержку в течение разного количества времени в зависимости от сделанного выбора.
Иногда вам требуется условно выполнить всего лишь одну строчку кода. Это возможно, если написать if
и сразу же ваш вопрос. Например:
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
Если запустить этот код, то каждый раз будут звучать разные аккорды, в которых вероятность появления каждой ноты будет различна.
Итак, вы написали чумовую бас-партию и заводной ритм. Как сыграть обе эти части одновременно? Одно из решений - переплести их вместе вручную - играть небольшую часть баса, затем немного от ударных, потом еще бас… Однако, вскоре становится очень сложно даже думать о том, как разместить это все во времени, особенно если вы начнёте добавлять новые элементы.
Что если бы Sonic Pi мог соединять партии инструментов за вас автоматически? Вообще-то это возможно, для этого вам надо использовать специальную вещь, которая называется поток выполнения.
Дабы не усложнять наш пример, представим, что это и есть крутой ритм и потрясающая бас-партия:
loop do
sample :drum_heavy_kick
sleep 1
end
loop do
use_synth :fm
play 40, release: 0.2
sleep 0.5
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
Обернув первый цикл в do/end блок типа in_thread
, мы заставляем Sonic Pi выполнять содержимое блока do/end точно в то же самое время, когда начинается следующее выражение после блока do/end. В нашем примере таковым является второй цикл. Попробуйте, и вы услышите, как ударные и бас переплетаются вместе!
Теперь, что если мы хотим добавить синт поверх. Что-то типа:
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
. Но третий цикл не достигается. То есть нам нужен ещё один поток:
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
Вас может это удивить, но при нажатии кнопки “Выполнить” также создаётся поток выполнения кода. Вот почему её многократное нажатие наслаивает звуки друг на друга. Запуски автоматически наслаивают звуки, потому что они сами являются потоками.
По мере овладевания секретами мастерства 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
Заметили, что вторая нота воспроизводится на :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}
Последнее, что вам нужно узнать об именованных потоках, это то, что только один поток с определённым именем может выполняться одновременно. Рассмотрим следующий код:
in_thread do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Скопируйте этот фрагмент в пустой буфер редактора и нажмите кнопку “Выполнить”. Нажмите её еще пару раз. Получилась какафония от того, что много повторений амен-брейка смешались вместе. Ладно, нажимайте “Остановить”.
Это то самое поведение, которое нам не раз уже доводилось наблюдать. Если нажимать кнопку “Выполнить”, то новый звук накладывается поверх уже играющего. Поэтому, если у вас есть цикл, и вы нажмёте кнопку “Выполнить” три раза, то получится три слоя циклов, звучащих вместе.
Но ситуация меняется с именованными потоками:
in_thread(name: :amen) do
loop do
sample :loop_amen
sleep sample_duration :loop_amen
end
end
Теперь попробуте понажимать кнопку “Выполнить” с этим кодом. Вы услышите только один цикл амен-брейк. В сообщениях вы также увидите:
==> Пропуск создания потока: thread, поток с именем :amen уже существует.
Sonic Pi сообщает вам, что поток с именем :amen
уже существует, так что он не создаст ещё одного такого же.
Сейчас такое поведение может не показаться вам таким уж полезным. Но в дальнейшем вы ещё вспомните о нём, когда мы начнем лайвкодинг…
Когда вы станете писать большое количество кода, вам потребуется способ организовать и структурировать элементы так, чтобы они выглядели более аккуратно, и их было бы проще понять. Функции - это очень мощный инструмент достижения этой цели. Они позволяют нам давать имена фрагментам кода. Посмотрим, как это работает.
define :foo do
play 50
sleep 1
play 55
sleep 2
end
Мы определили новую функцию, называющуюся foo
. Мы сделали это при помощи нашего старого знакомого - блока do/end и магического слова define
, за которым следует имя нашей функции. Необязательно было называть ее foo
. Можно было придумать какое угодно название, к примеру bar
или baz
. Но, вообще-то, лучше всего, когда имя что-то означает, например main_section
(главная секция) или lead_riff
(солирующий рифф).
Не забывайте ставить двоеточие :
перед именем функции, когда вы определяете её.
Когда наша функция определена, мы можем вызвать её, просто написав её имя:
define :foo do
play 50
sleep 1
play 55
sleep 0.5
end
foo
sleep 1
2.times do
foo
end
Можно использовать foo
внутри повторяющихся блоков, а также везде, где мы могли бы использовать play
или sample
. Это даёт нам отличный способ самовыражения и создания новых обозначений в наших композициях.
Пока что, всякий раз при нажатии кнопки “Выполнить”, Sonic Pi начинал с чистого листа. Ему не известно ничего, кроме того, что находится в буфере редактора. Нельзя ссылаться на код в другом буфере или другом потоке. Однако, функции меняют это. Когда вы определяете функцию, Sonic Pi запоминает ее. Попробуем. Удалите весь код в буфере и замените его вот на что:
foo
Нажмите кнопку “Выполнить”, и убедитесь, что ваша функция играет. Куда же пропал код? Откуда Sonic Pi знал, что играть? Он просто вспомнил вашу функцию даже после её удаления из буфера. Он запомнил что вы напечатали. Это работает только с функциями, которые создаются при помощи define
(и defonce
)
Вам, возможно, будет интересно узнать, что вашу функцию можно научить принимать аргументы, прямо как rrand
принимает значения минимума и максимума. Посмотрим как это выглядит:
define :my_player do |n|
play n
end
my_player 80
sleep 0.5
my_player 90
Пример не очень интересный, но он показывает, что имеется в виду. Мы создали нашу собственную версию play
с параметрами и назвали её my_player
.
Параметры должны описываться после ключевого слова do
блока define
. Они должны быть окружены вертикальными стойками |
и разделены запятыми ,
. Любые слова могут служить именами параметров.
Магия происходит внутри блока define
. Там можно использовать имена параметров, как если бы они были настоящими значениями. В этом примере я проигрываю ноту n
. Вы можете думать о параметрах, как о неких обещаниях о том, что при выполнении кода они будут заменены их значениями. Это достигается передачей параметра функции при её вызове. Чтобы сыграть ноту 80, я пишу my_player 80
. Тогда внутри определения функции n
меняется на 80, так что play n
превращается в play 80
. В следующий раз, когда я вызываю my_player 90
, вместо n
появляется 90, поэтому play n
становится play 90
.
Рассмотрим что-нибудь поинтереснее:
define :chord_player do |root, repeats|
repeats.times do
play chord(root, :minor), release: 0.3
sleep 0.5
end
end
chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3
Я использовал переменную repeats
, как если бы она была числом в строке repeats.times do
. Ещё я использовал root
в качестве названия ноты для play
.
Видите, как можно писать нечто очень выразительное и в то же время простое для чтения, если перенести большую часть логики в функцию!
Присвоение имён полезно для вашего кода. С Sonic Pi это очень просто. Вы пишете желаемое имя, знак равенства, а затем то, что нужно запомнить:
sample_name = :loop_amen
В этом примере мы “запомнили” обозначение :loop_amen
в переменной sample_name
. Теперь мы можем пользоваться sample_name
везде, где мы могли бы указать :loop_amen
. Например:
sample_name = :loop_amen
sample sample_name
Есть три главных причины для использования переменных в Sonic Pi: присвоение значения, управление повторами и захват результатов операций.
Когда вы пишете код, вы говорите компьютеру сделать что-то. Пока компьютер это понимает - всё в порядке. Но всё же важно помнить, что код читает не только компьютер. Другие люди, возможно, захотят тоже прочесть его и попробовать разобраться, что в нём происходит. Скорее всего и вы сами будете читать и пытаться понять свой собственный код в будущем. Сейчас всё кажется очевидным, но для остальных, или же для вас самих в будущем, это может быть не так!
Одним из способов помочь другим понять, что делает ваш код, - это оставлять комментарии (как мы это видели в предыдущей главе). Ещё один способ - давать осмысленные имена переменным. Посмотрите на этот код:
sleep 1.7533
Зачем указано число 1.7533
? Откуда оно взялось? Что оно означает? Теперь взгляните на этот пример:
loop_amen_duration = 1.7533
sleep loop_amen_duration
Вот теперь стало ясно, что значит 1.7533
. Это же продолжительность сэмпла :loop_amen
! Конечно, вы могли бы заметить, почему бы просто не написать так:
sleep sample_duration(:loop_amen)
Это, безусловно, очень хороший способ выразить намерения кода.
Часто вы видите много повторений в своем коде. Когда необходимо что-то поменять, то делать это приходится во многих местах. Посмотрите на следующее:
sample :loop_amen
sleep sample_duration(:loop_amen)
sample :loop_amen, rate: 0.5
sleep sample_duration(:loop_amen, rate: 0.5)
sample :loop_amen
sleep sample_duration(:loop_amen)
Много чего мы делаем с :loop_amen
! Но что если мы захотим послушать как это будет звучать с другим замкнутым сэмплом, таким как :loop_garzul
? Пришлось бы найти и заменить все :loop_amen
на :loop_garzul
. Этим можно заняться, если больше нечего делать. А как насчет живого выступления? Иногда время - это непозволительная роскошь. Особенно, если вы хотите, чтобы люди продолжали танцевать.
Ну, а если бы вы записали свой код так:
sample_name = :loop_amen
sample sample_name
sleep sample_duration(sample_name)
sample sample_name, rate: 0.5
sleep sample_duration(sample_name, rate: 0.5)
sample sample_name
sleep sample_duration(sample_name)
Он делает совершенно то же самое (попробуйте сами). Зато тут есть возможность заменить строку sample_name = :loop_amen
на sample_name = :loop_garzul
, что приведёт к реальным изменениям во многих местах. Вот что даёт нам магия переменных.
Наконец, хороший повод использовать переменные - захватывать результат чего-либо. К примеру, вам может понадобится что-то сделать с продолжительностью сэмпла:
sd = sample_duration(:loop_amen)
Теперь можно вставлять sd
везде, где нам нужна длительность сэмпла :loop_amen
.
Вероятно, ещё более важно то, что переменная разрешает нам сохранить результат вызова play
или sample
:
s = play 50, release: 8
Мы захватили и запомнили s
как переменную, которая позволяет управлять синтом, пока он играет:
s = play 50, release: 8
sleep 2
control s, note: 62
В следующей главе мы рассмотрим подробнее управление синтами.
Хотя переменные хороши для присвоения имени и сохранения результатов, важно знать что они обычно должны использоваться в потоке. Например, не делайте так:
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :sorted do
a = a.sort
sleep 0.5
puts "sorted: ", a
end
live_loop :shuffled do
a = a.shuffle
sleep 0.5
end
В примере выше мы присвоили ряд чисел переменной ‘a’ и затем использовали её в двух отдельных ‘live_loop`s’. В первом живом цикле каждые ‘0,5’ секунды мы сортируем кольцевой список (1, 2, 3, 4, 5, 6), затем отображаем результат в журнале. Если ты запустишь код, ты увидишь, что выведенный список не всегда отсортирован!. Это может быть для тебя сюрпризом, ведь иногда список выводится отсортированным, а иногда нет. Это называется недетерминированным поведением и является результатом неприятной проблемы называемой гонкой состояний. Проблема заключается в том, что второй живой цикл также работает с нашим кольцевым списком (в данном случае перемешивает его) и на момент вывода на экран список может быть как отсортирован, так и перемешан. Оба живых цикла соревнуются сделать разные вещи с одной переменной и каждый раз ‘побеждает’ разный цикл.
Есть два решения. Первое: не использовать одну переменную в разных живых циклах или потоках. Например, код ниже всегда выводит отсортированный список, поскольку каждый живой цикл имеет собственную отдельную переменную:
live_loop :shuffled do
a = (ring 6, 5, 4, 3, 2, 1)
a = a.shuffle
sleep 0.5
end
live_loop :sorted do
a = (ring 6, 5, 4, 3, 2, 1)
a = a.sort
sleep 0.5
puts "sorted: ", a
end
Однако, иногда мы хотим поделиться чем-то между потоками. Например, текущей тональностью, BMP, синтом и т.д. В этом случае решением будет воспользоваться специальными потоко-безопасными состояниями системы Sonic Pi через функции ‘get’ и ‘set. Это будет осуждаться в разделе 10.
Когда у вас начнёт достаточно хорошо получаться лайвкодинг с большим количеством потоков, выполняющихся одновременно, вы, скорее всего, заметите, что очень легко допустить ошибку, которая может прервать поток. Ничего страшного в этом нет, так как поток может быть перезапущен простым нажатием кнопки “Выполнить”. Однако, после перезапуска потока он будет играть невпопад с другими.
Как мы обсуждали ранее, новые потоки, созданные при помощи in_thread
наследуют все настройки от родительского потока. Они включают и текущую метку времени. Это означает, что потоки всегда синхронизированы друг с другом после одновременного их запуска.
Но, когда поток стартует отдельно от родительского, внутри него ведётся собственный отсчет времени, который вряд ли совпадёт с каким-либо из других активных потоков.
В Sonic Pi решением этой проблемы являются функции cue
и sync
.
cue
позволяет нам отправлять сигнал пульса другим потокам. По умолчанию, другие потоки не слушают и пропускают эти сообщения. Однако, поток может легко заявить о своей заинтересованности, вызвав функцию sync
.
Важно осознавать, что функция sync
похожа на sleep
, ведь она останавливает текущий поток, и тот некоторое время не выполняется. Для sleep
время простоя указывается явно, но вызвав sync
, вы не знаете сколько времени оно продлится, потому что sync
ждёт следующий cue
от другого потока. Это может случиться скоро, а может и нет.
Давайте выясним немного больше деталей:
in_thread do
loop do
cue :tick
sleep 1
end
end
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Здесь у нас есть два потока. Один работает как метроном. Он не играет никаких звуков, только отправляет :tick
сигнал каждую долю такта. Второй поток синхронизуется с сообщениями tick
. Когда он получает :tick
сообщение, то наследует временную отметку потока, вызвавшего cue
, и продолжает выполнение.
В результате мы будем слышать сэмпл :drum_heavy_kick
в тот самый момент, когда другой поток отправляет :tick
сигнал. Даже если два этих потока стартовали не одновременно, это всё равно будет происходить:
in_thread do
loop do
cue :tick
sleep 1
end
end
sleep(0.3)
in_thread do
loop do
sync :tick
sample :drum_heavy_kick
end
end
Результатом вызова sleep
будет расхождение второго потока с первым. Однако, так как мы используем cue
и sync
, то мы автоматически синхронизируем потоки и избегаем любых случайных временных сдвигов.
Для сигналов cue
можно использовать любые названия, а не только :tick
. Просто следите за тем, чтобы все остальные потоки вызывали sync
с правильным именем. Иначе они остановятся навсегда (или, по крайней мере, пока вы не нажмёте кнопку “Остановить”).
Попробуем запрограммировать что-нибудь с использованием нескольких имен cue
:
in_thread do
loop do
cue [:foo, :bar, :baz].choose
sleep 0.5
end
end
in_thread do
loop do
sync :foo
sample :elec_beep
end
end
in_thread do
loop do
sync :bar
sample :elec_flip
end
end
in_thread do
loop do
sync :baz
sample :elec_blup
end
end
Тут у нас есть цикл с функцией cue
, отправляющей пульс. Случайным образом этот пульс может быть назван :foo
, :bar
или :baz
. Ещё есть три цикла в потоках, которые синхронизируются с каждым из этих сигналов независимо и воспроизводят разные сэмплы. Чистый эффект от этого кода в том, что каждые полсекунды мы слышим звук, так как каждый из потоков sync
случайным образом синхронизируется с потоком cue
и проигрывает свой сэмпл.
Конечно же, код будет работать даже если расположить потоки в обратном порядке, поскольку потоки будут дожидаться следующего cue
.
Одной из наиболее стоящих и весёлых вещей в Sonic Pi является возможность легко добавить студийные эффекты к вашим звукам. Например, можно добавить к частям вашей пьесы реверберацию или эхо, или даже исказить или заставить вибрировать ваши басы.
Sonic Pi даёт очень простой, но вместе с тем очень мощный способ добавления эффектов. Можно даже строить цепочки из них (таким образом можно пропустить звук через дисторшн, потом эхо и в конце реверберацию) и настраивать каждый из них по отдельности при помощи регулировок (как синты и сэмплы). Можно даже менять параметры эффектов пока они используются. Так, к примеру, реверберация баса может усиливаться в течение трэка…
Не переживайте, если это кажется вам слишком сложным. Всё станет намного понятнее после того, как вы попробуете это сами. Но пока полезной аналогией будет служить гитарный эффект. Есть много видов гитарных эффектов. Одни добавляют реверберацию, другие искажение и так далее. Гитарист подключает свой инструмент к педали, например дисторшн, затем другим кабелем добавляет в цепь педаль реверберации. После этого выход реверберации соединяется с усилителем:
Гитара -> Дисторшн -> Реверберация -> Усилитель
Это называется каскадом эффектов. И это поддерживается в Sonic Pi. Вдобавок, обычно на каждой педали есть ручки и ползунки для управления применяемым эффектом. В Sonic Pi есть то же самое. Представьте себе музыканта, который что-то играет, а кто-то другой управляет эффектами. Такой способ тоже реализован в Sonic Pi, но тут вместо кого-то другого вступает в дело компьютер.
Давайте исследовать эффекты!
В этом разделе мы рассмотрим пару эффектов - реверберацию и эхо. Мы увидим, как их использовать, как настраивать и как строить из них цепочки.
Система эффектов Sonic Pi использует блоки. Так что, если ты еще не прочел главу 5.1, было бы неплохо прежде её просмотреть и затем вернуться обратно.
Нужно написать специальный блок with_fx :reverb
, если мы хотим использовать реверберацию. Примерно так:
with_fx :reverb do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Теперь запустите этот код, и вы услышите как он звучит с реверберацией. Неплохо, правда? Все что угодно будет звучать отлично с реверберацией.
Посмотрим, что произойдет, если поместить код вне блока do/end:
with_fx :reverb do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
sleep 1
play 55
Обратите внимание, как последний play 55
играется без реверберации. Это происходит потому, что эта строка находится за пределами блока do/end, то есть она не пропускается через эффект.
Точно так же, если играть звуки перед блоком do/end, то и они не будут обрабатываться эффектом:
play 55
sleep 1
with_fx :reverb do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
sleep 1
play 55
Есть множество эффектов на выбор. Как насчет эхо?
with_fx :echo do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Одна из сильных сторон блоков эффектов Sonic Pi в том, что у них есть регулировки, похожие на те, что мы уже видели у play
и sample
. Например, рассмотрим забавный параметр phase:
, который представляет собой длительность эхо в долях такта. Сделаем эхо помедленнее:
with_fx :echo, phase: 0.5 do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Или побыстрее:
with_fx :echo, phase: 0.125 do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Заставим эхо затихать дольше, установив время decay:
на 8 долей такта:
with_fx :echo, phase: 0.5, decay: 8 do
play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62
end
Блоки эффектов можно вкладывать друг в друга, что позволяет очень легко собирать из них каскады эффектов. Например, что если вы захотите пропустить некоторый код через эхо, а потом через реверберацию? Легко! Просто поместите один эффект внутри другого:
with_fx :reverb do
with_fx :echo, phase: 0.5, decay: 8 do
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
end
end
Представьте как звук вытекает изнутри наружу. Весь звук из внутреннего блока do/end (такой как play 50
) вначале попадает в эффект эхо, а затем звук с эффектом эхо в свою очередь отправляется в эффект реверберации.
Можно создавать очень глубокие вложения, чтобы получать непредсказуемые результаты. Однако, имейте в виду, что эффекты требуют больших ресурсов. При вложении они работают в одно и то же время. Так что используйте эффекты разумно, особенно на платформах с низким количеством ресурсов (например Raspberry Pi).
В Sonic Pi встроено большое количество эффектов на выбор. Чтобы увидеть доступные, щелкните мышью по FX в левом нижнем углу справочной системы. Вот некоторые из моих любимых:
колебание, реверберации, эхо, искажение, разрезание
Теперь вы можете добавлять эффекты везде, где только захочется!
Хотя снаружи они выглядят обманчиво просто, внутри эффекты устроены довольно сложно. Их простота часто побуждает людей злоупотреблять их использованием. Это вполне нормально, если у вас мощный компьютер. Но если, как и я, вы импровизируете на Raspberry Pi, то нужно быть аккуратным с нагрузкой. Иначе ритм может начать прерываться.
Рассмотрим следующий код:
loop do
with_fx :reverb do
play 60, release: 0.1
sleep 0.125
end
end
В этом примере мы играем ноту 60 с очень коротким временем затухания. То есть это очень короткая нота. Нам нужна реверберация, поэтому мы обернули её в блок reverb. Пока что все хорошо. За исключением…
Посмотрим, что делает код. Во-первых, у нас есть цикл loop
. Это означает, что всё, что внутри него, повторяется бесконечно. Во-вторых, есть блок with_fx
. Его роль в том, чтобы создавать новый эффект реверберации каждый раз, когда он выполняется. Как будто для каждого щипка гитарной струны включается собственная педаль реверберации. Здорово, что так можно делать, но это не всегда то, что нам нужно. Например, такой код будет трудно выполнять на Raspberry Pi. Создание эффекта реверберации и ожидание момента, когда он должен быть остановлен и удален, - обо всем позаботится за тебя блок with_fx
. Но на это требуются ресурсы процессора, а они могут быть ограничены.
Как изменить код так, чтобы он больше походил на обычное подключение, где у нашего гитариста всего одна педаль реверберации, через которую и пропускаются все звуки? Легко:
with_fx :reverb do
loop do
play 60, release: 0.1
sleep 0.125
end
end
Мы помещаем наш цикл внутрь блока with_fx
. Таким образом создается всего один единственный эффект для всех нот, извлекаемых в цикле. Этот вариант намного более эффективен, и Raspberry Pi с ним хорошо справится.
В качестве компромисса можно предложить использовать with_fx
на протяжении нескольких повторений внутри цикла:
loop do
with_fx :reverb do
16.times do
play 60, release: 0.1
sleep 0.125
end
end
end
То есть новый эффект реверберации будет создаваться через каждые 16 нот.
Это настолько распространенный паттерн, что with_fx
поддерживает опцию для выполнения именно этого, но без необходимости писать блок 16.times
:
loop do
with_fx :reverb, reps: 16 do
play 60, release: 0.1
sleep 0.125
end
end
Обе записи: reps: 16
и 16.times do
будут вести себя одинаково. Reps: 16
по сути повторяет код в блоке do / end
16 раз, так что вы можете использовать их оба взаимозаменяемо и выбрать тот, который вам удобнее.
Помните, ошибок нет, есть только возможности. Однако, каждый из этих подходов даст разный звук и разные показатели производительности. Поэтому попрактикуйтесь, а затем использте тот способ, который звучит лучше всего для вас, и в то же время укладывается в ограничения быстродействия вашей платформы.
До этого момента мы разбирали, как включать синты и сэмплы, и то, как менять их регулировки, такие как амплитуда, панорамирование, параметры огибающей и т.д. Каждый звук, по сути, является отдельным звуком с собственными настройками, действующими в течение всей его продолжительности.
Вот бы было здорово, если бы вы могли менять параметры воспроизводящегося звука, как вы може подтягивать вибрирующую струну гитары, правда?
Вам повезло - этот раздел покажет, как это можно сделаеть в Sonic Pi.
Раньше мы изучали только как включать звуки и добавлять эффекты. Однако, в Sonic Pi есть возможность управлять воспроизводимыми звуками. Этого можно достичь, сохранив ссылку на синт в переменной:
s = play 60, release: 5
В этом примере мы создали локальную переменную среды выполнения s
, которая представляет собой синт, играющий ноту 60. Обратите внимание, что она локальна для текущего контекста - нельзя получить к ней доступ из других контекстов, таких как функции.
После того, как у нас появилась s
, мы можем управлять ей с помощью функции control
:
s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72
Заметьте, что мы запускаем не четыре разных синта, а один и просто изменяем высоту звука в то время, как он продолжает играть.
Можно передавать функции control
любые из стандартных настроек, то есть доступен контроль над такими параметрами, как amp:
, cutoff:
или pan:
.
Некоторые регулировки нельзя менять после включения синта. Это относится ко всем параметрам ADSR-огибающей. Из документации в справочной системе можно узнать какие параметры разрешено менять, а какие нет. Если документация говорит Нельзя изменять после установки, это значит, что после запуска синта настройке нельзя задавать новое значение.
Также в Sonic Pi доступен контроль над эффектами, хотя он и достигается немного другим способом:
with_fx :reverb do |r|
play 50
sleep 0.5
control r, mix: 0.7
play 55
sleep 1
control r, mix: 0.9
sleep 1
play 62
end
Мы используем параметры блока do/end вместо переменных. Нам надо задать уникальное имя для выбранного эффекта, окружив его вертикальными чертами |
. Затем мы можем ссылаться на него изнутри охватывающего блока do/end. Так же работают и параметризованные функции.
Пришла пора немного поуправлять синтами и эффектами!
Вы могли заметить, что есть множество настроек, имя которых оканчивается на _slide
, пока занимались изучением синтов и специальных эффектов. Возможно, вы даже пытались ими воспользоваться и заметили, что ничего не происходит. Это от того, что они не являются обычными параметрами. Эти настройки особенные потому, что они работают только тогда, когда вы контролируете синт так, как мы видели в предыдущем разделе.
Рассмотрим пример:
s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72
Вы можете слышать, как высота звука синта сразу же меняется, как только происходит вызов control
. Однако, что если мы захотим, чтобы параметр менялся плавно. Поскольку мы управляем значением note:
, то для добавления плавности надо задать параметр синтезатора note_slide
:
s = play 60, release: 5, note_slide: 1
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72
Теперь мы слышим, как ноты подтягиваются в промежутках между вызовами control
. Звучит неплохо, не так ли? Можно ускорить скольжение звука, если указать более короткий интервал времени, например note_slide: 0.2
, или замедлить его, установив большее значение.
Для каждой настройки, которой можно управлять, есть соответствующий _slide
параметр, с которым можно поиграть.
Если вы задали значение _slide
для играющего синтезатора, то оно запомнится и будет использоваться всякий раз, когда соответствующая настройка меняется. Чтобы прекратить плавное изменение звука, надо установить значение _slide
в 0 перед следующим вызовом control
.
Можно делать плавное изменение эффектов:
with_fx :wobble, phase: 1, phase_slide: 5 do |e|
use_synth :dsaw
play 50, release: 5
control e, phase: 0.025
end
Пришла пора добавить немного плавности к вашей музыке…
Очень полезный инструмент в инструментарии программиста - это структуры данных.
Иногда вам может потребоваться определить и использовать сразу несколько разных элементов. Например, вы можете посчитать полезным иметь последовательность нот, чтобы играть их одну за другой. Языки программирования имеют структуры данных, чтобы вы могли делать это.
Существует множество интересных и экзотических структур данных, доступных для программистов, и люди постоянно изобретают новые. Впрочем, пока что мы нуждаемся в рассмотрении одной очень простой структуры данных - списка.
Давайте рассмотрим его более подробно. Мы узнаем про его базовую форму, а так же как списки могут быть использованы для представления гамм и аккордов.
В этом разделе мы рассмотрим очень полезную структуру данных - список. Мы очень кратко познакомились с ним ранее в разделе о рандомизации, тогда мы случайным образом выбирали ноты из списка, чтобы играть их:
play choose([50, 55, 62])
В этом разделе мы также изучим использование списков для представления аккордов и гамм. Сначала давайте вспомним, как мы можем сыграть аккорд. Помните, что если мы не используем sleep
, все звуки воспроизводятся одновременно:
play 52
play 55
play 59
Давайте посмотрим на другой способ представления этого кода.
Один из вариантов - разместить все ноы в виде списка: [52, 55, 59]
. Наша дружественная функция play
достаточно умна, чтобы понимать, как играть список нот. Попробуйте это:
play [52, 55, 59]
О, это уже приятнее читать. Воспроизведение списка нот не мешает вам использовать любые обычные параметры:
play [52, 55, 59], amp: 0.3
Конечно, мы также можем использовать традиционные имена нот вместо номеров MIDI:
play [:E3, :G3, :B3]
Теперь те из вас, кому повезло изучать теорию музыки, смогут подтвердить, что аккорд ми минор был сыгран в 3-й октаве.
Еще одной полезной особенностью списка является возможность получать оттуда информацию. Это может звучать немного странно, но это не сложнее чьей-либо просьбы открыть книгу на странице 23. Применительно к списку, говорят - “Какой элемент находится по индексу 23”? Единственная странность заключается в том, что в программировании индексы начинаются с 0, а не с 1.
Мы не считаем индекы списка 1, 2, 3… вместо этого мы считаем 0, 1, 2…
Давайте рассмотрим это чуть более подробно. Взгляните на этот список:
[52, 55, 59]
Здесь нет ничего страшного. Теперь, какой второй элемент в этом списке? Конечно, это 55
. Это было легко. Давайте посмотрим, что нам ответит компьютер на аналогичный вопрос:
puts [52, 55, 59][1]
Это выглядит немного странно, если вы никогда не видели ничего подобного раньше. Поверьте мне, это не очень сложно. Строка выше состоит из трёх частей: слово puts
, наш список [52, 55, 59]
и наш индекс [1]
. Сначала мы говорим puts
потому что хотим, чтобы Sonic Pi напечатал ответ для нас в журнал. Далее, мы даём ему наш список, и, наконец, наш индекс запрашивает второй элемент. Мы должны окружить индекс квадратными скобками и т.к. счёт начинается с 0
, индекс второго элемента это 1
. Посмотрите:
# indexes: 0 1 2
[52, 55, 59]
Попробуйте выполнить код puts [52, 55, 59][1]
и вы увидите, что 55
появится в журнале. Измените индекс 1
на другой, попробуйте более длинные списки и подумайте, как вы сможете использовать список в своём следующем сочинении. Например, какие музыкальные структуры могут быть представлены в виде ряда чисел…
Sonic Pi имеет встроенную поддержку названий аккордов, которая возвращает списки. Попробуйте сами:
play chord(:E3, :minor)
Теперь мы действительно до чего-то добрались. Это выглядит намного симпатичнее, чем сырые списки (и это легче читать). А как на счёт других аккордов, Sonic Pi их поддерживает? Да, и много. Попробуйте некоторые из них:
chord(:E3, :m7)
chord(:E3, :minor)
chord(:E3, :dim7)
chord(:E3, :dom7)
Мы можем легко превратить аккорды в арпеджио с функцией play_pattern
:
play_pattern chord(:E3, :m7)
Хорошо, но не очень весело - она играла очень медленно. play_pattern
будет играть каждую ноту из списка, вызывая sleep 1
после каждого вызова play
. Мы можем использовать другую функцию - play_pattern_timed
, чтобы устанавливать наше собственное время и повысить скорость:
play_pattern_timed chord(:E3, :m7), 0.25
Мы можем также передавать разное время в виде списка, который будет рассматриваться как кольцо:
play_pattern_timed chord(:E3, :m13), [0.25, 0.5]
Это эквивалентно:
play 52
sleep 0.25
play 55
sleep 0.5
play 59
sleep 0.25
play 62
sleep 0.5
play 66
sleep 0.25
play 69
sleep 0.5
play 73
Что бы вы предпочли написать?
Sonic Pi поддерживает широкий диапазон гамм. Как насчет сыграть мажорную гамму от ноты С3?
play_pattern_timed scale(:c3, :major), 0.125, release: 0.1
Мы даже можем запросить больше октав:
play_pattern_timed scale(:c3, :major, num_octaves: 3), 0.125, release: 0.1
Как насчёт пентатоники?
play_pattern_timed scale(:c3, :major_pentatonic, num_octaves: 3), 0.125, release: 0.1
Использование аккордов и гамм - отличный способ ограничить случайный выбор для получения чего-то более осмысленного. Поиграйте с примером, который выбирает случайные ноты из минорного аккорда:
use_synth :tb303
loop do
play choose(chord(:E3, :minor)), release: 0.3, cutoff: rrand(60, 120)
sleep 0.25
end
Попробуйте другие названия аккордов и диапазоны частот среза фильтра.
Чтобы выяснить, какие гаммы и аккорды поддерживаются Sonic Pi, просто нажмите кнопку lang внизу слева от этого учебника и затем выберите аккорд или гамму в списке. Прокручивайте вниз информацию в главной панели, пока не увидите длинный список аккордов или гамм (в зависимости от того, что вы ищете).
Получайте удовольствие и помните: здесь нет ошибок, только возможности.
Интересной разновидностью списков являются кольца. Если вы раньше занимались программированием, то наверняка сталкивались с кольцевым буфером или кольцевым массивом. Здесь мы узнаем про кольцевой список - это быстро и просто.
В предыдущем разделе о списках мы видели, как можно извлечь из них элементы, используя механизм индексирования:
puts [52, 55, 59][1]
Так, а что произойдет, если вы захотите извлечь индекс 100
? Там явно нет элемента с индексом 100, так как у нашего списка только три элемента. Поэтому Sonic Pi вернет вам nil
, что означает “ничто”.
Однако, представьте, что у вас есть счётчик, который, подобно номеру текущего такта, постоянно увеличивается. Давайте создадим наш счётчик и наш список:
counter = 0
notes = [52, 55, 59]
Теперь мы можем использовать счётчик, чтобы получить доступ к нотам в нашем списке:
puts notes[counter]
Здорово, мы получили 52
. Теперь давайте увеличим наш счётчик и получим другую ноту:
counter = (inc counter)
puts notes[counter]
Супер, теперь мы получили 55
и если мы сделаем так снова, получим 59
. Однако, если после этого мы увеличим счётчик ещё раз, мы выйдем за пределы нашего списка и получим nil
. Но что, если нам нужно вернуться к началу списка и снова начинать извлекать элементы по кругу? Вот для этого и нужны кольца.
Мы можем создавать кольца одним из двух способов. Либо используем функцию ring
с элементами кольца в качестве параметров:
(ring 52, 55, 59)
Либо можем взять обычный список и преобразовать его в кольцо, передав ему .ring
сообщение:
[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
Допустим, мы используем переменную для хранения номера текущего такта. Мы можем использовать её в качестве индекса в нашем кольце для извлечения нот, или времени затухания или чего-нибудь полезного, что мы сохранили в нашем кольце, независимо от номера такта, в котором мы находимся в данный момент.
Полезно знать, что списки, возвращаемые scale
и chord
также являются кольцами и позволяют получить к ним доступ с помощью произвольных индексов.
В дополнение к ring
существует ряд других функций, которые будут создавать кольца для нас.
range
предлагает вам указать начальную точку, конечную точку и размер шага.
bools
позволяет использовать 1
и 0
, чтобы кратко представлять логические переменные.
knit
позволяет связывать в последовательности повторяющиеся значения.
spread
создает кольцо логических значений с Евклидовым распределением.
Взгляните на их соответствующую документацию для получения дополнительной информации.
Помимо конструкторов, таких как range
и spread
, есть и другой способ создания новых колец - манипулирование существующими кольцами.
Чтобы исследовать это, возьмём простое кольцо:
(ring 10, 20, 30, 40, 50)
Что, если мы хотим перевернуть его задом наперёд? Тогда мы используем связанный метод .reverse
, который разворачивает кольцо в обратную сторону:
(ring 10, 20, 30, 40, 50).reverse #=> (ring 50, 40, 30, 20, 10)
Так, а что, если мы захотим получить первые три элемента кольца?
(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 элемент, а затем получить первые 3 элемента?
Давайте сделаем это в несколько этапов:
(ring 10, 20, 30, 40, 50)
- наше исходное кольцо
(ring 10, 20, 30, 40, 50).shuffle
- перемешиваем - (ring 40, 30, 10, 50, 20)
(ring 10, 20, 30, 40, 50).shuffle.drop(1)
- отбрасываем 1 элемент - (ring 30, 10, 50, 20)
(ring 10, 20, 30, 40, 50).shuffle.drop(1).take(3)
- берём 3 первых элемента - (ring 30, 10, 50)
Как вы видите, можно создавать длинные цепи из этих методов просто склеивая их вместе. Мы можем комбинировать их в любом порядке, в каком захотим, создавая чрезвычайно богатый и мощный способ генерации новых колец из существующих.
Наши кольца обладают одним очень важным свойством. Оно заключается в том, что цепные методы, описанные в этом разделе не изменяют кольца, они возвращают новые кольца. Это значит, что вы можете разделять кольцо между потоками выполнения и использовать разные методы в разных потоках, зная, что не повлияете на другой поток, использующий то же самое кольцо.
Вот список доступных для вас цепных методов:
.reverse
- возвращает отсортированную в обратном порядке версию кольца
.sort
- возвращает отсортированную версию кольца
.shuffle
- возвращает отсортированную в случайном порядке версию кольца
.pick (3)
- возвращает кольцо с результатами вызова .choose
3 раза
.pick (3)
- возвращает кольцо с результатами вызова .choose
3 раза
.take(5)
- возвращает кольцо, содержащее первые 5 элементов исходного кольца
.drop(3)
- возвращает кольцо, содержащее все элементы исходного кольца, кроме первых 3 элементов
.butlast
- возвращает новое кольцо с отсутствующим последним элементом
.drop_last(3)
- возвращает новое кольцо с отсутствующими 3 последними элементами
.take_last(6)
- возвращает кольцо, содержащее последние 6 элементов исходного кольца
.stretch(2)
- повторяет каждый элемент кольца дважды
.repeat(3)
- повторяет всё кольцо 3 раза
.mirror
- добавляет кольцо к перевёрнутой версии себя
.reflect
- то же, что и .mirror
, но не дублирует средний элемент
.scale(2)
- возвращает новое кольцо все элементы которого умножены на 2 (если кольцо содержит только числа)
Конечно, цепные методы, принимающие числовые аргументы, могут принимать и другие числа! Так что не стесняйтесь вызывать .drop(5)
вместо .drop(3)
, если вы хотите отбросить первые 5 элементов кольца.
Один из наиболее интересных аспектов Sonic Pi заключается в том, что он позволяет писать и модифицировать код вживую, играть музыку, как если бы вы выступали с гитарой. Одно из преимуществ такого подхода состоит в том, что он даёт вам больше обратной связи во время сочинения (просто начни выполнение цикла и продолжай настройку до тех пор, пока звук не станет идеальным). Однако, главное преимущество заключается в том, что вы можете взять Sonic Pi на сцену и выступать с ним.
В этом разделе мы рассмотрим основы превращения статического кода ваших сочинений в динамичное исполнение.
Держитесь за своё кресло…
Теперь мы узнали достаточно, чтобы начать по-настоящему развлекаться. В этом разделе мы будем черпать из всех предыдущих разделов и узнаем, как вы сможете делать свои музыкальные композиции живыми и превращать их в выступления. Для этого нам понадобится 3 основных компонента:
Умение писать код, который создаёт звук - ЕСТЬ! Умение писать функции - ЕСТЬ! Умение использовать (именовать) потоки - ЕСТЬ!
Чудненько, давайте начнём. Будем вживую кодировать наши первые звуки. Начнем с простого. Сначала нам нужна функция, содержащая код, который мы хотим проиграть. Ещё мы хотим зациклить вызовы этой функции в отдельном потоке:
define :my_loop do
play 50
sleep 1
end
in_thread(name: :looper) do
loop do
my_loop
end
end
Если это выглядит для вас довольно сложным, вернитесь и перечитайте разделы о функциях и потоках. Это не сложно, если раньше вы уже прокручивал эти вещи у себя в голове.
То, что мы здесь имеем - это определение функции, которая всего лишь играет ноту 50 и немного ждёт. Затем мы задали именованный поток с именем :looper
, который бесконечно выполняет цикл с функцией my_loop
.
Если вы выполните этот код, то услышите ноту 50 повторяющуюся снова и снова…
Итак, вот где начинается веселье. В то время, как код по-прежнему выполняется, изменим 50 на другое число, скажем, на 55, и снова нажмём кнопку “Выполнить”. Ого! Всё изменилось! Вживую!
Это не добавило новый звуковой слой, так как мы используем именованные потоки выполнения, которые допускают только один поток для каждого имени. Кроме того, звук изменился, потому что мы переопределили функцию. Мы дали :my_loop
новое определение. Когда поток :looper
повторял цикл, он просто вызвал новое определение.
Попробуйте изменить это снова - измените ноту, измените время сна. Как на счёт добавления инструкции use_synth
? Например, измените код на:
define :my_loop do
use_synth :tb303
play 50, release: 0.3
sleep 0.25
end
Сейчас это звучит довольно интересно, но мы можем оживить это ещё больше. Вместо того, чтобы играть одну и ту же ноту снова и снова, попробуем сыграть аккорд:
define :my_loop do
use_synth :tb303
play chord(:e3, :minor), release: 0.3
sleep 0.5
end
Как на счёт воспроизведения случайных нот из аккорда:
define :my_loop do
use_synth :tb303
play choose(chord(:e3, :minor)), release: 0.3
sleep 0.25
end
Или использования случайных значений частоты среза:
define :my_loop do
use_synth :tb303
play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
sleep 0.25
end
Наконец, добавим немного барабанов:
define :my_loop do
use_synth :tb303
sample :drum_bass_hard, rate: rrand(0.5, 2)
play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
sleep 0.25
end
Теперь это становится увлекательным!
Однако, прежде чем вы начнёте живое кодирование с функциями и потоками, остановите то, что вы сейчас делаете, и прочтите следующий раздел live_loop
, который изменит манеру вашего кодирования в Sonic Pi навсегда…
Окей, этот раздел учебника - настоящая жемчужина. Если вы решите прочесть только один раздел, это должен быть именно этот раздел. Если вы прочли предыдущий раздел - основы лайвкодинга, live_loop
- это простой способ сделать всё то же самое, но без необходимости писать так много кода.
Если вы не читали предыдущий раздел, live_loop
- это лучший способ поджемовать с Sonic Pi.
Давайте поиграем. Наберите следующее в новом буфере:
live_loop :foo do
play 60
sleep 1
end
Теперь нажмите кнопку “Выполнить”. Вы услышите базовый звуковой сигнал на каждую долю такта. Здесь нет ничего весёлого. Однако, пока не нажимайте “Остановить”. Измените 60
на 65
и нажмите “Выполнить” снова.
Ого! Тон изменился автоматически без пропуска доли. Это и есть лайвкодинг.
Почему бы не изменить звук так, чтобы он больше походил на бас? Просто обновите свой код пока тот играет:
live_loop :foo do
use_synth :prophet
play :e1, release: 8
sleep 8
end
Затем нажмите “Выполнить”.
Давайте добавим изменяющуюся частоту среза:
live_loop :foo do
use_synth :prophet
play :e1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
Нажмите “Выполнить” снова.
Добавьте какие-нибудь барабаны:
live_loop :foo do
sample :loop_garzul
use_synth :prophet
play :e1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
Измените ноту с e1
на c1
:
live_loop :foo do
sample :loop_garzul
use_synth :prophet
play :c1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
Теперь хватит слушать меня и начните играь сами! Веселись!
Рассмотрим следующий живой цикл:
live_loop :foo do
play 50
sleep 1
end
Вы, наверное, заинтересовались, почему он называется :foo
. Это имя имеет значение, поскольку оно показывает, что этот живой цикл отличается от всех других живых циклов.
Не может быть двух живых циклов, выполняющихся под одним именем.
Это значит, что если мы хотим иметь несколько одновременно выполняющихся циклов, нам просто нужно дать им разные имена:
live_loop :foo do
use_synth :prophet
play :c1, release: 8, cutoff: rrand(70, 130)
sleep 8
end
live_loop :bar do
sample :bd_haus
sleep 0.5
end
Теперь можно обновлять и изменять каждый живой цикл отдельно и всё будет прекрасно работать.
Есть один важный момент, который вы, наверное, уже заметили - все живые циклы автоматически работают с механизмом распарралеливания потоков, который мы исследовали ранее. Всякий раз, когда живой цикл начинает выполняться, он генерирует новое cue
событие с названием цикла. Следовательно, мы можем sync
эти сигналы, чтобы гарантировать нашим циклам синхронизацию без необходимости что-либо останавливать.
Рассмотрим этот плохо синхронизированный код:
live_loop :foo do
play :e4, release: 0.5
sleep 0.4
end
live_loop :bar do
sample :bd_haus
sleep 1
end
Давайте посмотрим, сможем ли мы исправить тайминг и синхронизировать его без остановки воспроизведения. Сначала исправим время сна в цикле :foo
на что-то вроде 0.5
:
live_loop :foo do
play :e4, release: 0.5
sleep 0.5
end
live_loop :bar do
sample :bd_haus
sleep 1
end
Но мы ещё не совсем закончили, ведь вы заметили, что такты пока не выстроились правильно. Это происходит потому, что циклы не в фазе. Давайте исправим это, синхронизировав один цикл с другим:
live_loop :foo do
play :e4, release: 0.5
sleep 0.5
end
live_loop :bar do
sync :foo
sample :bd_haus
sleep 1
end
Ого, теперь всё прекрасно синхронизируется по времени и всё это без остановки.
А теперь вперёд! Кодируйте вживую с живыми петлями!
Однажды, кодируя вживую, вы, вероятно, найдёте себя делающими множество вещей с помощью циклов, основанных на кольцах. Вы будете помещать в кольца мелодии, ритмы, последовательности аккордов, тембральные изменения и т.д и т.п.
Sonic Pi предоставляет очень удобный инструмент для работы с кольцами внутри live_loop
. Он называется системой тиков. В разделе о кольцах мы говорили о счётчике, который постоянно увеличиватся, подобно номеру текущего такта. Тик как раз и реализует эту идею. Давайте рассмотрим примеры:
counter = 0
live_loop :arp do
play (scale :e3, :minor_pentatonic)[counter], release: 0.1
counter += 1
sleep 0.125
end
Это эквивалентно:
live_loop :arp do
play (scale :e3, :minor_pentatonic).tick, release: 0.1
sleep 0.125
end
Здесь мы просто берём минорную пентатонику, построенную от e3, и перебираем каждый элемент кольца. Это делается путём добавления .tick
в конец объявления гаммы. Тик является локальным для живого цикла, поэтому каждый живой цикл может иметь свой собственный, независимый тик:
live_loop :arp do
play (scale :e3, :minor_pentatonic).tick, release: 0.1
sleep 0.125
end
live_loop :arp2 do
use_synth :dsaw
play (scale :e2, :minor_pentatonic, num_octaves: 3).tick, release: 0.25
sleep 0.25
end
Вы также можете вызвать tick
как стандартную функцию и использовать возвращаемое ею значение в качестве индекса:
live_loop :arp do
idx = tick
play (scale :e3, :minor_pentatonic)[idx], release: 0.1
sleep 0.125
end
Однако, гораздо изящнее вызывать .tick
в конце объявления кольцевого списка. Функция tick
полезна, когда вы хотите сделать что-то необычное с величиной тика или, если нужно, использовать тики для чего-то отличного от индексирования в кольцах.
Магическая особенность тика заключается в том, что он не только возвращает новый индекс (или элемент кольцевого списка по этому индексу), он также гарантирует, что в следующий раз, когда вы вызовете тик, вы получите следующее значение. Посмотрите примеры для функции tick
в разделе “Язык” документации, чтобы узнать о различных способах работы с ней. Впрочем, сейчас необходимо отметить, что иногда вам захочется просто посмотреть на текущее значение тика и не увеличивать его. Это доступно с помощью Функции look
. Вы можете вызвать look
как стандартную функцию путем добавления .look
в конец кольцевого списка.
Наконец, иногда вам может потребоваться использовать более одного тика внутри живой петли. Это достигается путем предоставления вашему тику имени:
live_loop :arp do
play (scale :e3, :minor_pentatonic).tick(:foo), release: 0.1
sleep (ring 0.125, 0.25).tick(:bar)
end
Здесь мы используем два тика - один для игры нот, другой для времени сна. Так как они оба находятся в одной и той же живой петле, чтобы держать их раздельно, нам нужно дать им уникальные имена. Это тот же самое, что и именование live_loop
- мы просто передаем функции аргумент с префиксом :
. В примере выше мы назвали один тик :foo
а другой :bar
. Если мы хотим применить функцию look
к одному из тиков, нам нужно передать имя тика функции look
.
Большая часть мощности системы тиков не будет полезной, пока вы ещё только начинаете осваивать Sonic Pi. Не пытайтесь сразу выучить всё в этом разделе. Просто сосредоточьтесь на одном тике для одного кольца. Это даст вам больше радости и простоты применения тиков для колец в твоих live_loop
.
Взгляните на документацию для функции tick
, там много полезных примеров. Счастливых тиков!
Часто полезно иметь информацию, которая является общей для нескольких потоков или живых циклов. Например, тебе может понадобиться сделать общими значение текущей тональности, BMP или даже более отвлеченные понятия такие как текущая ‘сложность’ (которая может быть интерпретирована по-разному в разных потоках). Мы также не хотим при этом потерять имеющуюся у нас гарантию определенности. Другими словами, мы все еще хотели бы иметь возможность делиться кодом с другими и точно знать, что они услышат, когда запустят его. В конце Раздела 5.6 этого руководства мы кратко обсудили, почему мы не должны использовать переменные для обмена информацией между потоками чтобы не потерять фактор детерминизма (из-за гонки состояний).
Sonic Pi решает проблему доступности работы с глобальными переменными детерминистским способом через новаторскую систему, названную Time State (Состояние времени). Это может звучать сложно и трудно (и на самом деле, в Великобритании программирование с несколькими потоками и разделяемой памятью, как правило, является предметом университетского уровня). Однако, как вы увидите, что так же, как и сыграть вашу первую ноту, Sonic PI сделает обмен состоянием между потоками невероятно простым, в то же время сохраняя ваш код потоко-безопасными и детерминированными.
Встречайте get
и set
…
Sonic PI имеет глобальное хранилище памяти, называемое Временным состоянием. В основном оно используется чтобы “установить” (set) информацию и “получить” (get) информацию. Давайте нырнем глубже…
Чтобы хранить информацию во Временном Состоянии нам нужны две вещи:
информация, которую мы хотим сохранить, уникальное имя (ключ) для этой информации.
Например, мы можем захотеть сохранить число 3000
с ключом :intensity
. Это можно сделать используя функцию set
:
set :intensity, 3000
Мы можем дать ключу любое имя. Если какая-то информация уже хранится под этим именем, наш новый set
перезапишет её:
set :intensity, 1000
set :intensity, 3000
В примере выше, где мы сохранили оба числа под одним ключом, последний вызов set
‘побеждает’, поэтому число связанное с :intensity
будет равно 3000
, так как первый вызов ‘set’ эффективно перезаписан.
Для извлечения информации из Временного Состояния нам просто нужен ключ, который мы использовали в set
, в нашем случае это :intensity
. Тогда нам просто нужно вызвать get[:intensity]
, результат которого выведем на экран:
print get[:intensity] #=> выведет 3000
Обратите внимание, что запросы get
могут возвращать информацию, которая была записана в set
в предыдущем запуске исполнения кода. После того, как часть информации была записана в set
, она становится доступной до тех пор, пока она либо не будет переопределена (точно так же, как мы переопределили значение:intensity
от 1000
к ` 3000`), либо Sonic Pi не будет закрыт.
Основное преимущество системы Time State заключается в том, что ее можно безопасно использовать в потоках или в живых циклах. Например, у вас может быть сделана установка для одного живого цикла, а другой может ее получить:
live_loop :setter do
set :foo, rrand(70, 130)
sleep 1
end
live_loop :getter do
puts get[:foo]
sleep 0.5
end
Хорошая вещь об использовании get
и set
в потоках, подобных этому, заключается в том, что всегда будет выдаваться один и тот же результат всякий раз, когда вы запускаете исполнение кода. Попробуйте этом, и посмотрите, есть ли в вашем журнале следующее:
{run: 0, time: 0.0}
└─ 125.72265625
{run: 0, time: 0.5}
└─ 125.72265625
{run: 0, time: 1.0}
└─ 76.26220703125
{run: 0, time: 1.5}
└─ 76.26220703125
{run: 0, time: 2.0}
└─ 114.93408203125
{run: 0, time: 2.5}
└─ 114.93408203125
{run: 0, time: 3.0}
└─ 75.6048583984375
{run: 0, time: 3.5}
└─ 75.6048583984375
Попробуйте запустить этот код несколько раз - видите, результат одинаков каждый раз. Это то, что мы называем детерминированным поведением, и это действительно очень важно, когда мы хотим поделиться своей музыкой в виде кода и знать, что человек, играющий код, слышит именно то, что мы хотели, чтобы он услышал (точно так же, как воспроизведение MP3 или интернет-стрим звучат одинаково для всех слушателей).
В разделе 5.6 мы обсуждали, почему использование переменных в потоках может привести к случайному поведению. Это лишает нас возможности надежно воспроизводить код, такой как этот:
## Пример недетерминированного поведения
## (из-за гонки состояний, вызванной несколькими
## живыми циклами, манипулирующими одной и той же переменной
## в одно и то же время).
##
## Если вы запустите этот код, вы заметите
## что список, отображаемый в журнале
## не всегда сортируется!
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
a = a.shuffle
sleep 0.5
end
live_loop :sorted do
a = a.sort
sleep 0.5
puts "sorted: ", a
end
Давайте посмотрим, как это может выглядеть, используя get
и set
:
## Пример детерминированного поведения
## (несмотря на одновременный доступ к общему состоянию)
## используя новую систему Time State от Sonic Pi.
##
## Когда этот код выполняется, список,
## отображаемый в журнале, всегда отсортирован!
set :a, (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
set :a, get[:a].shuffle
sleep 0.5
end
live_loop :sorted do
set :a, get[:a].sort
sleep 0.5
puts "sorted: ", get[:a]
end
Обратите внимание, что этот код в значительной степени идентичен версии, использующей переменную. Однако когда вы запускаете код, он ведет себя так, как вы ожидаете с любым типичным кодом Sonic Pi - * он делает то же самое каждый раз * в этом случае благодаря системе Time State.
Поэтому, когда вы делитесь информацией между живыми циклами и потоками, используйте get
и set
вместо переменных для детерминированного, воспроизводимого поведения.
В разделе 5.7, при рассмотрении проблемы синхронизации потоков, были представлены функции cue
и sync
То, что там не было разъяснено, это система Time State, которая обеспечивает эту функциональность. Так случилось, что функцияset
на самом деле является вариацией cue
и устроена поверх той же базовой функциональности, которая заключается в сообщении информации системе Time State. Кроме того, функция sync
также спроектирована таким образом, чтобы бесперебойно работать с Time State - любую информацию, которую мы планируем хранить в Time State, мы можем синхронизировать с ее помощью. Другими словами - * мы применяем функциюsync
к событиям, которые еще только предстоит сообщить системе Time State *.
Давайте кратко рассмотрим, как использовать sync
для ожидания новых событий, которым предстоит быть добавленными в Time State:
in_thread do
sync :foo
sample :ambi_lunar_land
end
sleep 2
set :foo, 1
В этом примере мы сначала создаем поток, который ожидает в дальнейшем добавления события : foo
в Time State. После этого, мы “спим” 2 такта, а затем посредством функции set
устанавливаем для : foo
значение 1
. Это определяет функцию sync
, которая в следующей строке воспроизводит сэмпл: ambi_lunar_land
.
Обратите внимание, что sync
всегда ожидает * будущих событий * и блокирует текущий поток в ожидании нового события. Кроме того, он унаследует логическое время потока, который запустил его через set
или cue
, поэтому его также можно использовать для синхронизации времени.
В приведенном выше примере мы установили для : foo
значение 1
, с которым ничего не сделали. На самом деле мы можем получить это значение из sync
, вызывающего поток:
in_thread do
amp = sync :foo
sample :ambi_lunar_land, amp: amp
end
sleep 2
set :foo, 0.5
Обратите внимание, что значения, которые передаются через set
и cue
, должны быть потокобезопасными - то есть кольца, числа, символы или замороженные строки не должны изменяться. Sonic Pi выдаст ошибку, если значение, которое вы пытаетесь сохранить в Time State, недопустимо.
При получении и установке информации в Time State можно использовать более сложные ключи, чем основные символы, такие как : foo
и: bar
. Вы также можете использовать строки в стиле URL, которые называются пути (paths), например " / foo / bar / baz "
. Как только мы начнем работать с путями, мы сможем воспользоваться преимуществами реализованной в Sonic Pi сложной системы сопоставления паттернов для того, чтобы пользоваться функциями get
и sync
с похожими, а не с полностью идентичными путями. Давайте взглянем на это.
Предположим, что мы хотим дождаться следующего события, которое имеет три сегмента пути:
sync "/*/*/*"
Это будет сопоставимо с любым событием Time State с тремя сегментами пути, независимо от их имен. Например:
cue "/foo/bar/baz"
cue "/foo/baz/quux"
cue "/eggs/beans/toast"
cue "/moog/synths/rule"
Однако он * не будет * сопоставляться с путями с меньшим или большим количеством сегментов. Следующие пути не будут сопоставляться:
cue "/foo/bar"
cue "/foo/baz/quux/quaax"
cue "/eggs"
Каждый символ *
означает * любой контент *. Таким образом, мы можем сопоставлять между собой пути с одним сегментом с / *
или пути с пятью сегментами с / * / * / * / * / *
Если мы знаем, с чего начинается или заканчивается сегмент, мы можем использовать *
в дополнение к частичному имени сегмента. Например: " / foo / b * / baz "
будет соответствовать любому пути, который имеет три сегмента, первый из которых foo
, последний baz
, а средний сегмент может быть любым, начинающимся с b
. Таким образом, с этим будут сопоставимы следующие пути:
cue "/foo/bar/baz"
cue "/foo/baz/baz"
cue "/foo/beans/baz"
Однако, не будут сопоставимы следующие пути:
cue "/foo/flibble/baz"
cue "/foo/abaz/baz"
cue "/foo/beans/baz/eggs"
Вы также можете поместить *
в начале сегмента, чтобы указать последние символы сегмента: " / foo / * zz / baz "
, который будет соответствовать любым 3 сегментам cue
или set
, где первый сегмент - foo
, последний - baz
, а средний сегмент заканчивается zz
, например "cue" / foo / whizz / baz "
.
Иногда вы не знаете, сколько сегментов пути вы хотите сопоставить. В этих случаях вы можете использовать возможности двойной звезды: **
, например " / foo / ** / baz "
. Тогда это будет сопоставимо с:
cue "/foo/bar/baz"
cue "/foo/bar/beans/baz"
cue "/foo/baz"
cue "/foo/a/b/c/d/e/f/baz"
Вы можете использовать символ ?
для сопоставления с одним символом. Например " /? оo / bar / baz "
, что будет сопоставимо с:
cue "/foo/bar/baz"
cue "/goo/bar/baz"
cue "/too/bar/baz"
cue "/woo/bar/baz"
Если вы знаете, что сегмент может быть представлен словом из заданного набора, вы можете использовать сопоставители {
и }
, чтобы указать список вариантов. Например `” / foo / {bar, beans, eggs} / quux “, что может быть сопоставлено только со следующим:
cue "/foo/bar/quux"
cue "/foo/beans/quux"
cue "/foo/eggs/quux"
Наконец, вы можете сопоставить сегмент из набора букв, если используете сопоставители [
и ]
, чтобы указать список вариантов. Например путь " / foo / [abc] ux / baz "
будет сопоставим только с:
cue "/foo/aux/baz"
cue "/foo/bux/baz"
cue "/foo/cux/baz"
Вы также можете использовать символ -
для указания диапазонов букв. Например, " / foo / [a-e] ux / baz "
будет сопоставим только с:
cue "/foo/aux/baz"
cue "/foo/bux/baz"
cue "/foo/cux/baz"
cue "/foo/dux/baz"
cue "/foo/eux/baz"
При вызове sync
или get
вы можете комбинировать сопоставители в любом порядке, который вы считаете подходящим для сопоставления любому событию Time State, заданному с помощью cue
или set
. Давайте рассмотрим потрясающий пример:
in_thread do
sync "/?oo/[a-z]*/**/ba*/{quux,quaax}/"
sample :loop_amen
end
sleep 1
cue "/foo/beans/a/b/c/d/e/bark/quux/"
Для тех, кому интересно, эти правила сопоставления основаны на спецификации сопоставления паттернов протокола Open Sound Control. Подробности описаны здесь: http://opensoundcontrol.org/spec-1_0
После того, как вы освоите преобразование кода в музыку, вы можете задаться вопросом - что дальше? Иногда ограничения работы исключительно в рамках синтаксиса и звуковой системы Sonic Pi могут быть захватывающими и перенести вас на новый творческий уровень. Однако иногда важно вырваться из кода в реальный мир. Мы хотим две дополнительные вещи:
Иметь возможность преобразовывать действия в реальном мире в события Sonic Pi с помощью кода Иметь возможность использовать сильную временную модель и семантику Sonic Pi для управления и манипулирования объектами в реальном мире
К счастью, есть протокол, существующий с 80-х годов, который обеспечивает именно такое взаимодействие - MIDI. Существует невероятное количество внешних устройств, включая клавиатуры, контроллеры, секвенсоры и профессиональные аудио-приложения, которые поддерживают MIDI. Мы можем использовать MIDI для получения данных, а также использовать его и для отправки данных.
Sonic Pi обеспечивает полную поддержку протокола MIDI, позволяя вам подключить ваш живой код к реальному миру. Давайте исследуем это поглубже …
В этом разделе мы узнаем, как подключить MIDI-контроллер для отправки событий в Sonic Pi для управления нашими синтезаторами и звуками. Хватай свою MIDI-клавиатуру или контроллер, и начнем работать физически!
Чтобы получить информацию с внешнего MIDI-устройства в Sonic Pi, нам сначала нужно подключить ее к нашему компьютеру. Как правило, это происходит через USB порт, хотя старое оборудование будет иметь 5-контактный разъем DIN, для которого вам потребуется аппаратная поддержка вашего компьютера (например, некоторые звуковые карты имеют разъемы MIDI DIN). После подключения устройства запустите Sonic Pi и загляните в раздел IO на панели «Настройки». Вы должны увидеть там в списке ваше устройство. Если его нет, попробуйте нажать кнопку «Reset MIDI» и посмотреть, появится ли оно. Если вы по-прежнему ничего не видите, то попробуйте обратиться к конфигурации MIDI в вашей операционной системы, чтобы уточнить, доступно ли она ваше устройство там. В противном случае, не стесняйтесь задавать вопросы в публичном чате: http://gitter.im/samaaron/sonic-pi
Как только ваше устройство подключено, Sonic Pi будет автоматически получать от него события. Вы можете убедиться в этом сами, манипулируя вашим MIDI-устройством и поглядывая в регистратор сигналов в правом нижнем углу, под журналом (если его не видно, перейдите в «Настройки» -> «Редактор» -> «Показать/Скрыть» и включите «Показать журнал сигналов»). Вы увидите поток событий, таких как:
/midi:nanokey2_keyboard:0:1/note_off [55, 64]
/midi:nanokey2_keyboard:0:1/note_on [53, 102]
/midi:nanokey2_keyboard:0:1/note_off [57, 64]
/midi:nanokey2_keyboard:0:1/note_off [53, 64]
/midi:nanokey2_keyboard:0:1/note_on [57, 87]
/midi:nanokey2_keyboard:0:1/note_on [55, 81]
/midi:nanokey2_keyboard:0:1/note_on [53, 96]
/midi:nanokey2_keyboard:0:1/note_off [55, 64]
Как только вы увидите поток таких сообщений, вы успешно подключили ваше MIDI-устройство. Поздравляем! Давайте посмотрим, что мы можем с этим сделать!
Эти события разбиты на два раздела. Во-первых, есть имя события, например /midi:nanokey2_keyboard:0:1/note_on
, а во-вторых, есть значения события, такие как [18, 62]
. Интересно, что это две вещи, которые нам нужны для хранения информации в Time State. * Sonic Pi автоматически вставляет входящие события MIDI в Time State *. Это означает, что вы можете использовать get
, чтобы получить последнее значение MIDI, а также использоватьsync
для ожидания следующего MIDI значения, применяя все, что мы узнали в разделе 10 этого руководства.
Теперь мы подключили MIDI-устройство, увидели его события в журнале и обнаружили, что наше знание Time State - это все, что нам нужно для работы с этими событиями, теперь мы можем начать веселиться. Давайте создадим простое MIDI-пианино:
live_loop :midi_piano do
note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
synth :piano, note: note
end
В приведенном выше коде происходит несколько вещей, включая некоторые проблемы. Во-первых, у нас есть простой live_loop
, который будет постоянно повторять код, выполняемый в блоке внутри ` do /
end. Это было дано разъяснение в Разделе 9.2. Во-вторых, мы применяем
sync для ожидания следующего подходящего для сопоставления события Time State. Мы используем строку, определяющую MIDI-сообщение, которое мы ждем (и которое совпадает с отображением в журнале событий). Обратите внимание, что эта длинная строка пдставояется вам системой автозаполнения Sonic Pi, так что вам не нужно печатать все вручную. В журнале мы увидели, что для каждого MIDI note on события было два значения, поэтому мы присваиваем результат двум отдельным переменным
note и
velocity. Наконец, мы запускаем синтезатор
: piano`, передавая ему нашу ноту.
Теперь попробуйте сами. Введите приведенный выше код, замените ключ синхронизации строкой, соответствующей вашему конкретному MIDI-устройству, и нажмите Выполнить. Вуаля, у вас есть пианино! Однако вы, вероятно, заметите пару проблем: во-первых, все ноты имеют одинаковую громкость независимо от того, как сильно вы нажимаете на клавиатуру. Это можно легко исправить преобразовав значение MIDI velocity в амплитуду звукового сигнала. Учитывая, что MIDI имеет диапазон 0-> 127, чтобы преобразовать это число в значение между 0-> 1, нам просто нужно разделить его на 127:
live_loop :midi_piano do
note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
synth :piano, note: note, amp: velocity / 127.0
end
Обновите код и снова нажмите «Выполнить». Теперь зависимость громкости от скорости нажатия клавиш на клавиатуре соблюдается. Далее, давайте избавимся от этой досадной паузы.
Прежде чем мы сможем убрать эту паузу, нам нужно знать, почему она возникает. Чтобы обеспечить своевременную синхронизацию всех синтезаторов и эффектов на различных процессорах с различными возможностями, Sonic Pi по умолчанию планирует запуск аудио *заранее * на 0,5 секунды. (Обратите внимание, что эта дополнительная задержка может быть настроена через fns set_sched_ahead_time!
и use_sched_ahead_time
). Эта задержка 0,5 секунды добавляется и к нашим триггерам синтезатора : piano
, поскольку она добавляется ко всем синтезаторам, запускаемым Sonic Pi. Как правило, мы действительно хотим добавить дополнительную задержку, поскольку это означает, что все синтезаторы будут рассчитаны вовремя. Однако это имеет смысл только для синтезаторов, запускаемых кодом с использованием play
и sleep
. В нашем случае мы фактически запускаем синтезатор : piano
с помощью внешнего MIDI-устройства и поэтому не хотим, чтобы Sonic Pi контролировал время за нас. Мы можем отключить эту задержку с помощью команды use_real_time
, которая отключает задержку для текущего потока. Это означает, что вы можете использовать режим реального времени для живых циклов, чье время контролируется путем синхронизации
с внешними устройствами, и сохранять задержку по умолчанию для всех других живых циклов. Давайте взглянем на это:
live_loop :midi_piano do
use_real_time
note, velocity = sync "/midi:nanokey2_keyboard:0:1/note_on"
synth :piano, note: note, amp: velocity / 127.0
end
Обновите код, чтобы он соответствовал приведенному выше, и снова нажмите «Выполнить». Теперь у нас есть пианино с низкой задержкой и переменной скоростью, кодируемое всего за 5 строк. Это было не так уж и просто!
Наконец, поскольку наши MIDI-события идут прямо в Time State, мы также можем использовать функцию get
для получения последнего значения. Это не блокирует текущий поток и не возвращает nil
, если не найдено никакого значения (которое вы можете переопределить, передав значение по умолчанию - смотрите документацию по get
). Помните, что вы можете вызвать get
в любом потоке в любое время, чтобы увидеть последнее соответствующее значение Time State. Вы даже можете использовать time_warp
, чтобы вернуться назад во времени, вызвать get
и увидеть прошедшие события …
Самое захватывающее то, что теперь вы можете использовать одни и те же структуры кода для вызова функций sync
и get
в отношении MIDI-информации с любого MIDI-устройства и выполнения в дальнейшем любых действий с полученными значениями. Теперь вы можете выбирать, что будет делать ваше MIDI-устройство!
В дополнение к получению MIDI-событий мы также можем отправлять MIDI-события для запуска и управления внешними аппаратными синтезаторами, клавиатурами и другими устройствами. Sonic Pi предоставляет полный набор функций для отправки различных MIDI-сообщений, таких как:
Note on - midi_note_on
Note off - midi_note_off
Control change - midi_cc
Pitch bend - midi_pitch_bend
Clock ticks - midi_clock_tick
Также есть много других поддерживаемых MIDI-сообщений - ознакомьтесь с документацией API для остальных функций, начинающихся с midi_
.
Чтобы отправить MIDI-сообщение на внешнее устройство, мы должны сначала подключить его. Ознакомьтесь с подразделом «Подключение MIDI-контроллера» в разделе 11.1 для получения более подробной информации. Обратите внимание, что если вы используете USB, подключение к устройству, на которое вы отправляете сообщение (а не получаете от него), является той же процедурой. Однако, если вы используете классические DIN-разъемы, убедитесь, что вы подключены к MIDI-выходу вашего компьютера. Вы должны увидеть ваше MIDI-устройство в списке в панели настроек.
Многие midi_ *
функции работают так же, как play
, sample
и synth
, так как они отправляют сообщение в текущее (логическое) время. Например, чтобы распределить вызовы функций midi_ *
, вам нужно использовать sleep
, как вы это делали с play
. Давайте взглянем:
midi_note_on :e3, 50
Это отправит событие MIDI-note on на подключенное MIDI-устройство со скоростью нажатия клавиши 50. (Обратите внимание, что Sonic Pi автоматически преобразует ноты в форме : e3
в соответствующий им номер MIDI, например, 52)
Если подключенное MIDI-устройство является синтезатором, вы должны услышать, как он воспроизводит ноту. Чтобы отключить ноту, используйте midi_note_off
:
midi_note_off :e3
По умолчанию Sonic Pi отправляет каждое MIDI-сообщение на все подключенные устройства на всех MIDI-каналах. Это облегчает работу с одним подключенным устройством без необходимости что-либо настраивать. Однако иногда MIDI-устройство будет обрабатывать MIDI-каналы особым образом, к примеру, если каждая нота имеет отдельный канал, или же если вы подключили более одного MIDI-устройства одновременно. В более сложных настройках вашего оборудования, вы можете пожелать иметь больше возможности выбирать относительно того, какое MIDI-устройство будет получает то или иное сообщение и по какому каналу.
Посредством опции port:
и имени устройства, каким оно отображается в настройках, мы можем указать, к какому устройству желаем обратиться:
midi_note_on :e3, port: "moog_minitaur"
Мы также можем указать канал для отправки посредством опции channel:
(используя значение в диапазоне 1-16):
midi_note_on :e3, channel: 3
Конечно, мы также можем задействовать обе опции одновременно для отправки информации на конкретное устройство по определенному каналу:
midi_note_on :e3, port: "moog_minitaur", channel: 5
Наконец, действительно забавная вещь - подключить аудиовыход вашего MIDI-синтезатора к одному из аудиовходов вашей звуковой карты. Тогда вы сможете управлять синтезатором с помощью кода посредством функций midi_ *
, а также манипулировать звуком с помощью live_audio
и FX:
with_fx :reverb, room: 1 do
live_audio :moog
end
live_loop :moog_trigger do
use_real_time
midi (octs :e1, 3).tick, sustain: 0.1
sleep 0.125
end
(Функция midi
доступна в виде удобных сокращений для отправки событий note on и note off одной командой. Для получения дополнительной информации ознакомьтесь с документацией).
В дополнение к MIDI, другой способ получать и выводить информацию из Sonic Pi, но уже через сеть, предполагает использование простого протокола OSC - Open Sound Control. Это позволит вам обмениваться сообщениями с внешними программами (как работающими на вашем компьютере, так и на других компьютерах), что открывает потенциальные возможности для контроля за пределами протокола MIDI, который имеет ограничения из-за его дизайна 1980-х годов.
Например, вы можете написать программу на другом языке программирования, который отправляет и получает OSC (есть библиотеки OSC для почти всех распространенных языков) и работает непосредственно с Sonic Pi. То, для чего вы можете использовать это, ограничено только вашим воображением.
По умолчанию при запуске Sonic Pi он прослушивает порт 4560 для входящих сообщений OSC от программ на том же компьютере. Это означает, что без какой-либо дополнительной настройки вы можете отправить Sonic Pi сообщение OSC, и оно будет отображаться в журнале событий, как и входящие MIDI-сообщения. Любое входящее сообщение OSC автоматически добавляется в Time State, и вы можете использовать get
и sync
для работы с входящими данными - как с MIDI или синхронизацией live_loops
- см. Разделы 5.7 и 10.2. Вспомним, как это работает.
Давайте создадим простой OSC-слушатель:
live_loop :foo do
use_real_time
a, b, c = sync "/osc*/trigger/prophet"
synth :prophet, note: a, cutoff: b, sustain: c
end
В этом примере мы синхронизируем путь OSC, который описали как "/osc*/trigger/prophet"
. Это может быть любой допустимый путь OSC (все буквы и цифры поддерживаются, а /
используется, как и в URL-адресации, для разбиения пути на несколько слов). Префикс / osc
добавляется Sonic Pi ко всем входящим сообщениям OSC, поэтому нам нужно отправить сообщение OSC с путем / trigger / prophet
, чтобы вызванная нами функция sync
запустила синтезатор prophet.
Мы можем отправить OSC в Sonic Pi с любого языка программирования, который имеет библиотеку OSC. Например, если мы отправляем OSC из Python, мы можем сделать что-то вроде этого:
from pythonosc import osc_message_builder
from pythonosc import udp_client
sender = udp_client.SimpleUDPClient('127.0.0.1', 4559)
sender.send_message('/trigger/prophet', [70, 100, 8])
Или, если мы отправляем OSC из Clojure, мы можем сделать что-то вроде этого из REPL:
(use 'overtone.core)
(def c (osc-client "127.0.0.1" 4560))
(osc-send c "/trigger/prophet" 70 100 8)
Из соображений безопасности, по умолчанию Sonic Pi не позволяет удаленным машинам отправлять ему OSC-сообщения. Однако вы можете включить поддержку удаленных машин в Настройки-> IO-> Сетевой OSC-> Принимать удаленные сообщения OSC. Как только вы включите это, вы сможете получать сообщения OSC с любого компьютера в вашей сети. Обычно отправляющему устройству необходимо знать ваш IP-адрес (уникальный идентификатор вашего компьютера в вашей сети - например, номер телефона или адрес электронной почты). Вы можете узнать IP-адрес своего компьютера, посмотрев раздел IO на панели настроек. (Если ваш компьютер имеет более одного IP-адреса, при наведении курсора мыши на указанный адрес появится список всех известных адресов).
Обратите внимание, что некоторые программы, такие как TouchOSC для iPhone и Android, поддерживают отправку OSC в качестве стандартной функции. Так, включив опцию прослушивания входящих сообщений от удаленных машин и зная свой IP-адрес, вы можете мгновенно начать отправку сообщений из приложений, вроде TouchOSC, которые позволяют создавать собственные сенсорные элементы управления с помощью слайдеров, кнопок, валкодеров и т. Д. Это может предоставить вам огромный диапазон вариантов ввода управляющих данных.
В дополнение к получению OSC и работе с ним, используя Time State, мы также можем отправлять сообщения OSC одновременно с музыкой, исполняемой посредством нашего кода (точно так же, как мы можем одновременно с этим отправлять и MIDI-сообщения). Нам просто нужно знать, на какой IP-адрес и порт мы отправляем. Давайте попробуем:
use_osc "localhost", 4560
osc "/hello/world"
If you run the code above, you’ll notice that Sonic Pi is sending itself an OSC message! This is because we set the IP address to the current machine and the port to the default OSC in port. This is essentially the same as posting a letter to yourself - the OSC packet is created, leaves Sonic Pi, gets to the network stack of the operating system which then routes the packed back to Sonic Pi and then it’s received as a standard OSC message and is visible in the cue logger as the incoming message /osc:127.0.0.1:4560/hello/world
. (Notice how Sonic Pi automatically prefixes all incoming OSC messages with /osc
and then the hostname and port of the sender.)
Конечно, отправка сообщений OSC самому себе может быть забавной, но это не так полезно. Реальная польза начинается, когда мы отправляем сообщения в другие программы:
use_osc "localhost", 123456
osc "/hello/world"
В этом случае мы предполагаем, что есть другая программа на том же компьютере, которая прослушивает порт 123456. Если это так, то она получит сообщение OSC “/ hello / world`, с которым она сможет сделать все, что захочет.
Если наша программа работает на другом компьютере, нам нужно знать ее IP-адрес, который мы используем вместо " localhost "
:
use_osc "192.168.10.23", 123456
osc "/hello/world"
Теперь мы можем отправлять сообщения OSC на любое доступное нам устройство через наши локальные сети и даже через Интернет!
До сих пор, с точки зрения звукового производства, мы исследовали запуск синтезаторов и записанных звуков через функции play
, synth
и sample
. Затем они генерировали звук, который воспроизводился через нашу стерео систему. Тем не менее, многие компьютеры также имеют возможность ввода звука, например, через микрофон, в дополнение к возможности отправлять звук на более чем две колонки. Часто эта возможность становится доступной благодаря использованию внешней звуковой карты (существуют устройства для всех платформ). В этом разделе руководства мы рассмотрим, как мы могли бы использовать преимущества этих внешних звуковых карт и без усилий работать в Sonic Pi с несколькими каналами входящего и исходящего аудио.
Одним простым (и, должно быть, уже знакомым) способом доступа к аудио входам является использование нашего друга synth
с указанием для него пути : sound_in
:
synth :sound_in
Это будет работать так же, как и любой синтезатор, такой как «synth: dsaw», за исключением того, что сгенерированный звук будет считываться непосредственно с первого входа звуковой карты вашей системы. На ноутбуках это обычно встроенный микрофон, но если у вас есть внешняя звуковая карта, вы можете подключить любой аудиовход к первому входу.
Одна вещь, которую вы могли бы заметить, это то, что как synth: dsaw
, синтезатор: sound_in
длится всего 1 такт, поскольку к нему применяется стандартная огибающая. Если вы хотите, чтобы он звучал немного дольше, измените настройки огибающей ADSR. Например, следующий код будет ближайшие 8 тактов держать открытым аудиовход для нашего синтезатора:
synth :sound_in, sustain: 8
Конечно, как и на любой обычный синтезатор, вы можете легко накладывать на него эффекты с помощью FX-блока:
with_fx :reverb do
with_fx :distortion do
synth :sound_in, sustain: 8
end
end
Если вы подключили гитару к первому входу, вы должны услышать ее с искажением и реверберацией, пока исполняется код.
Вы можете использовать синтезатор : sound_in
одновременно столько раз, сколько вам нравится (точно так же, как вы делаете это с любым обычным синтезатором). Например, следующий код будет воспроизводить два синтезатора : sound_in
одновременно - один с искажением, а другой с реверберацией:
with_fx :distortion do
synth :sound_in, sustain: 8
end
with_fx :reverb do
synth :sound_in, sustain: 8
end
Вы можете выбрать, какой аудиовход вы хотите воспроизвести, с помощью опции input:
. Вы также можете указать стереовход (два последовательных входа), используя синтезатор : sound_in_stereo
. Например, если у вас есть звуковая карта с по крайней мере тремя входами, вы можете рассматривать первые два как стереопоток и добавлять искажения, а третий - как монопоток и добавлять реверберацию со следующим кодом:
with_fx :distortion do
synth :sound_in_stereo, sustain: 8, input: 1
end
with_fx :reverb do
synth :sound_in, sustain: 8, input: 3
end
Однако, хотя это и действенный метод, у этого подхода есть несколько ограничений. Во-первых, он работает только в течение определенного периода времени (из-за наличия огибающей ADSR), и, во-вторых, нет возможности переключать эффекты после запуска исполнения кода. Обе эти вещи являются типичными запросами при работе с внешними аудиопотоками от микрофонов, гитар и внешних синтезаторов. Поэтому мы рассмотрим предлагаемое Sonic Pi решения проблемы (потенциально) бесконечного потока живого аудиовхода: live_audio
.
Синтез : sound_in
, как описано в предыдущем разделе, предоставляет очень гибкий и знакомый метод для работы с входящим аудио. Однако, как уже говорилось, у него есть несколько проблем при работе с отдельным аудио входом в смысле отдельного инструмента (например, вашего голоса или гитары). Безусловно, лучший подход к работе с отдельным непрерывным аудиопотоком - использовать live_audio.
live_audio
разделяет с live_loop
пару основных ограничений, связанных с дизайном ядра Sonic Pi (отсюда и похожее имя). Во-первых, каждый объект такого типа должен иметь уникальное имя. Во-вторых, в любой момент времени может существовать только один поток live_audio
с таким именем. Давайте взглянем:
live_audio :foo
Этот код будет действовать подобно synth: sound_in
с некоторыми ключевыми отличиями: он работает постоянно (пока вы явно его не остановите), и вы можете перемещать его в новые FX-контексты динамически.
При первоначальном запуске, live_audio
работает с FX точно так, как вы и ожидаете. Например, чтобы запустить живой аудиопоток с добавлением реверберацией, нужно просто применить FX-блок : reverb
:
with_fx :reverb do
live_audio :foo
end
Однако, учитывая, что live_audio
работает постоянно (по крайней мере, до тех пор, пока вы его не остановите), нас сильно бы ограничило, если, как и уже известные вам обычные синтезаторы, живой аудио поток так же был бы связан с эффектом : reverb
все время своей работы. К счастью, это не тот случай, и эта функция была разработана так, чтобы было легко перемещаться между различными FX. Давай попробуем. Запустите приведенный выше код, чтобы услышать живой звук, поступающий непосредственно с первого входа вашей звуковой карты. Обратите внимание, что если вы используете ноутбук, это, как правило, ваш встроенный микрофон, поэтому рекомендуется использовать наушники, чтобы пресечь обратную связь между микрофоном и динамиками.
Теперь, пока вы все еще слышите звук в реальном времени с звуковой карты с реверберацией, измените код на следующий:
with_fx :echo do
live_audio :foo
end
Теперь нажмите Выполнить, и вы сразу услышите звук, воспроизводимый через блок эффекта эхо, вместо реверберации. Если вы хотите слышать их оба, просто отредактируйте код еще раз и нажмите Выполнить:
with_fx :reverb do
with_fx :echo do
live_audio :foo
end
end
Важно отметить, что вы можете вызывать live_audio: foo
из любого потока или живого цикла, и он будет перемещать живое аудио в текущий FX-контекст этого потока. Поэтому, для получения некоторых интересных результатов, вы можете легко иметь несколько живых циклов, вызывающих live_audio: foo
в разное время, от чего FX-контекст будет автоматически меняться.
В отличие от стандартных синтезаторов, к live_audio
не применяется огибающая, поэтому он будет работать постоянно (даже если вы удалите код, точно так же, как функция все еще определена в памяти, даже если вы удалите код в редакторе). Чтобы остановить его, вам нужно использовать аргумент : stop
:
live_audio :foo, :stop
Его можно легко перезапустить, выполнив код без аргумента : stop
:
live_audio :foo
Кроме того, все запущенные живые звуковые потоки останавливаются, когда вы нажимаете глобальную кнопку «Стоп» (это работает и для всех других исполняемых синтезаторов и эффектов).
Что касается аудиоканалов, то по умолчанию live_audio
работает аналогично синтезатору: sound_in
в том смысле, что он принимает отдельный монофонический входной аудио поток и преобразует его в стереопоток, используя заданное панорамирование. Однако, как и в случае : sound_in_stereo
, можно также указать live_audio
, читать два последовательных аудиовхода и обрабатывать их напрямую как левый и правый каналы. Это достигается через опцию : stereo
. Например, чтобы обрабатывать вход 2 как левый канал, а вход 3 - как правый канал, необходимо указать опции input:
значение 2 и включить стереорежим следующим образом:
live_audio :foo, stereo: true, input: 2
Обратите внимание, что после запуска потока живого аудио в режиме стерео вы не можете изменить его на моно без остановки и перезапуска. Точно так же, если вы запустите его в монофоническом режиме по умолчанию, вы не сможете переключиться на стерео без перезапуска потока.
До сих пор в этом разделе мы рассматривали, как получить несколько потоков аудио в Sonic Pi - это возможно либо с помощью синтезатора : sound_in
, либо с помощью мощной системы live_audio
. В дополнение к работе с несколькими потоками входного аудио, Sonic Pi также может выводить несколько аудио потоков. Это достигается с помощью FX-контектса : sound_out
.
Давайте быстро вспомним, как синтезаторы и эффекты в Sonic Pi выводят свое аудио в текущий контекст FX. Рассмотрим следующее:
with_fx :reverb do # C
with_fx :echo do # B
sample :bd_haus # A
end
end
Самый простой способ понять, что происходит с аудиопотоком, - это начать с аудио контекста, находящегося ближе всего к центру блока, и двигаться от него наружу. В этом случае самый внутренний контекст, представляющий собой исполняемый сэмпл: bd_haus
, пометим как A
. Аудио из него идет напрямую в его контекст, который назовем B
- это эффект: echo
. Это добавляет эхо к входящему аудио и выводит его в его контекст C
- эффект : reverb
. Затем к входящему потоку аудио добавляется реверберация и он выводится в контекст, который является самым верхним уровнем - это левый и правый динамики (выходы 1 и 2 на вашей звуковой плате). Аудио движется от начала до выхода на динамики, будучи на всем протяжении стереофоническим потоком.
Вышеуказанное поведение верно для всех синтезаторов (включая live_audio
) и большинства эффектов за исключением: sound_out
. FX-контектс : sound_out
делает две вещи. Во-первых, он выводит звук во внешний контекст по отношению к себе контекст, как описано выше. Во-вторых, он * также * выводит звук напрямую на выход звуковой карты. Давайте взглянем на это:
with_fx :reverb do # C
with_fx :sound_out, output: 3 do # B
sample :bd_haus # A
end
end
В этом примере наш сэмпл : bd_haus
выводит свое аудио во внешний контекст, который является FX-контекстом : sound_out
. Это в свою очередь выводит звук далее во внешний FX-контекст : reverb
(как и ожидалось). Однако он * также * выводит монофонический микс на 3-й выход звуковой карты системы. Поэтому звук, сгенерированный внутри : sound_out
, имеет два назначения - FX-контекст : reverb
и выход звуковой карты 3.
Как мы уже видели, по умолчанию FX-контекст : sound_out
выводит монофонический микс стереовхода на определенный канал в дополнение к передаче стереофонического канала во внешний контекст (как и ожидалось). Если вывод моно микса не совсем то, что вы хотите сделать, есть ряд альтернативных вариантов. Во-первых, используя опцию mode:
, вы можете задать вывод только левого или только правого входного сигнала на звуковую карту. Или вы можете использовать FX-контекст : sound_out_stereo
для вывода аудио на два последовательных выхода звуковой карты. Смотрите документацию функций для получения дополнительной информации и примеров их работы.
Как мы также видели, поведение по умолчанию для : sound_out
и: sound_out_stereo
заключается в отправке аудио как во внешний контекст (что типично для всех эффектов), так и * на указанный выход на вашей звуковой карте. Однако иногда вам может потребоваться * только * отправить аудио на выход звуковой карты, а не во внешний контекст (, следовательно, без микширования и передачи аудио на стандартные выходные каналы 1 и 2). Это возможно при использовании стандартной опции FX-контекста amp:
, который работает с аудио *после того, как FX-контекст смог бы на это аудио повлиять:
with_fx :sound_out, output: 3, amp: 0 do # B
sample :loop_amen # A
end
В приведенном выше примере сэмпл : loop_amen
отправляется во внешний FX-контекст : sound_out
. Затем он отправляет монофонический микс на выход 3 звуковой карты, а затем умножает звук на 0, что, по сути, приводит к его отключению. Именно этот заглушенный сигнал затем отправляется во внешний контекст : sound_out
, который является стандартным выходом. Поэтому с этим кодом выходные каналы по умолчанию не будут принимать никакого звука, а 3-й канал получит монофонический микс из amen drum break.
На этом вводное руководство Sonic Pi завершено. Надеюсь, вы чему-то научились на этом пути. Не беспокойтесь, если вы чувствуете, что не все поняли - просто играйте и развлекайтесь, и вы доберете недостающее в свое время. Не стесняйтесь возвращаться к этому руководству, когда у вас возникает вопрос, который мог быть рассмотрен в одном из разделов.
Если у вас есть какие-либо вопросы, которые не были рассмотрены в этом руководстве, переходите на [форумы Sonic Pi] (http://groups.google.com/group/sonic-pi/) и задавайте свои вопросы там. Вы обязательно найдете там кого-нибудь, кто дружелюбно протянет вам руку помощи.
Наконец, я также приглашаю вас более подробно ознакомиться с остальной документацией в справочной системе. Существует ряд функций, которые не были рассмотрены в этом руководстве, и которые еще ожидают быть открытыми вами.
Так что играйте, веселитесь, делитесь своим кодом, выступайте для друзей, показывайте свои экраны и помните:
Здесь нет ошибок, только возможности.
В Приложении A собраны статьи о Sonic Pi, выходившие в журнале MagPi.
Эти статьи не были задуманы для чтения в каком-либо определённом порядке и содержат много перекрёстных ссылок на материалы из разных глав этого учебника. Вместо того, чтобы пытаться рассказать вам обо всём в Sonic Pi, эти статьи фокусируются на определённом аспекте и подают это в весёлой и доступной форме.
Вы можете прочесть эти статьи в великолепном, профессионально оформленном виде, бесплатно загрузив их в формате PDF из MagPi
Если вы не находите интересующую вас тему в этих статьях - почему бы не предложить свою? Самый простой способ сделать это - твитнуть в @Sonic_Pi. Кто знает, возможно предложенная вами тема станет предметом следующей статьи!
Самый главный урок в обучении работе с Sonic Pi заключается в том, что здесь действительно нет ошибок. Лучший способ узнать это - пробовать, пробовать и ещё раз пробовать. Перестаньте беспокоиться о том, звучит ли ваш код хорошо или нет, и начните экспериментировать с как можно большим количеством различных синтезаторов, нот, эффектов и параметров. Вы откроете для себя множество вещей, которые заставят вас смеяться, потому что они звучат просто ужасно, но некоторые - настоящие жемчужины, звучащие просто потрясающе. Просто отбросьте то, что не нравится, и продолжайте делать то, что делаете. Чем больше “ошибок” вы позволите себе совершить, тем быстрее вы научитесь и откроете ваш собственный уникальный звук.
Допустим, вы уже освоили основы создания звука в Sonic Pi с помощью sample
и play
. Что дальше? Знаете ли вы, что Sonic Pi поддерживает более 27 студийных эффектов для изменения звучания вашего кода? Эффекты похожи на причудливые фильтры изображений в графических редакторах, за исключением того, что вместо размытия или замены чего-то цветного чёрно-белым, вы можете использовать в своём звуке такие вещи, как реверберация, искажения и эхо. Думайте об этом, как о подключении кабеля от вашей гитары к педали эффектов, которую вы выбрали, а затем к усилителю. К счастью, Sonic Pi делает использование эффектов очень простым и не требует никаких проводов! Всё что вам нужно сделать - это выбрать, какой именно фрагмент кода вы бы обработали эффектом, и поместить его в FX-контекст. Давайте рассмотрим пример. Предположим, у вас есть следующий код:
sample :loop_garzul
16.times do
sample :bd_haus
sleep 0.5
end
Если вы хотите добавить эффект к сэмплу :loop_garzul
, просто поместите его внутрь блока with_fx
, как здесь:
with_fx :flanger do
sample :loop_garzul
end
16.times do
sample :bd_haus
sleep 0.5
end
Теперь, если вы захотите добавить эффект к басовому барабану, оберните его with_fx
тоже:
with_fx :flanger do
sample :loop_garzul
end
with_fx :echo do
16.times do
sample :bd_haus
sleep 0.5
end
end
Помните, вы можете обернуть любой код в with_fx
, и любые созданные вами звуки будут проходить через выбранный эффект.
Для того, чтобы по-настоящему раскрыть свой звук в коде, вы довольно скоро захотите узнать, как модифицировать и контролировать синтезаторы и эффекты. Например, вы можете изменить длительность ноты, добавить больше реверберации или изменить время между отражениями эхо. К счастью, Sonic Pi дает вам удивительный уровень контроля, чтобы сделать это посредством т.н. необязательных параметров или сокращенно - опций. Давайте взглянем на них. Скопируйте этот код в рабочую область и нажмите Выполнить:
sample :guit_em9
О, прекрасный звук гитары! Теперь давайте поиграем с ним. Как насчёт изменения скорости?
sample :guit_em9, rate: 0.5
Эй, что это за rate: 0.5
я добавил в конце? Это называется параметр. Все синтезаторы и эффекты в Sonic Pi поддерживают их, и их тут множество. Они также доступны и для эффектов. Попробуйте это:
with_fx :flanger, feedback: 0.6 do
sample :guit_em9
end
Теперь, попробуйте увеличить обратную связь до 1, чтобы услышать какие-то сумасшедшие звуки! Читайте документацию для получения полной информации о всем доступном для вас множестве параметров.
Лучший способ начать быстро экспериментировать и исследовать Sonic Pi - кодирование в реальном времени. Это означает, что вы начинаете выполнять какой-то код, постоянно изменяя и подправляя его в то время, как он звучит. Например, если вы не знаете, что делает с сэмплом параметр частоты среза фильтра, просто играйте его по кругу и экспериментируйте. Давайте пробовать! Скопируйте этот код в буфер вашего Sonic Pi:
live_loop :experiment do
sample :loop_amen, cutoff: 70
sleep 1.75
end
Теперь, нажмите “Выполнить” и вы будете слышать чуть приглушенный барабанный брейк. Измените значение cutoff:
на 80
и нажмите “Выполнить” снова. Слышите разницу? Попробуйте 90
, 100
, 110
…
Как только вы зависните с live_loop
, вы уже никогда не вернётесь обратно. Всякий раз, когда я делаю лайвкодинг гиг, я завишу от live_loop
так, как ударник зависит от своих палочек. Для получения дополнительной информации о лайвкодинге, смотрите раздел 9, встроенного руководства.
Наконец, ещё одна вещь, которую я люблю делать, это давать Sonic Pi сочинять за меня музыку. Действительно крутой способ сделать это - использовать рандомизацию. Это может показаться сложным, но на самом деле это не так. Давайте проверим. Скопируйте это в свободное рабочее пространство:
live_loop :rand_surfer do
use_synth :dsaw
notes = (scale :e2, :minor_pentatonic, num_octaves: 2)
16.times do
play notes.choose, release: 0.1, cutoff: rrand(70, 120)
sleep 0.125
end
end
Когда вы запустите это, вы услышите постоянный поток случайных нот гаммы :Е2 :minor_pentatonic
, сыгранных синтезатором :dsaw
. “Подожди, подожди! Это не мелодия”, слышу я ваш возглас! Ну, это только первая часть волшебного трюка. Каждый раз, когда мы проходим круг цикла live_loop
, мы можем сказать Sonic Pi сбросить случайный поток к уже известной начальной точке. Это как если бы возвращаться во времени в ТАРДИС с Доктором (см. британский телесериал «Доктор Кто») в определённую точку в пространстве и времени. Давайте попробуем это - добавьте строку use_random_seed 1
к live_loop
:
live_loop :rand_surfer do
use_random_seed 1
use_synth :dsaw
notes = (scale :e2, :minor_pentatonic, num_octaves: 2)
16.times do
play notes.choose, release: 0.1, cutoff: rrand(70, 120)
sleep 0.125
end
end
Теперь каждый раз, когда цикл live_loop
повторяется, случайный поток будет сброшен у началу. Это значит, что он выбирает одни и те же 16 нот каждый раз. Вуаля, мелодия в один миг! А теперь действительно захватывающая вещь. Измените значение отправной точки с 1
на другое число. Скажем, 4923
. Ого! Другая мелодия! Так, просто изменяя одну цифру (отправную точку), вы можете открыть столько мелодических комбинаций, сколько только сможете себе представить! Это и есть магия кода.
Лазерные лучи пронзают клубы дыма, одновременно с тем, как сабвуфер проталкивает бас глубоко в толпу людей. Атмосфера наполнена пьянящей смесью синтезаторов и танцев. Однако что-то не совсем привычное происходит в этом ночном клубе. Над диджейской будкой, двигаясь, танцуя, и перемигиваясь в ярких цветах, проецируется футуристический текст. Но это не какие-то причудливые визуальные эффекты, — это проекция Sonic Pi, запущенного на Raspberry Pi. А находящийся на стенде диджея не крутит диски, — он пишет и редактирует код. Вживую. Это лайвкодинг.
Это может звучать как притянутая за уши история из футуристичного ночного клуба, но кодирование музыки - это развивающийся тренд, часто называемый Лайвкодинг (http://toplap.org). Одним из новых направлений этого способа создания музыки является Алгорэйв (http://algorave.com) - мероприятие, где такие артисты как я, кодируют музыку для танцующих людей. Однако, вам не надо быть в ночном клубе, чтобы кодировать в реальном времени - с Sonic Pi v2.6+ вы можете делать это в любом месте, в которое сможете взять ваш Raspberry Pi и пару наушников или колонок. Как только вы дойдёте до конца этой статьи, вы будете программировать свой собственный бит и изменять его вживую. То, где вы окажетесь после этого, может быть ограничено только вашим воображением.
Ключ к лайвкодингу с Sonic Pi - овладение циклами live_loop
. Давайте посмотрим на один из них:
live_loop :beats do
sample :bd_haus
sleep 0.5
end
Есть 4 основные составляющие циклов live_loop
. Первая - это имя. Наш live_loop
называется :beats
. Вы вольны называть свой live_loop
так, как вам угодно. Не стесняйтесь подходить к этому творчески. Обычно я использую имена циклов, что-то говорящие об их роли музыке, которую они исполняют. Вторая составляющая - это слово do
, которое отмечает, где цикл начинается. Третья составляющая - слово end
, которое отмечает, где цикл заканчивается. И, наконец, есть тело цикла live_loop
, которое описывает то, что конкретно повторяет цикл - это часть кода между do
и end
. В данном случае мы многократно воспроизводим сэмпл бас бочки и ждём половину такта. Это производит приятный регулярный ритм. Скопируйте этот код в свободный буфер Sonic Pi и нажмите “Выполнить”. Бум, Бум, Бум!.
Итак, что такого особенного в цикле live_loop
? Он отдалённо напоминает усовершенствованный цикл loop
. Преимущество live_loop
в том, что вы можете изменять его на лету. Это значит, что пока выполняется цикл, вы можете изменить то, что он делает. Это и есть секрет лайвкодинга с Sonic Pi. Давайте играть:
live_loop :choral_drone do
sample :ambi_choir, rate: 0.4
sleep 1
end
Теперь, нажмите кнопку “Выполнить” или Alt-r
. Вы услышите великолепный звук хора. Теперь, пока он ещё играет, измените скорость с 0.4
на 0.38
. Нажмите “Выполнить” снова. Ого! Вы слышите, как хор сменил ноту? Измените скорость обратно на 0.4
, чтобы вернуться к тому, что было раньше. Теперь, снизьте скорость до 0.2
, потом до 0.19
, а затем обратно до 0.4
. Видите, как изменение на лету одного лишь параметра, даёт вам реальный контроль над музыкой? Теперь поиграйте со скоростью самостоятельно - выберите свои собственные значения. Попробуйте отрицательные числа, попробуйте очень маленькие и очень большие числа. Повеселитесь!
Один из самых важных аспектов цикла live_loop
в том, что в нём должна быть пауза. Рассмотрим следующий код:
live_loop :infinite_impossibilities do
sample :ambi_choir
end
Если вы попробуете запустить этот код, вы сразу увидите жалобу Sonic Pi на то, что в live_loop
не указанно время sleep
. Это ругается система безопасности! Воспользуйтесь моментом, чтобы подумать о том, что просит ваш компьютер сделать этот код. Правильно, он просит компьютер играть бесконечное количество сэмплов хора за нулевое время. Без системы безопасности бедный компьютер будет пытаться сделать это, что приведёт к аварии. Поэтому помните, ваш live_loop
должен содержать sleep
.
Музыка полна вещей, происходящих одновременно. Барабаны звучат в то же самое время, что и бас, вокал, гитары… В информатике это называется параллелизм и Sonic Pi обеспечивает нам удивительно простой способ играть разные вещи в одно и то же время. Просто используйте больше, чем один live_loop
!
live_loop :beats do
sample :bd_tek
with_fx :echo, phase: 0.125, mix: 0.4 do
sample :drum_cymbal_soft, sustain: 0, release: 0.1
sleep 0.5
end
end
live_loop :bass do
use_synth :tb303
synth :tb303, note: :e1, release: 4, cutoff: 120, cutoff_attack: 1
sleep 4
end
Здесь у нас есть два цикла live_loop
, один цикл делает быстрый ритм, а другой - медленный сумасшедший басовый звук.
Одна из особенностей использования нескольких циклов live_loop
состоит в том, что каждый из них обладает своим собственным независимым временем. Это значит, что с помощью этого легко создавать интересные полиритмические структуры и даже поиграть с фазировкой в стиле Стива Райха (Steve Reich). Зацени:
# Steve Reich's Piano Phase
notes = (ring :E4, :Fs4, :B4, :Cs5, :D5, :Fs4, :E4, :Cs5, :B4, :Fs4, :D5, :Cs5)
live_loop :slow do
play notes.tick, release: 0.1
sleep 0.3
end
live_loop :faster do
play notes.tick, release: 0.1
sleep 0.295
end
Каждую из этих статей мы будем заканчивать примером в виде фрагмента музыкального произведения, который вырисовывается из всех представленных в статье идей. Прочтите этот код и посмотрите, сможете ли вы понять, что он делает. Затем скопируйте его в свободный буфер Sonic Pi, нажмите “Выполнить” и послушайте, как он самом деле звучит. Наконец, измените одно из чисел или закомментируйте/раскомментируйте какие-нибудь строки. Посмотрите, сможете ли вы использовать этот пример в качестве отправной точки для нового выступления, и самое главное, веселитесь! До встречи в следующий раз…
with_fx :reverb, room: 1 do
live_loop :time do
synth :prophet, release: 8, note: :e1, cutoff: 90, amp: 3
sleep 8
end
end
live_loop :machine do
sample :loop_garzul, rate: 0.5, finish: 0.25
sample :loop_industrial, beat_stretch: 4, amp: 1
sleep 4
end
live_loop :kik do
sample :bd_haus, amp: 2
sleep 0.5
end
with_fx :echo do
live_loop :vortex do
# use_random_seed 800
notes = (scale :e3, :minor_pentatonic, num_octaves: 3)
16.times do
play notes.choose, release: 0.1, amp: 1.5
sleep 0.125
end
end
end
Одним из самых захватывающих и взрывных по своим последствиям для современной музыки, стало изобретение сэмплеров. Это были коробки, которые позволяли записывать в них любой звук, а затем воспроизводить и управлять этим звуком множеством различных способов. Например, можно взять старую записать, найти в ней барабанное соло (или брэйк), записать его в свой сэмплер и воспроизводить на половине от изначальной скорости, чтобы положить его в основу для своих собственных ритмов. Так зарождался ранний хип-хоп, и сегодня практически невозможно найти электронную музыку, в составе которой нет сэмплов в том или ином виде. Использование сэмплов - это действительно отличный способ легко внедрять новые интересные элементы в ваш лайвкодинг-перформанс.
Так и где же можно заполучить этот сэмплер? Ну, у вас уже есть один - это ваш Raspberry Pi! Идущее в комплекте приложение для лайвкодинга Sonic Pi имеет чрезвычайно мощный сэмплер, встроенный в его ядро. Давайте с ним поиграем!
Один из самых узнаваемых сэмплов среди классических барабанных брейков называется Амен-брейк. Он впервые прозвучал в 1969 году в песне “Аминь, Брат”, исполнителя “Winstons”, как часть барабанного брейка. Тем не менее, когда он был обнаружен ранними хип-хоп музыкантами в 80-х годах и начал использоваться в сэмплерах, он стал активно внедряться и в другие стили, такие как драм-эн-бэйс, брейкбит, хардкор, техно и брейк-кор.
Я уверен, что вы будете взволнованы, узнав, что он также входит в состав Sonic Pi. Очистите буфер и поместите в него следующий код:
sample :loop_amen
Нажмите Выполнить и бум! Вы слушаете один из самых влиятельных барабанных брейков в истории танцевальной музыки. Однако, этот сэмпл не стал бы известен, будучи сыгран сам по себе, он был выбран для того, чтобы стать петлёй.
Давайте зациклим амен-брейк, используя наш старый добрый цикл live_loop
, представленный в прошлом выпуске этого журнала:
live_loop :amen_break do
sample :loop_amen
sleep 2
end
ОК, мы его зациклили, но при каждом повторе есть неприятная пауза. Это потому, что мы сказали Sonic Pi ждать 2
тактовые доли, а с учётом того, что по умолчанию BPM (ударов в минуту) равно 60, сэмпл :loop_amen
длится только 1.753
удара. Поэтому мы имеем тишину 2 - 1.753 = 0.247
удара. Даже не смотря на то, что она довольно короткая, она всё равно заметна.
Чтобы устранить эту проблему, мы можем воспользоваться параметром beat_stretch:
, чтобы сказать Sonic Pi растянуть (или сжать) сэмпл согласно установленнму количеству ударов.
Функции sample
и synth
в Sonic Pi дают вам контроль через необязательные параметры, такие как amp:
, cutoff:
и release:
. Однако, термин “необязательный параметр” - это слишком длинное название, поэтому для простоты будем называть их просто параметры.
live_loop :amen_break do
sample :loop_amen, beat_stretch: 2
sleep 2
end
Теперь мы можем танцевать! Хотя, возможно, вы захотите ускорить или замедлить его, чтобы придать звуку иной характер.
ОК, но что, если мы хотим изменить стиль на олдскульный хип-хоп или брейк-кор? Один из простейших способов сделать это - играть со временем - или, другими словами, сдвинуть темп. В Sonic Pi это супер просто - добавьте use_bpm
в живой цикл:
live_loop :amen_break do
use_bpm 30
sample :loop_amen, beat_stretch: 2
sleep 2
end
Пока вы будете читать рэп под этот медленный ритм, обратите внимание, что мы до сих пор ждём 2 удара, и хотя наш BPM 30, всё продолжает звучать пропорционально. Параметр beat_stretch
работает с текущим BPM, чтобы быть уверенным, что всё будет работать исправно.
Теперь самое интересное. Пока цикл всё ещё исполняется, изменми 30
в строке use_bpm 30
на50
. Ого, всё ускорилось, но продолжает звучать равномерно во времени! Попытайтесь разогнаться ещё быстрее - до 80, до 120, или, сойдите с ума, и дайте 200!
Теперь, когда мы можем зацикливать сэмплы в реальном времени, давайте взглянем на некоторые из самых забавных параметров, предоставляемых сэмплером. Первый - cutoff:
, который контролирует частоту среза фильтра. По умолчанию эта возможность отключена, но вы можете легко её включить:
live_loop :amen_break do
use_bpm 50
sample :loop_amen, beat_stretch: 2, cutoff: 70
sleep 2
end
Давайте изменим параметр cutoff:
. Например, увеличьте его до 100, нажмите Выполнить и ждите, пока круг цикла завершится, чтобы услышать изменения в звуке. Обратите внимание, что низкие значения, такие как 50, дают сочный звук и басы, а высокие значения, типа 100 и 120, дают более полное звучание и больше высокочастотных составляющих. Это происходит потому, что параметр cutoff:
срезает высокочастотную область звука так же, как газонокосилка срезает верхнюю часть травы. Параметр cutoff:
определяет сколько “травы” оставлять.
Еще один отличный инструмент, с которым можно поиграть - это эффект slicer
. Он позволяет “нарезать” звук сэмпла. Оберните строку sample
кодом эффекта, как здесь:
live_loop :amen_break do
use_bpm 50
with_fx :slicer, phase: 0.25, wave: 0, mix: 1 do
sample :loop_amen, beat_stretch: 2, cutoff: 100
end
sleep 2
end
Обратите внимание, как звук стал более упругим (вы можете услышать оригинальное звучание сэмпла без эффекта, установив параметр mix:
в 0
.) Теперь поиграйтесь с параметром phase:
. Это размер (в ударах) нарезки. Меньшее значение, такое как 0.125
, нарежет сэмпл более короткими кусками и в большем количестве, чем значение 0.5
, при котором нарезка будет реже и толще. Обратите внимание, что удвоения значений phase
, как правило, всегда звучат хорошо. Наконец, измените параметр wave:
, выбрав из 0, 1 или 2, и послушайте, как меняется звук. Это три разные формы волны. 0 - это пилообразная волна, (резко начинается, плавно затухает), 1 - прямоугольная волна (резко начинается, резко обрывается), и 2 - треугольная волна (плавно нарастает, плавно затухает).
Наконец, давайте вернёмся назад во времени, и вновь посетим раннюю Бристольскую драм-эн-бэйс сцену. Не волнуйтесь о том, что всё это значит, просто введите этот код в пустой буфер, нажмите “Выполнить”, и начинайте лайвкодинг. Изменяйте значения параметров и подумайте, где бы вы смогли применить это. Пожалуйста, поделитесь тем, что у вас получилось! Увидимся в следующий раз…
use_bpm 100
live_loop :amen_break do
p = [0.125, 0.25, 0.5].choose
with_fx :slicer, phase: p, wave: 0, mix: rrand(0.7, 1) do
r = [1, 1, 1, -1].choose
sample :loop_amen, beat_stretch: 2, rate: r, amp: 2
end
sleep 2
end
live_loop :bass_drum do
sample :bd_haus, cutoff: 70, amp: 1.5
sleep 0.5
end
live_loop :landing do
bass_line = (knit :e1, 3, [:c1, :c2].choose, 1)
with_fx :slicer, phase: [0.25, 0.5].choose, invert_wave: 1, wave: 0 do
s = synth :square, note: bass_line.tick, sustain: 4, cutoff: 60
control s, cutoff_slide: 4, cutoff: 120
end
sleep 4
end
Какой бы звук вы не использовали, солирующий синтезатор всегда играет главную роль в любом электронном треке. В статье из прошлого номера мы рассматривали, как кодировать барабанные биты. В этой статье мы узнаем, как кодировать три основных компонента синтезаторных риффов - тембр, мелодию и ритм.
Итак, подключите ваш Paspberry Pi, откройте Sonic Pi версии v2.6+ и давайте пошумим!
Неотъемлемой частью любого синтезаторного риффа является его тембр. Мы можем изменять тембр в Sonic Pi двумя способами - выбирая различные синты для резкой смены тембра, и изменяя различные синтовые параметры для более тонкой настройки. Мы также можем использовать эффекты, но об этом в другой раз…
Давайте создадим простой живой цикл, в котором будет постоянно изменяться текущий синт:
live_loop :timbre do
use_synth (ring :tb303, :blade, :prophet, :saw, :beep, :tri).tick
play :e2, attack: 0, release: 0.5, cutoff: 100
sleep 0.5
end
Взгляните на код. Мы просто перебираем по кругу элементы кольцевого списка, содержащего имена синтов (цикл переключает синт на следующий в списке снова и снова). Мы передаём имена этих синтов функции use_synth
, которая и переключает текущий синтезатор цикла live_loop
. Ещё мы играем ноту :Е2
(ми второй октавы), со временем затухания 0.5 удара (пол секунды с ВРМ по умолчанию 60) и с параметром cutoff:
, равным 100.
Слышите, разные синтезаторы звучат совершенно по-разному, хотя играют одну и ту же ноту? Теперь давайте поэкспериментируем. Измените время затухания на большее или меньшее значение. Изменяйте оба параметра - attack:
и release:
, чтобы посмотреть, как сильно разные их значения изменяют звук. Наконец, измените параметр cutoff:
, чтобы услышать, что разные значения среза фильтра также радикально изменяют тембр синта (значения между 60 и 130 обычно звучат хорошо). Посмотрите, сколько разнообразных звуков можно создать, изменяя всего лишь несколько параметров. Как только вы это освоите, откройте вкладку “Синтезаторы” справочной системы, и взгляните на полный список синтезаторов и их параметров, чтобы увидеть, какую мощь вы держите в руках.
Тембр - это просто слово, описывающее звук. Если вы сыграете одну и ту же ноту на разных инструментах, таких как скрипка, гитара, или пианино, высота звука будет одинаковой, но свойство звуков будет разным. Это свойство звука - то, что позволяет вам слышать разницу между пианино и гитарой - и есть тембр.
Ещё одним важным аспектом нашего солирующего синтезатора является выбор нот, которые он будет играть. Если у вас уже есть хорошая мелодическая идея, то вы можете просто создать кольцо с вашими нотами, и воспроизводить его по кругу:
live_loop :riff do
use_synth :prophet
riff = (ring :e3, :e3, :r, :g3, :r, :r, :r, :a3)
play riff.tick, release: 0.5, cutoff: 80
sleep 0.25
end
Здесь мы поместили нашу мелодию в кольцевой список, содержащий ноты, такие как :е3
и паузы, обозначенные :r
. Затем, мы использовали .tick
, чтобы получить повторяющийся рифф.
Не всегда бывает легко придумать хороший рифф с нуля. Вместо этого, иногда проще сказать Sonic Pi играть случайный рифф, и выбрать тот, который понравится вам больше всего. Для этого нам необходимо объединить три вещи: кольца, рандомизацию и отправную точку (зерно) рандомизации. Взгляните на пример:
live_loop :random_riff do
use_synth :dsaw
use_random_seed 3
notes = (scale :e3, :minor_pentatonic).shuffle
play notes.tick, release: 0.25, cutoff: 80
sleep 0.25
end
Здесь происходит несколько вещей - давайте рассмотрим их по очереди. Во-первых, мы указали, что используем зерно рандомизации 3. Что это значит? Ну, смысл в том, что когда мы устанавливаем зерно, мы можем предсказать, какой будет рандомизация в следующий раз. Той же самой, что и в тот раз, когда мы устанавливали зерно в 3! Ещё одна вещь, которую полезно знать, что перемешивание нот кольца будет произведено тем же способом. В примере выше, мы, по сути, вызываем “третье перемешивание” из стандартного списка перемешиваний, который остаётся неизменным всякий раз, когда мы устанавливаем зерно в то же значение перед перемешиванием. Наконец, мы просто вызываем по кругу наши перемешанные ноты, чтобы получить рифф.
Вот где начинается веселье. Если мы меняем значение зерно рандомизации на другое, скажем 3000, мы получаем совершенно другое перемешивание нот. Так что теперь очень легко исследовать новые мелодии. Просто выберите список нот, которые вы хотите перемешать (гаммы представляют собой отличную отправную точку), а затем выберите зерно рандомизации, с которого вы хотите начать перемешивание. Если вам не нравится мелодия, просто измените одну из этих двух вещей и попробуйте снова. Повторяйте до тех пор, пока вам понравится то, что вы слышите!
Случайный выбор в Sonic Pi на самом деле не является случайным, это то, что обычно называется псевдо рандомизация. Представьте, что вы бросали игральные кости 100 раз и записывали результат каждого броска на лист бумаги. Sonic Pi имеет эквивалент этого списка результатов, которые он использует, когда вы запрашиваете случайные значения. Только вместо бросков настоящих костей, он выбирает следующее значение из списка. Настройка зерна рандомизации - это просто прыжок в определённое место этого списка.
Ещё один важный аспект нашего риффа, это ритм - т.е. последовательность нот и пауз. Как мы видели раньше, мы можем использовать :r
в наших кольцах, чтобы вставить паузу. Ещё один очень мощный способ - использовать методы колец, но о них мы поговорим в следующий раз. Сегодня мы будем использовать рандомизацию, чтобы помочь нам найти подходящий ритм. Вместо того, чтобы играть каждую ноту, мы можем играть ноту с заданной вероятностью. Давайте посмотрим:
live_loop :random_riff do
use_synth :dsaw
use_random_seed 30
notes = (scale :e3, :minor_pentatonic).shuffle
16.times do
play notes.tick, release: 0.2, cutoff: 90 if one_in(2)
sleep 0.125
end
end
Очень полезно знать функцию one_in
, которая возвращает нам true
или false
с заданной вероятностью. Здесь мы используем значение 2, поэтому в среднем один раз каждые два вызова, one_in
возвратит true
. Другими словами, она будет возвращать true
в 50% случаев. Если использовать более высокие значения, false
будет возвращаться чаще, добавляя в рифф больше пауз.
Заметим, что мы добавили повторы 16.times
. Это потому, что мы хотим сбрасывать наше зерно рандомизаци каждые 16 нот. Так наш ритм будет повторяться каждые 16 ударов. Это не влияет на перемешивание, т.к. оно выполняется сразу после того, как установлено зерно рандомизации. Мы можем использовать разное количество повторов для изменения длины риффа. Попробуйте изменить 16 на 8 или даже на 4 или 3 и посмотрите, как это повлияет на ритм.
ОК, теперь давайте совместим всё, чему мы научились, в один финальный пример. Увидимся в следующий раз!
live_loop :random_riff do
# uncomment to bring in:
# synth :blade, note: :e4, release: 4, cutoff: 100, amp: 1.5
use_synth :dsaw
use_random_seed 43
notes = (scale :e3, :minor_pentatonic, num_octaves: 2).shuffle.take(8)
8.times do
play notes.tick, release: rand(0.5), cutoff: rrand(60, 130) if one_in(2)
sleep 0.125
end
end
live_loop :drums do
use_random_seed 500
16.times do
sample :bd_haus, rate: 2, cutoff: 110 if rand < 0.35
sleep 0.125
end
end
live_loop :bd do
sample :bd_haus, cutoff: 100, amp: 3
sleep 0.5
end
Невозможно исследовать историю электронной танцевальной музыки, и не заметить огромного влияния крошечного синтезатора Roland TB-303. Это секретный ингредиент оригинального кислотного баса. Классическое визжание и чавканье басовых риффов TB-303 можно услышать в ранней чикагской хаус сцене благодаря таким музыкантам, как Plastikman, Squarepusher и Aphex Twin.
Интересно, что инженеры Roland никогда не предполагали, что TB-303 будет использоваться в танцевальной музыке. Он изначально создавался для гитаристов. Они рассчитывали, что гитаристы будут программировать TB-303 играть басовые линии в джемах. К сожалению, существовал ряд проблем: они были немного неудобными для программирования, не очень хорошо звучали в качестве замены бас-гитары и были довольно дорогими. Решив сократить убытки, Roland прекратили их выпуск после продажи 10 000 экземпляров, и после нескольких лет лежания на полках, эти синтезаторы можно было найти только в комиссионных магазинах. Эти одинокие, отвергнутые TB-303 ждали, когда их обнаружит новое поколение экспериментаторов, которые начали применять их способом, который в Roland и представить не могли, создавая новые сумасшедшие звуки. Так зародился эйсид хаус.
Хотя получить на руки оригинал TB-303 не так уж и просто, вам будет приятно узнать, что вы можете превратить ваш Raspberry Pi в один из них, используя мощь Sonic Pi. Узрите свет Sonic Pi, забросив этот код в пустой буфер и нажав “Выполнить”:
use_synth :tb303
play :e1
Кислотный бас в одно мгновение! Давайте с ним поиграем…
Во-первых, построим живой арпеджиатор, чтобы играть было веселей. В прошлой статье мы узнали, что риффы могут быть простыми кольцами нот, извлекающимися одна за другой. Давайте создадим живой цикл, который сделает для нас это:
use_synth :tb303
live_loop :squelch do
n = (ring :e1, :e2, :e3).tick
play n, release: 0.125, cutoff: 100, res: 0.8, wave: 0
sleep 0.125
end
Для начала рассмотрим код построчно.
В первой строке мы задаём синтезатор по умолчанию tb303
с помощью функции use_synth
.
Во второй строке мы создаем живой цикл с именем :squelch
, который будет просто повторяться снова и снова.
Третья строка - та, где мы создаём наш рифф - кольцо нот (ми в октавах 1, 2 и 3), которые мы извлекаем по кругу с помощью .tick
. Мы определяем n
для представления текущей ноты в риффе. Знак равенства означает, что присваиваем имени, находящемуся слева,значение, находящееся справа. Это значение будет отличаться каждый круг цикла. Первый круг n
будет иметь значение :е1
. Второй круг - :е2
, затем :е3
, потом снова :е1
и так круг за кругом.
Четвёртая строка - место, где мы включаем наш :tb303
. У нас здесь есть несколько интересных параметров: release:
, cutoff:
, res:
и wave:
, которые мы обсудим чуть позже.
В пятой строке появляется sleep
- мы просим цикл замыкать круг каждые 0.125
секунды, или 8 раз в секунду с BPM по умолчанию 60.
Строка шесть - это end
живого цикла. Мы просто говорим Sonic Pi, что здесь конец живого цикла.
В то время, как вы всё ещё пытаетесь понять, что здесь происходит, поместите этот код в пустой буфер, и нажмите кнопку “Выполнить”. Вы должны услышать :tb303
в действии. Теперь пора начинать лайвкодинг.
В то время, как цикл исполняется, измените параметр cutoff:
на 110
. Затем нажмите кнопку “Выполнить” снова. Вы должны услышать, что звук стал немного жёстче и более “хлюпающим”. Наберите 120
и нажмите “Выполнить”. Затем 130
. Слушайте, как более высокие значения делают звук более пронзительным и интенсивным. Наконец, понизьте значение до 80
, если захотите отдохнуть. Затем повторите это столько раз, сколько захотите. Не волнуйтесь, я всё ещё буду здесь…
Ещё один параметр, с которым стоит поиграть, это res:
. Он контролирует уровень резонанса фильтра. Для кислотных басовых партий характерен высокий резонанс. В настоящее время наш res:
установлен в 0.8
. Попробуйте изменить его на 0.85
, затем на 0.9
, и наконец, на 0.95
. Вы можете обнаружить, что предельные значения cutoff:
, такие как 110
или выше, помогают легче услышать различия. Наконец, сойдите с ума и установите 0.999
, чтобы получить действительно безумный звук. С этим значением res:
вы слышите так много резонанса, что он начинает звучать сам по себе!
Наконец, для резкого изменения тембра попробуйте изменить параметр wave:
на 1
. Это выбор формы волны исходного генератора. Значение по умолчанию - 0
- пилообразная волна, 1
- прямоугольная волна, и 2
- треугольная форма волны.
Конечно, пробуйте разные риффы, изменяя ноты в кольце, или же выбирая ноты из гамм, или аккордов. Веселитесь с вашим первым кислотным басовым синтезатором.
Конструкция оригинальных TB-303 на самом деле довольно проста. Как вы можете видеть из следующей диаграммы, главных составляющих всего 4.
Первой является волновой регенератор - сырая основа звука. В этом примере у нас прямоугольная волна. Дальше идёт генератор амплитудной огибающей, который контролирует амплитуду прямоугольной волны во времени. Он доступен в Sonic Pi в виде параметров attack:
, decay:
, sustain:
и release:
. Для получения более подробной информации об этих параметрах читайте раздел 2.4 “Длительность с помощью огибающих” встроенного учебника. Затем, мы пропускаем наш амплитудно модулированный сигнал через резонансный низкочастотный фильтр. Это срубает высокочастотную составляющую, а также добавляет этот приятный резонансный эффект. Теперь начинается самое весёлое. Значение среза этого фильтра может управляться своей собственной огибающей! Это значит, что мы имеем удивительный контроль над тембром звука, играя двумя этими огибающими. Давайте приступим:
use_synth :tb303
with_fx :reverb, room: 1 do
live_loop :space_scanner do
play :e1, cutoff: 100, release: 7, attack: 1, cutoff_attack: 4, cutoff_release: 4
sleep 8
end
end
В синтезаторе :tb303
, для каждого стандартного параметра огибающей есть эквивалент и для cutoff_
. Так, для изменения времени атаки фильтра, мы можем использовать параметр cutoff_attack:
. Скопируйте приведенный выше код в пустой буфер, и нажмите “Выполнить”. Вы услышите безумный плавающий звук. Теперь поиграем. Попробуйте изменять время cutoff_attack:
на 1
, а затем на 0.5
. Потом попробуйте 8
.
Заметьте, что я пропустил звук через :reverb
эффект для создания дополнительной атмосферы - попробуйте другие эффекты, чтобы посмотреть, как это работает!
Наконец, ниже расположен фрагмент кода, который я сочинил, используя идеи этой статьи. Скопируйте его в свой буфер, послушайте, а потом начните лайвкодинг, внося свои собственные изменения. Посмотрим, какие безумные звуки вы сможете создать с помощью этого! Увидимся в следующий раз…
use_synth :tb303
use_debug false
with_fx :reverb, room: 0.8 do
live_loop :space_scanner do
with_fx :slicer, phase: 0.25, amp: 1.5 do
co = (line 70, 130, steps: 8).tick
play :e1, cutoff: co, release: 7, attack: 1, cutoff_attack: 4, cutoff_release: 4
sleep 8
end
end
live_loop :squelch do
use_random_seed 3000
16.times do
n = (ring :e1, :e2, :e3).tick
play n, release: 0.125, cutoff: rrand(70, 130), res: 0.9, wave: 1, amp: 0.8
sleep 0.125
end
end
end
Привет, и с возвращением! В предыдущих упражнениях мы сосредотачивались исключительно на музыкальных возможностях Sonic Pi - (превращая ваш Raspberry Pi в готовый к выступлению музыкальный инструмент). К этому моменту мы научились:
Кодировать в реальном времени, Создавать различные ритмы, Генерировать мощные солирующие синты, Воссоздавать знаменитые кислотные басы TB-303.
Однако, есть ещё множество аспектов создания музыки, которые нужно показать вам (что я и сделаю в будущем). Но в этом месяце мы рассмотрим особенность Sonic Pi, о наличии которой вы, наверное, даже и не подозревали: управлять Minecraft.
ОК, давайте начнём. Подключите ваш Raspberry Pi, запустите Minecraft Pi и создайте новый мир. Теперь запустите Sonic Pi, измените размеры окон и разместите их так, чтобы вы могли видеть одновременно и Minecraft Pi, и Sonic Pi.
В пустом буфере наберите следующее:
mc_message "Hello Minecraft from Sonic Pi!"
Теперь, нажмите “Выполнить”. Бум! Ваше сообщение появилось в Minecraft! Ну как, это было легко? Теперь, прекратите на мгновение чтение этой статьи и поиграйте с вашими собственными сообщениями. Веселитесь!
Теперь давайте исследовать мир Minecraft. Стандартный вариант - дотянуться до мыши и клавиатуры и начать перемещаться в мире Minecraft. Это работает, но это довольно медленно и скучно. Было бы гораздо интереснее, если бы у нас было что-то вроде телепортатора. Благодаря Sonic Pi, мы имеем один. Попробуйте это:
mc_teleport 80, 40, 100
Боже мой! Это был долгий путь вверх. Если вы не находились в режиме полёта, то должны были упасть обратно на землю. Если вы дважды нажмёте пробел для входа в режим полёта и телепортируетесь снова, вы останетесь висеть на том месте, куда вы в телепортировались.
Итак, что же означают эти цифры? У нас есть три числа, которые описывают координаты места, куда мы хотим переместиться. Мы даём каждой цифре имя - х, y и z:
x - как далеко от левого края (в нашем примере - 80) y - как высоко (в нашем примере - 40) z - как далеко вглубь мира (в нашем примере - 100)
Выбирая различные значения для x, y и z, мы можем телепортироваться куда угодно. Попробуйте! Выбирайте различные цифры и смотрите, где вы окажетесь. Если экран стал чёрным, это произошло потому, что вы телепортировали себя под землю или внутрь скалы. Просто выберите значение y
выше, чтобы оказаться снова над землёй. Продолжайте исследования, пока не найдёте место, которое вам понравится…
Используя эти идеи, построим телепортатор, который издаёт весёлый звук телепортации, пока переносит нас сквозь мир Minecraft:
mc_message "Preparing to teleport...."
sample :ambi_lunar_land, rate: -1
sleep 1
mc_message "3"
sleep 1
mc_message "2"
sleep 1
mc_message "1"
sleep 1
mc_teleport 90, 20, 10
mc_message "Whoooosh!"
Сейчас, когда вы нашли хорошее место, начнём строительство. Вы могли бы делать то, к чему привыкли, и начать яростно кликать мышкой, располагая блоки под курсором. Или вы могли бы использовать магию Sonic Pi. Попробуйте это:
x, y, z = mc_location
mc_set_block :melon, x, y + 5, z
Теперь посмотри вверх! В небе дынный блок! Найдите минутку, чтобы посмотреть на код. Что он делает? На первой строке мы определили текущее местоположение как переменные x, y и z. Они соответствуют нашим координатам, описанным выше. Мы использовали эти координаты в функции mc_set_block
, которая поместила блок, который мы выбрали, по указанным координатам. Чтобы указать сделать что-то выше в небе, нам просто нужно увеличить значение y
, вот почему мы добавляем 5 к нему. Сделаем длинный след из этих блоков:
live_loop :melon_trail do
x, y, z = mc_location
mc_set_block :melon, x, y-1, z
sleep 0.125
end
Теперь переключитесь на Minecraft, убедитесь что вы находитесь в режиме полёта (двойное нажатие на пробел, если нет) и летайте по всему миру. Обернитесь, чтобы увидеть длинный след дынных блоков! Посмотрите, какие извилистые структуры вы можете сделать в небе.
Тем из вас, кто следит за этими статьями в течение последних нескольких месяцев, наверное снесёт крышу к этому моменту. След дынных блоков это очень здорово, но самая захватывающая часть предыдущего пример заключается в том, что вы можете использовать live_loop
с Minecraft! Для тех, кто не знает, цикл live_loop
в Sonic Pi - особая магическая способность, которой нет других языках программирования. Он позволяет запускать несколько циклов в одно и то же время и изменять их, пока они выполняются. Они невероятно мощные и удивительно весёлые. Я использую live_loop
, чтобы исполнять музыку в ночных клубах с Sonic Pi - диджеи используют диски, а я циклы live_loop
:-) Тем не менее, сегодня мы собираемся кодировать в реальном времени и музыку, и Minecraft.
Давайте начнём. Запустите приведенный выше код и начните делать свой дынный след снова. Теперь, не останавливая код, просто измените :melon
на :brick
и нажмите “Выполнить”. Вуаля, вы теперь делаете кирпичную дорогу. Это было просто! Добавим немного музыки в это? Легко. Попробуйте это:
live_loop :bass_trail
tick
x, y, z = mc_location
b = (ring :melon, :brick, :glass).look
mc_set_block b, x, y -1, z
note = (ring :e1, :e2, :e3).look
use_synth :tb303
play note, release: 0.1, cutoff: 70
sleep 0.125
end
Теперь, пока это играет, начнём вносить изменения в наш код. Измените тип блока. Попробуйте :water
, :grass
или другой ваш любимый тип блока. Также, попробуйте изменить значение отсечки фильтра с 70
до 80
и затем до 100
. Разве это не весело?
Давайте объединим всё, что мы видели до сих пор, с небольшой дополнительной магией. Совместим наши способности к телепортации с размещением блоков и музыкой, сделав музыкальное видео Minecraft. Не волнуйтесь, если вы не всё здесь понимаете, просто введите код в буфер и играйте, изменяя значения, пока код выполняется. Повеселитесь и увидимся в следующий раз…
live_loop :note_blocks do
mc_message "This is Sonic Minecraft"
with_fx :reverb do
with_fx :echo, phase: 0.125, reps: 32 do
tick
x = (range 30, 90, step: 0.1).look
y = 20
z = -10
mc_teleport x, y, z
ns = (scale :e3, :minor_pentatonic)
n = ns.shuffle.choose
bs = (knit :glass, 3, :sand, 1)
b = bs.look
synth :beep, note: n, release: 0.1
mc_set_block b, x+20, n-60+y, z+10
mc_set_block b, x+20, n-60+y, z-10
sleep 0.25
end
end
end
live_loop :beats do
sample :bd_haus, cutoff: 100
sleep 0.5
end
После нашего краткого экскурса в сказочный мир кодинга Minecraft в прошлом месяце, давайте снова помузицируем. Сегодня мы собираемся перенести классический оперный танцевальный ритм в 21-й век, используя грандиозную силу кода.
Переместимся на машине времени в 1875 год. Композитор Бизе как раз закончил свою последнюю оперу “Кармен”. К сожалению, как и множество других прогрессивных, ломающих стереотипы музыкальных произведений, публика поначалу её не приняла, ведь она была слишком дерзкой и непохожей на другие оперы того времени. Печально, но Бизе умер за десять лет до того, как эта опера возымела ошеломляющий международный успех и стала одной из самых известных и часто исполняемых опер всех времён. Из сочувствия к этой трагедии, возьмем одну из главных тем оперы “Кармен”, и преобразуем её в современный формат музыки, который также слишком возмутителен и чужд большинству людей нашего времени - кодированную музыку!
Пытаться кодировать всю оперу было бы трудноватой задачей для одной статьи, так что давайте сосредоточимся на одной из самых известных её частей - басовой партии Хабанеры:
Если вы ещё не изучали нотной записи, это будет выглядеть крайне непонятным для вас. Однако, как программисты, мы видим нотную запись просто как другую форму кода, содержащего инструкции не для компьютера, а для музыканта. Поэтому нам нужно найти способ декодировать его.
Ноты упорядочиваются слева направо, как слова в этой статьи, но имеют разную высоту. Высота относительно нотной партитуры обозначает высоту тона. Чем выше нота находится в партитуре, тем выше высоты тона.
Мы уже знаем, как изменить высоту ноты в Sonic Pi - либо используя цифры, такие как play 75
и play 80
, либо используя названия нот: play :Е
и play :F
. К счастью, каждой вертикальной позиции музыкальной партитуры соответствует определенная нота. Взгляните на эту удобную таблицу:
Ноты представляют собой чрезвычайно богатый и выразительный вид кода, способного объединить сразу множество вещей. Поэтому для вас не должно стать большим удивлением, что партитура может не только сказать вам, какие ноты играть, но также когда ноты играть не нужно . В программировании это эквивалентно nil
или null
- отсутствию значения. Другими словами, пауза - это отсутствие ноты.
Если вы внимательно посмотрите на партитуру, вы увидите, что это на самом деле сочетание горизонтальных линий с черными точками, которые представляют собой ноты, которые нужно играть, и волнистых штук, которые представляют собой паузы. К счастью, Sonic Pi имеет очень удобное представление для пауз: :r
, так, если мы выполним: play :r
, он на самом деле сыграет тишину! Мы могли бы также написать play :rest
, play nil
или play false
- это всё эквивалентные способы представления пауз.
Наконец, нужно узнать ещё одну вещь - как расшифровывать в партитуре длительности нот. В оригинальной партитуре мы видим, что ноты связаны толстыми линиями, называемыми рёбрами. Вторая нота имеет два таких ребра, что означает, что она длится 16-ю часть такта. Другие ноты имеют одно ребро, которое означает, что они длятся 8-ю часть такта. Паузы имеют два волнистых флажка, которые означают, что они также длятся 16-ю часть такта.
Когда мы пытаемся расшифровать и изучить новые вещи, очень удобный приём - сделать всё как можно более однородным, чтобы увидеть соотношения и структуры. Например, если мы перепишем нашу партитуру одними только 16-ми длительностями, вы сможете увидеть, что она превращается в простую последовательность нот и пауз.
Теперь мы в состоянии начать переводить эту басовую партию для Sonic Pi. Давайте закодируем эти ноты и паузы в кольцо:
(ring :d, :r, :r, :a, :f5, :r, :a, :r)
Теперь посмотрим, как это звучит. Закиньте это кольцо в живой цикл, чтобы можно было последовательно извлекать элементы кольца:
live_loop :habanera do
play (ring :d, :r, :r, :a, :f5, :r, :a, :r).tick
sleep 0.25
end
Легендарный, мгновенно узнаваемый рифф возвращается к жизни сквозь ваши колонки. Потребовалось немало усилий, чтобы добраться сюда, но это того стоило!
Теперь у нас есть басовая партия. Давайте воссоздадим атмосферу оперной сцены. Попробуем осуществить это с :blade
, мрачным солирующим синтом в стиле 80-х. Давайте испробуем его, извлекая ноту :d
, пропущенную через эффекты нарезки и реверберации:
live_loop :habanera do
use_synth :fm
use_transpose -12
play (ring :d, :r, :r, :a, :f5, :r, :a, :r).tick
sleep 0.25
end
with_fx :reverb do
live_loop :space_light do
with_fx :slicer, phase: 0.25 do
synth :blade, note: :d, release: 8, cutoff: 100, amp: 2
end
sleep 8
end
end
Теперь, попробуйте подставить туда другие ноты басовой партии::a
и :f5
. Помните, вам не надо нажимать кнопку “Остановить”, просто измените код в то время, как музыка играет, и нажмите “Выполнить” снова. Также, попробуйте разные значения параметра phase:
нарезки, такие как 0.5
, 0.75
и 1
.
Наконец, давайте объединим все идеи этой статьи в новый ремикс Хабанеры. Вы можете заметить, что я включил ещё одну часть басовой партии как комментарий. Как только вы набрали всё это в буфере, нажмите “Выполнить”, чтобы прослушать композицию. Затем, не нажимая кнопку “Остановить”, раскомментируйте вторую строку, удалив знак #
, и нажмите “Выполнить” снова - как это удивительно! Итак, начинайте лайвкодинг и веселитесь.
use_debug false
bizet_bass = (ring :d, :r, :r, :a, :f5, :r, :a, :r)
#bizet_bass = (ring :d, :r, :r, :Bb, :g5, :r, :Bb, :r)
with_fx :reverb, room: 1, mix: 0.3 do
live_loop :bizet do
with_fx :slicer, phase: 0.125 do
synth :blade, note: :d4, release: 8,
cutoff: 100, amp: 1.5
end
16.times do
tick
play bizet_bass.look, release: 0.1
play bizet_bass.look - 12, release: 0.3
sleep 0.125
end
end
end
live_loop :ind do
sample :loop_industrial, beat_stretch: 1,
cutoff: 100, rate: 1
sleep 1
end
live_loop :drums do
sample :bd_haus, cutoff: 110
synth :beep, note: 49, attack: 0,
release: 0.1
sleep 0.5
end
Все вы играли в Minecraft. Все строили удивительные сооружения, конструировали хитрые ловушки и даже создавали контролируемые транспортные линии. Но, держу пари, вы не догадывались, что могли бы использовать Minecraft для создания удивительных визуальных эффектов как профессиональный виджей.
Если вашим единственным способом игры с Minecraft была модификация игрового мира с помощью мышки, вам наверняка было бы трудно изменять его достаточно быстро. К счастью, ваш Raspberry Pi поставляется с версией Minecraft, управляемой с помощью кода. Он также содержит приложение Sonic Pi, которое делает кодирование Minecraft не только лёгким, но и невероятно весёлым.
В этой статье я покажу вам некоторые советы и трюки, использующиеся в выступлениях в ночных клубах и концертных площадках по всему миру.
Итак, начнём…
Давайте начнём с простого разминочного упражнения, дабы освежить в памяти основы. Во-первых, подключите ваш Raspberry Pi и запустите Sonic Pi вместе с Minecraft. В Minecraft создайте новый мир, а в Sonic Pi выберите пустой буфер и наберите там этот код:
mc_message "Let's get started..."
Нажмите кнопку “Выполнить”, и вы увидите сообщение в окне Minecraft. Хорошо, мы готовы начать, давайте повеселимся……
Когда мы используем Minecraft для создания визуальных эффектов, мы стараемся думать о том, чтобы это одновременно выглядело интересно и легко генерировалось с помощью кода. Интересный трюк - создать песчаную бурю, сбрасывая песчаные блоки с неба. Для этого нам необходимы несколько базовых функций:
sleep
- для того, чтобы вставить задержку между действиями
mc_location
- для нахождения нашего текущего местоположения
mc_set_block
- чтобы поместить песчаный блок в заданное место
rrand
- для генерации случайных чисел в заданном диапазоне
live_loop
- позволяет сделать дождь из песка непрерывным
Если вы не знакомы с какой-либо из встроенных функций, например rrand
, просто введите её название в свой буфер, кликните на нём, а затем используйте клавиатурное сочетание Ctrl-i
, вызывающее встроенную документацию. В качестве альтернативы вы можете переместиться к вкладке язык справочной системы, и найти нужную функцию прямо там, как и другие интересные вещи.
Прежде чем высвободить всю мощь бури, сделаем небольшой дождь. Возьмём ваше текущее местоположение и используем его для создания нескольких песчаных блоков в небе неподалеку:
x, y, z = mc_location
mc_set_block :sand, x, y + 20, z + 5
sleep 2
mc_set_block :sand, x, y + 20, z + 6
sleep 2
mc_set_block :sand, x, y + 20, z + 7
sleep 2
mc_set_block :sand, x, y + 20, z + 8
Когда вы нажмете “Выполнить”, вам, возможно, придется немного осмотреться, так как блоки могут начать падать позади вас в зависимости от того, в каком направлении вы в настоящее время смотрите. Не волнуйтесь, если вы пропустили их, просто нажмите “Выполнить” снова, и вы получите ещё одну порцию песчаного дождя - просто убедитесь, что вы смотрите в правильном направлении!
Давайте быстро посмотрим, что тут у нас происходит. На первой строке мы получили местоположение Стива в виде координат с помощью функции mc_location
и присвоили их переменным х
, у
, и z
. На последующих строках мы использовали функцию mc_set_block
, чтобы поместить немного песка в тех же координатах, что и Стив но с некоторыми изменениями. Мы выбрали ту же координату x
, но координата y
стала на 20 блоков выше, а затем последовательно увеличивали z
, чтобы песок падал в линию, удаляющуюся от Стива.
Почему бы вам самим не поиграть с этим кодом? Попробуйте добавить больше линий, измените время задержки, попробуйте смешать :sand
с :gravel
и выбирать разные координаты. Просто экспериментируйте и веселитесь!
Хорошо, пришло время получить бушующую бурю, высвободив мощь live_loop
- магической способности Sonic Pi, раскрывающей всю силу лайвкодинга - изменения кода в реальном времени!
live_loop :sand_storm do
x, y, z = mc_location
xd = rrand(-10, 10)
zd = rrand(-10, 10)
co = rrand(70, 130)
synth :cnoise, attack: 0, release: 0.125, cutoff: co
mc_set_block :sand, x + xd, y + 20, z + zd
sleep 0.125
end
Это весело! Мы выполняем круг цикла довольно быстро (8 раз в секунду), и во время каждого круга мы находим местоположение Стива также, как и раньше, но в этот раз генерируем 3 случайных значения:
xd
- разница для x
, которая будет находиться между -10 и 10
zd
- разница для z
, которая также будет между -10 и 10
co
- значение среза фильтра низких частот между 70 и 130
Затем мы используем эти случайные значения в функциях synth
и mc_set_block
, что даёт нам песок, падающий случайным образом вокруг Стива вместе с перкуссионным звуком, похожим на дождь, от синтезатора :cnoise
.
Для тех из вас, кто ещё новичок в живых циклах - именно здесь и начинается самое интересное. Пока код выполняется и песок сыплется вниз, попробуйте изменить одно из значений. Например, время задержки на 0.25
, или тип блока с :sand
на :gravel
. Теперь нажмите “Выполнить” снова. Эй! Всё изменилось без остановки кода. Это и есть та самая дверь к выступлениям в роли виджея. Продолжайте тренироваться и что-нибудь изменять. Насколько разнообразными можно сделать визуальные эффекты, не останавливая кода?
Наконец, еще один отличный способ создания интересных визуальных эффектов - генерировать огромные повторяющиеся стены, парящие рядом. Для этого эффекта нам нужно перейти от размещения блоков случайным образом, к размещению их в упорядоченном виде. Мы можем сделать это с помощью двух вложенных итераций (нажмите кнопку “Помощь”, чтобы перейти в раздел 5.2 учебника “Итерации И Циклы”, чтобы узнать больше об итерациях). Аргумент |xd|
после do
означает, что xd
будет соответствовать номеру итерации. Поэтому сначала это будет 0, потом 1, потом 2… и т. д. Совмещая две итерации вместе, мы можем сгенерировать любые координаты. Затем мы произвольно выбираем типы блоков из кольцевого списка для создания интересного эффекта:
x, y, z = mc_location
bs = (ring :gold, :diamond, :glass)
10.times do |xd|
10.times do |yd|
mc_set_block bs.choose, x + xd, y + yd, z
end
end
Довольно аккуратно. В то время как мы здесь веселимся, попробуйте изменить bs.choose
, на bs.tick
, чтобы перейти от случайного выбора к последовательному. Попробуйте изменять типы блоков более радикально. Вы можете захотеть делать это с live_loop
, чтобы узоры продолжали изменяться автоматически.
Теперь, измените обе итерации с 10.times
на 100.times
и нажмите “Выполнить”. Бабах! Огромные исполинские стены с хаотично расположенными кирпичами. Представьте сколько времени потребуется вам, чтобы построить их вручную с помощью мыши! Дважды нажмите пробел, чтобы переключиться в режим полёта и начните парить для создания замечательных визуальных эффектов. Не останавливайтесь на этом, используйте своё воображение, чтобы придумать интересные идеи, а затем, использовав силу кода Sonic Pi, сделайте это реальностью. Когда вы достаточно попрактикуетесь, приглушите свет и покажите шоу своим друзьям!
В 4 разделе этого руководства мы кратко рассмотрели рандомизацию и закодировали несколько потрясающих синтезаторных риффов. Учитывая, что рандомизация является такой важной частью моих лайвкодинг сетов, я подумал, что было бы полезно раскрыть основы более подробно. Итак, наденьте свою счастливую шляпу и давайте посмотрим на несколько случайных потоков!
Первое, что можно узнать, что может вас удивить, играя с функциями рандомизации в Sonic Pi, это то, что они на самом деле не случайны. Что это на самом деле означает? Что ж, давайте предпримем пару эксперементов. Во-первых, представьте число в вашей голове от 0 до 1. Держите его там и не говорите мне. Теперь позвольте мне догадаться … это было 0.321567
? Нет? Ба, да я явно не хорош в этом. Позвольте мне еще раз, но теперь давайте попросим Sonic Pi выбрать это число. Запустите Sonic Pi v2.7 + и укажите выбрать случайное число, но не говорите мне его:
print rand
Вскроем карты … было ли это 0.75006103515625
? Да! Ха, я вижу, вы настроены немного скептически. Возможно, это была просто удачная догадка. Давай еще раз попробуем. Нажмите кнопку Выполнить еще раз и посмотрите, что мы получим … Что? 0.75006103515625
снова? Это явно не может быть случайным! Ты прав, это не так.
Что тут происходит? Одно причудливое слово из информатики - детерминизм. Это означает, что ничто не случайно и всему суждено быть. Ваша версия Sonic Pi всегда должна возвращать 0.75006103515625
в ответ на указанный выше запрос. Это может показаться довольно бесполезным, но я хочу заверить вас, что это одна из самых мощных частей Sonic Pi. Если вы задержитесь на этом, вы узнаете, как использовать детерминистскую природу рандомизации Sonic Pi в качестве основного строительного блока для ваших композиций и лайвкодинг сетов.
Когда Sonic Pi загружается, он фактически загружает в память последовательность из 441 000 предварительно сгенерированных случайных значений. Когда вы вызываете случайную функцию, такую как rand
или rrand
, этот случайный поток используется для генерации вашего результата. Каждый вызов случайной функции берет значение из этого потока. Поэтому 10-й вызов случайной функции будет использовать 10-е значение из потока. Кроме того, каждый раз, когда вы нажимаете кнопку Выполнить, для этого цикла исполнения кода, поток случайных значений сбрасывается к своему началу. Вот почему я мог предсказать результат rand
и почему «случайная» мелодия всегда была одинаковой. В каждой версии Sonic Pi используется один и тот же случайный поток, что очень важно, когда мы начинаем делиться друг с другом своими произведениями.
Давайте используем эти знания для генерации повторяемой случайной мелодии:
8.times do
play rrand_i(50, 95)
sleep 0.125
end
Введите это в свободный буфер и нажмите Выполнить. Вы услышите мелодию, состоящую из «случайных» нот от 50 до 95. Когда она закончится, снова нажмите Выполнить, чтобы снова услышать точно такую же мелодию.
Sonic Pi поставляется с рядом полезных функций для работы со случайным потоком. Вот список некоторых из самых полезных:
rand
- просто возвращает следующее значение в случайном потоке
rrand
- возвращает случайное значение в диапазоне
rrand_i
- возвращает случайное целое число в диапазоне
one_in
- возвращает true или false с заданной вероятностью
dice
- имитирует бросание костей и возвращает значение от 1 до 6
choose
- выбирает случайное значение из списка
Ознакомьтесь с документацией этих функций в справочной системе для получения подробной информации и примеров использования.
Хотя возможность повторять последовательность выбранных нот очень важна, чтобы позволить вам воспроизвести риф на танцполе, это может быть не тот рифф, который вы хотите. Разве не было бы здорово, если бы мы могли попробовать несколько разных риффов и выбрать тот, который нам больше всего понравился? Здесь начинается настоящее волшебство.
Мы можем вручную установить поток с помощью функции use_random_seed
. В информатике случайное начальное число является отправной точкой, из которой может вырасти и расцвести новый поток случайных значений. Давай попробуем:
use_random_seed 0
3.times do
play rrand_i(50, 95)
sleep 0.125
end
Отлично, так мы получаем первые три ноты нашей случайной мелодии: 84
, 83
и 71
. Однако теперь мы можем изменить семя для чего-то другого. Как насчет этого:
use_random_seed 1
3.times do
play rrand_i(50, 95)
sleep 0.125
end
Интересно, что мы получили 83
, 71
и 61
. Вы можете заметить, что первые два числа здесь такие же, как и последние два числа из тех, что мы получили ранее. И это не совпадение.
Помните, что случайный поток - это просто гигантский список предварительно сгенерированных значений. Использование случайного начального числа просто переносит нас к точке в этом списке. Другой способ думать об этом - представить огромную колоду предварительно перемешанных карт. Использование случайного семени разрезает колоду в определенной точке. Нечто потрясающее здесь в том, что именно эта возможность переноситься по случайному потоку дает нам огромные возможности при создании музыки.
Давайте вернемся к нашей случайной мелодии из 8 нот с этой новообретенной силой сброса случайного потока, но добавим также живой цикл, чтобы мы могли экспериментировать вживую, пока он играет:
live_loop :random_riff do
use_random_seed 0
8.times do
play rrand_i(50, 95), release: 0.1
sleep 0.125
end
end
Теперь, пока он все еще играет, измените начальное значение с 0 на другое. Попробуйте 100
, или даже 999
. Попробуйте свои собственные значения, поэкспериментируйте с этим - посмотрите, какое семя создает риф, который вам больше нравится.
Учебное пособие этого месяца стало погружением в техническую область функционала рандомизации в Sonic Pi. Надеемся, что это дало вам некоторое представление о том, как это работает и как вы можете использовать рандомизацию с предсказуемым результатом для создания повторяющихся паттернов в вашей музыке. Важно подчеркнуть, что вы можете использовать повторяемую рандомизацию *где угодно *. Например, вы можете рандомизировать амплитуду нот, синхронизацию ритма, количество реверберации, параметры исполняемого синтезатора, микс эффектов и т. д. В будущем мы подробно рассмотрим кое-что из этого, но сейчас позвольте мне оставить вас с коротким примером.
Введите следующее в свободный буфер, нажмите Выполнить. Затем начинайте менять значения семени рандомизации и перезапускайте код снова, пока он еще играет. Изучите таким образом различные звуки, ритмы и мелодии, которые вы можете сделать. Когда вы найдете что-то интересное, запомните номер семени, чтобы вы могли вернуться к нему. Наконец, когда вы нашли несколько понравившихся вам значений семени, устройте лайвкодинг преформанс для своих друзей, просто переключаясь между этими значениями, чтобы создать полноценный пьесу.
live_loop :random_riff do
use_random_seed 10300
use_synth :prophet
s = [0.125, 0.25, 0.5].choose
8.times do
r = [0.125, 0.25, 1, 2].choose
n = (scale :e3, :minor).choose
co = rrand(30, 100)
play n, release: r, cutoff: co
sleep s
end
end
live_loop :drums do
use_random_seed 2001
16.times do
r = rrand(0.5, 10)
sample :drum_bass_hard, rate: r, amp: rand
sleep 0.125
end
end
До сих пор в этой серии мы фокусировались на запуске звуков. Мы обнаружили, что можем запускать синтезаторы Sonic Pi с помощью play
или synth
, а предварительно записанные сэмплы с помощью sample
. Мы также рассмотрели, как обернуть эти звуки внутрь FX-контекста студийных эффектов, таких как реверберация и искажение, используя команду with_fx
. Объединив это с невероятно точной системой синхронизации Sonic Pi, вы сможете создавать огромное количество звуков, битов и риффов. Однако, как только вы тщательно выбрали параметры определенного звука и запустили его, у вас не будет возможности поиграть с ним, пока он воспроизводится, правильно? Неправильно! Сегодня вы узнаете кое-что очень мощное - как управлять работой синтезаторов.
Давайте создадим простой звук. Запустите Sonic Pi и в свободном буфере наберите следующее:
synth :prophet, note: :e1, release: 8, cutoff: 100
Теперь нажмите кнопку Выполнить в левом верхнем углу, чтобы услышать чудный грохочущий синтезаторный звук. Давайте, нажмите его еще несколько раз, чтобы хорошенько прочувствовать это. Готово? Теперь давайте поуправляем им!
Малоизвестная особенность Sonic Pi заключается в том, что функции play
, synth
и sample
возвращают нечто, называемое SynthNode, что представляет собой исполняемый звук. Вы можете захватить один из этих
SynthNode, используя стандартную переменную, а затем ** контролировать ** ее в более поздний момент времени. Например, давайте изменим значение параметр
cutoff:` после 1 такта:
sn = synth :prophet, note: :e1, release: 8, cutoff: 100
sleep 1
control sn, cutoff: 130
Давайте рассмотрим каждую строку по очереди:
Сначала мы запускаем синтезатор : prophet
, используя функцию ` synth как обычно. Кроме того, мы еще фиксируем это в переменной с именем
sn. Мы могли бы назвать эту переменную как-то иначе, например, «synth_node» или «jane» - имя не имеет значения. Однако полезно выбрать такое имя, которое будет что-то означать для вас и для людей, читающих ваш код. Я выбрал
sn`, так как это мнемонически удобное сокращение для узла синтезатора (synth node).
В строке 2 у нас есть стандартная команда sleep
. В этом нет ничего особенного - она просто просит компьютер подождать 1 такт, прежде чем перейти к следующей строке.
В строке 3 начинается веселье управления. Здесь мы используем функцию control
, чтобы указать исполняемому SynthNode
изменить значение среза фильтра на 130
. Если вы нажмете кнопку ** Выполнить **, вы услышите, как синтезатор : prophet
начнет воспроизводиться, как было прежде, но после 1 такта он будет звучать намного ярче.
Модулируемые параметры
Большинство параметров синтезаторов и эффектов в Sonic Pi могут быть изменены в процессе исполнения. Но это не относится ко всем из них. Например, параметры огибающей attack:
, decay:
, Sustain:
и release:
могут быть установлены только при запуске исполнения синтезатора. Выяснить, какие параметры можно, а какие нельзя изменять достаточно просто - перейдите к документации синтезатора или эффекта, а затем прокрутите вниз до спецификаций отдельных параметров, ориентируясь на фразы «Может быть изменено во время игры» или «Не может быть измененным после установки». Например, документация для : beep
synth’s указывает, что параметр ‘attack:`изменять нельзя:
Default: 0 Должно быть больше или равно нолю Не может быть изменено после установки Масштабируется относительно текущего значения BPM
Пока синтезатор исполняется, вы не ограничены изменять его только один раз - вы можете менять его столько раз, сколько захотите. Например, мы можем превратить наш : prophet
в мини-арпеджиатор следующим образом:
notes = (scale :e3, :minor_pentatonic)
sn = synth :prophet, note: :e1, release: 8, cutoff: 100
sleep 1
16.times do
control sn, note: notes.tick
sleep 0.125
end
В этом фрагменте кода мы только добавили пару дополнительных вещей. Сначала мы определили новую переменную с именем notes
, которая содержит ноты, которые мы хотели бы циклически перемещать (арпеджиатор - это просто причудливое имя для чего-то, что циклически перебирает список нот по порядку). Во-вторых, мы заменили наш одиночный вызов на control
итерацией, вызывающей его 16 раз. В каждом вызове control
мы проходим с помощью ` .tick наше кольцо
notes, которое будет автоматически повторяться, как только мы доберемся до конца (благодаря невероятной силе колец Sonic Pi). Для некоторого разнообразия попробуйте заменить
.tick на
.choose` и посмотрите, можете ли вы услышать разницу.
Обратите внимание, что мы можем изменять несколько параметров одновременно. Попробуйте изменить строку управления на следующую и прислушайтесь к разнице:
control sn, note: notes.tick, cutoff: rrand(70, 130)
Когда мы контролируем SynthNode
, он реагирует точно вовремя и мгновенно меняет текущее значение параметра на новое, как если бы вы нажали кнопку или щелкнули переключателем, запрашивая изменение. Это может звучать ритмично и резко - особенно если парамметр контролирует какой-нибудь аспект тембра, как , например, cutoff:
. Однако иногда вы не хотите, чтобы изменения произошли мгновенно. Вместо этого вы можете плавно перейти от текущего значения к новому, как если бы вы переместили слайдер или валкодер. Конечно, Sonic Pi также может сделать это посредством _slide:
.
Каждый параметр, который можно изменить, также имеет специальный соответствующий ему параметр _slide:
, который позволяет указать время скольжения. Например, amp:
имеет amp_slide:
, так же как cutoff:
имеет cutoff_slide:
. Эти параметры скольжения работают немного иначе, чем все остальные, в том смысле, что они сообщают синтезатору, как себя вести **во время, когда ими управляют **. Давайте взглянем:
sn = synth :prophet, note: :e1, release: 8, cutoff: 70, cutoff_slide: 2
sleep 1
control sn, cutoff: 130
Обратите внимание, что этот пример точно такой же, как и раньше, за исключением добавления cutoff_slide:
. Это говорит о том, что во время когда параметр cutoff:
этого синтезатора будет управляться, потребуется 2 такта на то, чтобы перейти от текущего значения к новому. Поэтому, когда мы используем control
, вы можете услышать скольжение значения среза фильтра от 70 до 130. Это создает интересное динамическое ощущение звука. Теперь попробуйте изменить время cutoff_slide:
на более короткое значение, такое как 0,5, или более длинное значение, такое как 4, чтобы увидеть, как это меняет звук. Помните, что вы можете перемещать любые изменяемые параметры точно таким же образом, и каждое значение _slide:
может быть совершенно разным. Вы можете одновременно медленно скользить по срезу фильтра, быстро смещать амплитуду и плавно двигаться по панораме со средней между этими значениями скоростью, ища для себя творческие новые возможности …
Давайте рассмотрим короткий пример, который демонстрирует мощь управления синтезаторами после запуска их исполнения. Обратите внимание, что вы также можете плавно изменять параметры эффектов, хотя и с немного другим синтаксисом. Ознакомьтесь с разделом 7.2 встроенного руководства для получения дополнительной информации об управлении эффектами.
Скопируйте код в свободный буфер и прослушайте его. Не останавливайтесь на достигнутом - поиграйте с кодом. Измените время скольжения, измените ноты, синтезатор, эффекты, время сна и посмотрите, сможете ли вы превратить его во что-то совершенно другое!
live_loop :moon_rise do
with_fx :echo, mix: 0, mix_slide: 8 do |fx|
control fx, mix: 1
notes = (scale :e3, :minor_pentatonic, num_octaves: 2).shuffle
sn = synth :prophet , sustain: 8, note: :e1, cutoff: 70, cutoff_slide: 8
control sn, cutoff: 130
sleep 2
32.times do
control sn, note: notes.tick, pan: rrand(-1, 1)
sleep 0.125
end
end
end
В прошлом месяце в этой серии мы углубились в систему рандомизации, на которой базируется 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
. В совокупности у нас есть все инструменты, необходимые для создания простого арпеджиатора. Нам нужно всего четыре вещи:
Кольцо, содержащее ноты, которые мы хотим зациклить. Средства увеличения и получения значения такта. Возможность воспроизведения ноты с учетом текущего такта. Структура цикла для повторения арпеджиатора.
Все эти вещи можно найти в следующем коде:
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
Еще в третьем эпизоде этой серии Sonic Pi мы рассмотрели, как зациклить, растянуть и отфильтровать один из самых известных барабанных брейков всех времен - Amen Break. В этом уроке мы сделаем еще один шаг вперед и узнаем, как нарезать сэмплы на ломтики, перемешивать их и склеивать их в совершенно новом порядке. Если это звучит немного безумно для вас, не волнуйтесь, вот-вот все станет ясно, и скоро вы освоите новый мощный инструмент для своих лайвкодинг сетов.
Прежде чем мы начнем, давайте кратко рассмотрим, как работать с сэмплами. К настоящему времени вы все, надеюсь, уже играете с мощным сэмплером Sonic Pi. Если еще нет, то прямо сейчас не самое подходящее время! Загрузите Raspberry Pi, запустите Sonic Pi из меню Программирование, введите следующее в свободный буфер и затем нажмите кнопку Выполнить, чтобы услышать предварительно записанный барабанный ритм:
sample :loop_amen
Запись звука можно представить в виде данных - множество чисел от -1 до 1, которые определяют пики и провалы звуковой волны. Если мы воспроизведем эти числа по порядку, то получим оригинальный звук. Однако что мешает нам воспроизводить их в другом порядке и создавать новый звук?
Как на самом деле записываются сэмплы? Это на самом деле довольно просто, когда вы понимаете основы физики звука. Когда вы издаете звук, например, ударяя по барабану, шум распространяется по воздуху подобно тому, как рябь распространяется по поверхности озера, когда вы бросаете в него гальку. Когда эта рябь достигает ваших ушей, ваша барабанная перепонка соответственным это волне образом движется и преобразует эти движения в звук, который вы слышите. Если мы хотим записать и воспроизвести звук, нам нужен способ захвата, хранения и воспроизведения этих волн. Одним из способов является использование микрофона, который действует как барабанная перепонка и движется туда-сюда, когда с ним встречаются волны. Затем микрофон преобразует свое текущее положение в крошечный электрический сигнал, который измеряется много раз в секунду. Эти измерения далее представляются в виде последовательности чисел от -1 до 1.
Если бы мы отразили на графике звук, это был бы простой график данных со временем по оси x и положением микрофона / динамика в диапазоне от -1 до 1 по оси y. Вы можете увидеть пример такого графика на диаграмме в верхней правой части Sonic Pi.
Итак, как же мы программируем Sonic Pi, чтобы воспроизвести сэмпл в другом порядке? Чтобы ответить на этот вопрос, нам нужно взглянуть на такие параметры sample
, как start:
и finish:
. Они позволяют нам контролировать начальную и конечную позиции воспроизведения чисел, которые представляют звук. Значения для обоих этих вариантов представлены в виде числа между 0
и 1
, где 0
это начало сэмпла, а 1
- конец. Итак, чтобы сыграть первую половину Amen Break, нам просто нужно указать finish:
из 0.5
:
sample :loop_amen, finish: 0.5
Мы можем добавить значение start:
, чтобы воспроизвести еще меньшую часть сэмпла:
sample :loop_amen, start: 0.25, finish: 0.5
Для забавы, вы можете даже задать значение параметра finish:
* перед * значением параметраstart:
, и тогда указанная часть сэмпла будет воспроизведена в обратном направлении:
sample :loop_amen, start: 0.5, finish: 0.25
Теперь, когда мы знаем, что сэмпл - это просто список чисел, которые можно воспроизвести в любом порядке, а также то, как воспроизводить определенную часть сэмпла, мы можем теперь начать веселиться, воспроизводя сэмпл в «неправильном» порядке.
Давайте возьмем наш Amen Break и нарежем его на 8 слайсов одинакового размера, а затем перемешаем кусочки. Посмотрите на диаграмму: в верхней части А) представлен график наших исходных данных. Нарезка его на 8 слайсов дает нам B) - обратите внимание, что мы дали каждому слайсу свой цвет, чтобы легче различить их. Вы можете увидеть начальные и конечные значения каждого слайса в верхней части. Наконец, C) является одним из возможных переупорядочений слайсов. Затем мы можем воспроизвести это, чтобы создать новый ритм. Взгляните на код, чтобы сделать это:
live_loop :beat_slicer do
slice_idx = rand_i(8)
slice_size = 0.125
s = slice_idx * slice_size
f = s + slice_size
sample :loop_amen, start: s, finish: f
sleep sample_duration :loop_amen, start: s, finish: f
end
мы выбираем случайный фрагмент для воспроизведения, который представлен случайным числом от 0 до 7 (помните, что мы начинаем считать с 0). Sonic Pi имеет удобную функцию именно для этого: rand_i (8)
. Затем мы сохраняем этот случайный индекс слайса в переменной slice_idx
.
Мы определяем наш slice_size
, который составляет 1/8 или 0,125. Slice_size
необходим для того, чтобы мы преобразовали наш slice_idx
в значение между 0 и 1, чтобы мы могли использовать его в качестве нашего параметра start:
.
Мы вычисляем начальную позицию s
путем умножения slice_idx
на slice_size
.
Мы рассчитываем конечную позицию f
, добавляя slice_size
к начальной позиции s
.
Теперь мы можем воспроизвести слайс сэмпла, вставив значения s
и f
в параметрыstart:
и finish:
, принадлежащие sample
.
Перед тем, как мы начнем воспроизводить следующий слайс, нам нужно знать, как долго нужно sleep
, равно длительности слайса сэмпла. К счастью, у Sonic Pi есть для нас функцияsample_duration
, которая принимает все те же параметры, что и sample
, и просто возвращает продолжительность. Поэтому, передавая sample_duration
нашим параметрам start:
и finish:
, мы можем узнать длительность одного слайса.
Мы упаковываем весь этот код в live_loop
, чтобы циклически продолжать выбирать новые случайные фрагменты для воспроизведения.
Давайте собрать в кучу все, что мы прошли к настоящему времени, в заключительный пример, который продемонстрирует, как мы можем использовать аналогичный подход для соединения случайно нарезанных барабанных ритмов с кое-каким басом, чтобы положить начало интересному треку. Теперь ваша очередь - возьмите приведенный ниже код в качестве отправной точки и посмотрите, сможете ли вы, обойдясь с ним по-своему, создать что-то новое …
live_loop :sliced_amen do
n = 8
s = line(0, 1, steps: n).choose
f = s + (1.0 / n)
sample :loop_amen, beat_stretch: 2, start: s, finish: f
sleep 2.0 / n
end
live_loop :acid_bass do
with_fx :reverb, room: 1, reps: 32, amp: 0.6 do
tick
n = (octs :e0, 3).look - (knit 0, 3 * 8, -4, 3 * 8).look
co = rrand(70, 110)
synth :beep, note: n + 36, release: 0.1, wave: 0, cutoff: co
synth :tb303, note: n, release: 0.2, wave: 0, cutoff: co
sleep (ring 0.125, 0.25).look
end
end
В предыдущем эпизоде этой серии Sonic Pi мы исследовали силу рандомизации, чтобы внести разнообразие, неожиданность и изменения в наши лайвкодинг треки и выступления. Например, мы случайным образом выбирали ноты из гаммы для создания бесконечных мелодий. Сегодня мы собираемся изучить новую технику, которая использует рандомизацию для ритма - вероятностные биты!
Прежде чем мы сможем начать делать новые биты и синтезаторные ритмы, нам нужно быстро обратиться к основам вероятности. Это может показаться пугающим и сложным, но на самом деле это так же просто, как бросать кости - честно! Когда вы берете обычные 6-ти сторонние кости для настольных игр и бросаете их, что на самом деле происходит? Ну, во-первых, вы с одинаковой вероятностью получите 1, 2, 3, 4, 5 или 6. Фактически, учитывая, что это 6-ти сторонние кости, в среднем (если вы бросаете множество раз) вы будете получать 1 каждые 6 бросков. Это означает, что у вас есть шанс 1 к 6 бросить 1. Мы можем эмулировать броски костей в Sonic Pi с помощью функции dice
. Давайте бросим с ее помощью кости 8 раз:
8.times do
puts dice
sleep 1
end
Обратите внимание, что журнал отображает значения от 1 до 6 так же, как если бы мы сами бросали реальные кости.
Теперь представьте, что у вас есть барабан, и каждый раз, когда вы собирались в него ударить, вы бросали кости. Если вы получили 1, вы били в барабан, и не били всякий раз, когда выпадало другое число. Теперь у вас есть вероятностная драм-машина, работающая с вероятностью 1/6! Давайте послушаем, как это звучит:
live_loop :random_beat do
sample :drum_snare_hard if dice == 1
sleep 0.125
end
Давайте пробежим по каждой строке, чтобы убедиться, что нам с этим все ясно. Итак, сначала мы создаем новый live_loop
с именем: random_beat
, который будет постоянно повторять две строки между do
и end
. Первая из этих строк - это вызов sample
, который будет воспроизводить предварительно записанный звук (в данном случае звук: drum_snare_hard
). Однако эта строка имеет специальное условное окончание if. Это означает, что строка будет выполнена только в том случае, если оператор в правой части if
равен true
. В нашем случае, если «dice == 1». Это вызывает нашу функцию dice
, которая, как мы видели, возвращает значение от 1 до 6. Затем мы используем оператор равенства ==
, чтобы проверить, равно ли это значение 1
. Если это 1
, то оператор сообщает true
и звучит наш малый барабан. Если это не 1
, тогда оператор сообщает false
и малый барабан не звучит. Вторая строка просто ждет 0,125 секунды, прежде чем снова бросить кости.
Те из вас, кто играл в ролевые игры, будут знакомы с множеством кубиков странной формы с различными диапазонами. Например, есть кости в форме тетраэдра, которые имеют 4 стороны и даже 20 сторонних кубиков в форме икосаэдра. Количество сторон на кости меняет шанс или вероятность получить 1. Чем меньше сторон, тем больше вероятность, что вы получите 1, и чем больше сторон, тем меньше вероятность. Например, с 4-х сторонними кубиками, есть один шанс к 4 получить 1, а с 20-ти сторонними кубиками есть шанс один к 20. К счастью, в Sonic Pi для этого есть удобная функция one_in
. Давай поиграем:
live_loop :different_probabilities do
sample :drum_snare_hard if one_in(6)
sleep 0.125
end
Запустите живой цикл выше, и вы услышите уже знакомый случайный ритм. Но не останавливайте выполнение кода. Вместо этого измените 6
на другое значение, например ` 2 или
20`, и снова нажмите кнопку Выполнить. Обратите внимание, что более низкие числа означают, что малый барабан звучит чаще, а более высокие числа означают, что реже. Вы делаете музыку с вероятностью!
Все становится действительно захватывающим, когда вы комбинируете несколько сэмплов, запускаемых с разными вероятностями. Например:
live_loop :multi_beat do
sample :elec_hi_snare if one_in(6)
sample :drum_cymbal_closed if one_in(2)
sample :drum_cymbal_pedal if one_in(3)
sample :bd_haus if one_in(4)
sleep 0.125
end
Снова запустите код выше и затем начните изменять вероятности, чтобы повлиять на ритм. Кроме того, попробуйте изменить сэмплы, чтобы создать совершенно новое звучание кода. Например, попробуйте изменить : drum_cymbal_closed
на: bass_hit_c
, чтобы добавить баса!
Затем мы можем использовать нашего старого друга use_random_seed
для сброса случайного потока после 8 итераций для создания регулярного ритма. Введите следующий код, чтобы услышать гораздо более регулярный и повторяющийся ритм. Когда вы услышите ритм, попробуйте изменить начальное значение зерна с 1000 на другое число. Обратите внимание, как разные числа генерируют разные ритмы.
live_loop :multi_beat do
use_random_seed 1000
8.times do
sample :elec_hi_snare if one_in(6)
sample :drum_cymbal_closed if one_in(2)
sample :drum_cymbal_pedal if one_in(3)
sample :bd_haus if one_in(4)
sleep 0.125
end
end
Я стараюсь запомнить, какие значения семени звучат хорошо, и сохраняю их. Таким образом, я могу легко воссоздать свои ритмы в лайвкодинг перформансах.
Наконец, мы можем добавить немного случайного баса, чтобы придать этому приятный мелодичный контент. Обратите внимание, что мы также можем использовать наш недавно обнаруженный метод вероятностного секвенирования как на синтезаторах, так и на сэмплах. Но не стоит на этом останавливаться - подгоняйте цифры и создайте собственный трек с вероятностью!
live_loop :multi_beat do
use_random_seed 2000
8.times do
c = rrand(70, 130)
n = (scale :e1, :minor_pentatonic).take(3).choose
synth :tb303, note: n, release: 0.1, cutoff: c if rand < 0.9
sample :elec_hi_snare if one_in(6)
sample :drum_cymbal_closed if one_in(2)
sample :drum_cymbal_pedal if one_in(3)
sample :bd_haus, amp: 1.5 if one_in(4)
sleep 0.125
end
end
В этом месяце мы собираемся погрузиться в : slicer
- один из самых мощных и гибких звуковых эффектов Sonic Pi. К концу этой статьи вы узнаете, как манипулировать общей громкостью частей вашего закодированного вживую звука новыми мощными способами. Это позволит вам расширить звуковые возможности, создавая новые ритмические и тембральные структуры.
Итак, что же на самом деле делает эффект : slicer
? Один из способов думать об этом - это то же самое, как когда кто-то играет с регулятором громкости на телевизоре или домашнем хай-фай. Давайте посмотрим, но сначала послушаем следующий код, который заставит прорычать для нас синтезатор : prophet
:
synth :prophet, note: :e1, release: 8, cutoff: 70
synth :prophet, note: :e1 + 4, release: 8, cutoff: 80
Теперь давайте пропустим это через эффект : slicer
:
with_fx :slicer do
synth :prophet, note: :e1, release: 8, cutoff: 70
synth :prophet, note: :e1 + 4, release: 8, cutoff: 80
end
Послушайте, как работает слайсер - он как будто заглушает и включает звук в регулярном ритме. Также обратите внимание, как : slicer
влияет на все аудио, сгенерированное между блоками do
/ end
. Вы можете контролировать скорость, с которой он включает и выключает звук, с помощью опции phase:
, которая сокращает длительность фазы. Его значение по умолчанию равно 0.25
, что означает 4 раза в секунду при значении BPM по умолчанию 60. Давайте сделаем это быстрее:
with_fx :slicer, phase: 0.125 do
synth :prophet, note: :e1, release: 8, cutoff: 70
synth :prophet, note: :e1 + 4, release: 8, cutoff: 80
end
Теперь поиграйте с разными значениями продолжительности phase:
сами. Попробуйте более длинные и короткие значения. Посмотрите, что происходит, когда вы выбираете действительно короткое значение. Кроме того, попробуйте различные синтезаторы, такие как : beep
или: dsaw
и другие ноты. Взгляните на следующую диаграмму, чтобы увидеть, как различные значения phase:
изменяют количество изменений амплитуды за такт.
Продолжительность фазы - это продолжительность одного цикла включения / выключения. Поэтому меньшие значения заставят эффект включаться и выключаться намного быстрее, чем большие значения. Хорошие значения для начала игры: 0.125
, 0.25
, 0.5
и 1
.
По умолчанию эффект : slicer
использует прямоугольную волну для управления амплитудой во времени. Вот почему мы слышим, как амплитуда включается на некоторое время, затем сразу отключается на некоторое время, затем снова включается. Оказывается, прямоугольная волна - это всего лишь одна из 4 различных управляющих волн, которые поддерживаются : slicer
. Другие это пила, треугольник и (ко)синус. Посмотрите на диаграмму ниже, чтобы увидеть, как они выглядят. Мы также можем услышать, как они звучат. Например, следующий код использует (кo)синус в качестве управляющей волны. Послушайте, как звук не включается и не выключается внезапно, а плавно затухает:
with_fx :slicer, phase: 0.5, wave: 3 do
synth :dsaw, note: :e3, release: 8, cutoff: 120
synth :dsaw, note: :e2, release: 8, cutoff: 100
end
Поиграйте с разными формами волн, изменив параметр wave:
на 0
для пилы, 1
для квадрата, 2
для треугольника и 3
для синуса. Посмотрите, как звучат разные волны с разными параметрами phase:
.
Каждая из этих волн может быть инвертирована с помощью опции invert_wave:
, который переворачивает ее на оси y. Например, в одной фазе пилообразная волна обычно начинается с высокой отметки и медленно опускается, а затем возвращается к вершине. С помощью invert_wave: 1
он медленно поднимется, прежде чем снова спрыгнуть вниз. Кроме того, управляющая волна может быть запущена в разных точках с помощью параметра phase_offset:
, который должен быть значением между 0
и 1
. Играя с параметрами phase:
, wave:
, invert_wave:
и phase_offset
, вы можете кардинально изменить способ изменения амплитуды во времени.
По умолчанию : slicer
переключает значения амплитуды 1
(максимальная громкость) и 0
(беззвучно). Это можно изменить с помощью параметров amp_min:
и amp_max:
. Вы можете использовать это вместе с синусоидальной волной, чтобы создать простой эффект тремоло:
with_fx :slicer, amp_min: 0.25, amp_max: 0.75, wave: 3, phase: 0.25 do
synth :saw, release: 8
end
Это как если бы взять ручку регулировки громкости на своем hi-fi и немного переместить ее вверх и вниз, чтобы звук «качался» внутрь и наружу динамика.
Одной из мощных функций : slicer
является его способность использовать вероятность, чтобы выбирать, включаться ему или выключаться. Перед тем как эффект : slicer
начинает новую фазу, он бросает кости и на основании результата либо использует выбранную волну управления, либо отключает амплитуду. Давайте послушаем:
with_fx :slicer, phase: 0.125, probability: 0.6 do
synth :tb303, note: :e1, cutoff_attack: 8, release: 8
synth :tb303, note: :e2, cutoff_attack: 4, release: 8
synth :tb303, note: :e3, cutoff_attack: 2, release: 8
end
Послушайте, как у нас сейчас интересно пульсирует ритм. Попробуйте изменить параметр probability:
на другое значение между 0
и 1
. Значения, близкие к 0
, будут иметь больше места между каждым отдельным звуком, поскольку вероятность того, что звук будет срабатывать, будет намного ниже.
Следует также отметить, что система вероятностей в этом эффекте подобна системе рандомизации, доступной через такие функции, как rand
и shuffle
. Они все полностью детерминированы. Это означает, что каждый раз, когда вы нажимаете Выполнить, вы слышите точно такой же пульсирующий ритм для данной вероятности. Если вы хотите что-то изменить, вы можете использовать параметр seed:
, чтобы выбрать другое начальное число. Это работает точно так же, как use_random_seed
, но влияет только на этот конкретный эффект.
Наконец, с помощью параметра prob_pos:
, вы можете изменить положение ‘resting’ для управляющей волны с 0
на любую другую позицию, когда проверка вероятности возвращает ложь, а не истину:
with_fx :slicer, phase: 0.125, probability: 0.6, prob_pos: 1 do
synth :tb303, note: :e1, cutoff_attack: 8, release: 8
synth :tb303, note: :e2, cutoff_attack: 4, release: 8
synth :tb303, note: :e3, cutoff_attack: 2, release: 8
end
Есть одна очень забавная вещь - использовать : slicer
для нарезки барабанного ритма:
with_fx :slicer, phase: 0.125 do
sample :loop_mika
end
Это позволяет нам брать любой сэмпл и создавать новые ритмические возможности, что очень весело. Однако следует быть осторожным и убедиться, что темп сэмпла соответствует текущему BPM в Sonic Pi, иначе слайсы будут звучать криво относительно ритма этого сэмпла. Например, попробуйте поменять : loop_mika
на сэмпл loop_amen
, чтобы услышать, насколько плохо это может звучать, когда темпы не совпадают.
Как мы уже видели, изменение значения BPM по умолчанию с помощью use_bpm
приведет к увеличению или уменьшению времени ожидания и длительности огибающей синтезатора в соответствии с тактом. Эффект : slicer
также учитывает это, поскольку параметр phase:
фактически измеряется в тактах, а не секундах. Поэтому мы можем исправить проблему, возникшую с loop_amen выше, изменив BPM в соответствии с примером:
use_sample_bpm :loop_amen
with_fx :slicer, phase: 0.125 do
sample :loop_amen
end
Давайте применим все эти идеи в заключительном примере, в который используем только эффект :slicer
для создания интересной комбинации. Давайте, начните изменять его и сделайте из него свое собственное произведение!
live_loop :dark_mist do
co = (line 70, 130, steps: 8).tick
with_fx :slicer, probability: 0.7, prob_pos: 1 do
synth :prophet, note: :e1, release: 8, cutoff: co
end
with_fx :slicer, phase: [0.125, 0.25].choose do
sample :guit_em9, rate: 0.5
end
sleep 8
end
live_loop :crashing_waves do
with_fx :slicer, wave: 0, phase: 0.25 do
sample :loop_mika, rate: 0.5
end
sleep 16
end
В этом уроке мы рассмотрим, как можно начать относиться к Sonic Pi как к настоящему инструменту. Поэтому нам нужно начать думать о коде совершенно по-другому. Лайвкодеры думают о коде аналогично тому, как скрипачи думают о своем смычке. Фактически, точно так же, как скрипач может применять различные техники использования смычка для создания разных звуков (длинные медленные движения против коротких быстрых ударов), мы исследуем пять основных методов лайвкодинга, которые позволяет Sonic Pi. К концу этой статьи вы сможете начать практиковаться для собственных лайвкодинг-перформансов.
Первый совет для лайвкодинга с Sonic Pi - начать использовать сокращения. Например, вместо того, чтобы тратить драгоценное время на то, чтобы дотянуться до мыши, переместить ее на кнопку Выполнить и сделать клик, вы можете просто одновременно нажать «alt» и «r», что намного быстрее и позволяет держать пальцы на клавиатуре наготове. для дальнейшего редактирования. Вы можете найти сокращения для основных кнопок вверху окна программы, наведя на них курсор мыши. См. Раздел 10.2 встроенного руководства для полного списка сокращений.
При выступлении будет забавно добавить немного изящества движениям пальцев при нажатии комбинации клавиш. Например, часто полезно общаться с аудиторией, когда вы собираетесь внести изменения - так что приукрашивайте свое движение, нажимая alt-r
так же, как это делал бы гитарист, берущий крутой аккорд.
Теперь вы можете мгновенно запускать код с клавиатуры. И вы сразу же можете применить этот навык для нашей второй техники, которая заключается в наложении звуков вручную. Вместо ‘композирования’ с использованием большого количества вызовов play
и sample
, разделенных вызовами sleep
, у нас будет один вызов play
, который мы будем запускать вручную с помощью alt-r
. Давай попробуем. Введите следующий код в свободный буфер:
synth :tb303, note: :e2 - 0, release: 12, cutoff: 90
Теперь нажмите Выполнить, и пока это звучит, измените код на следующее, чтобы запустить еще четыре ноты:
synth :tb303, note: :e2 - 4, release: 12, cutoff: 90
Теперь снова нажмите Выполнить, чтобы услышать оба звуковых слоя одновременно. Это связано с тем, что кнопка Выполнить
в Sonic Pi не ждет завершения предыдущего кода, а сразу же запускает измененный код на выполнение. Это означает, что вы можете легко наложить много звуков вручную с незначительными или существенными изменениями между каждым запуском. Например, попробуйте изменить оба параметра note:
и cutoff:
, а затем повторно запустить.
Вы также можете попробовать эту технику с длинными абстрактными сэмплами. Например:
sample :ambi_lunar_land, rate: 1
Запустите сэмпл, а затем постепенно делите параметр rate:
вдвое между каждым нажатием Выполнить
. Начав с 1
, введите 0.5
, затем ` 0.25 и наконец
0.125. Можете даже попробовать некоторые отрицательные значения, такие как
-0.5`. Накладывайте звуки один на другой и посмотрите, где вы можете это использовать. И, наконец, попробуйте добавить немного эффектов.
Работая таким образом с простыми строками кода, вы позволяете аудитории, не знакомой с Sonic Pi, следить за тем, что вы делаете, и соотносить код, который они могут прочитать, со звуками, которые они слышат.
При работе с более ритмичной музыкой часто бывает сложно вручную все запустить вовремя. Вместо этого часто лучше использовать live_loop
. Это обеспечивает повторение вашего кода, а также дает возможность редактировать код для следующего цикла. Он также будет запускаться одновременно с другими live_loop
, что означает, что вы можете объединить их вместе друг с другом и руководить их запуском. Загляните в раздел 9.2 встроенного руководства для получения дополнительной информации о работе с живыми циклами.
При выступлении не забывайте использовать параметр sync:
функции live_loop
, чтобы позволить вам вернуться в такт после случайных ошибок выполнения кода, которые останавливают живой цикл. Если у вас уже есть параметр sync:
, указывающий на другой допустимый live_loop
, то вы можете быстро исправить ошибку и перезапустить код, не потеряв такт.
Один из приятных секретов Sonic Pi заключается в том, что у него есть мастер-микшер, через который проходит весь звук. Этот микшер имеет встроенный фильтр низких частот и фильтр высоких частот, так что вы можете легко вносить глобальные изменения в звук. Доступ к функциональности главного микшера можно получить через функцию set_mixer_control!
. Например, когда какой-то код работает и производит звук, введите следующее в свободный буфер и нажмите Выполнить
:
set_mixer_control! lpf: 50
После запуска этого кода ко всем уже существующим и новым звукам будет применен фильтр низких частот, и, следовательно, они будут звучать более приглушенно. Заметьте, это означает, что эти значения микшера остаются таковыми, пока не будут изменены снова. Однако, если вы хотите, вы всегда можете вернуть микшер обратно в состояние по умолчанию с помощью reset_mixer!
. Вот некоторые из поддерживаемых параметров: pre_amp:
, lpf:
hpf:
и amp:
. Полный список см. Во встроенной документации для set_mixer_control!
.
Используйте параметры микшера * _slide
для плавного скольжения одного или нескольких значений параметров во времени. Например, чтобы медленно передвинуть срез фильтр низких частот с текущего значения вниз до 30, используйте следующее:
set_mixer_control! lpf_slide: 16, lpf: 30
Затем вы можете быстро вернуться к высокому значению с помощью:
set_mixer_control! lpf_slide: 1, lpf: 130
При выступлении часто полезно держать один буфер свободным, чтобы работать с микшером.
Самым важной техникой для лайвкодинга является практика. Наиболее распространенным атрибутом среди профессиональных музыкантов всех видов является то, что они практикуют игру на своих инструментах - часто по много часов в день. Практика так же важна для лайвкодера, как и для гитариста. Практика позволяет вашим пальцам запоминать определенные шаблоны и общие изменения, чтобы вы могли набирать текст и работать с ними более свободно. Практика также дает вам возможность исследовать новые звуки и структуры кода.
Во время выступления вы обнаружите, что чем больше вы практикуетесь, тем более расслабленным вы будите перед аудиторией. Практика также даст вам богатый источник для извлечения уроков. Это может помочь вам понять, какие модификации будут интересны, а также как лучше работать с текущими звуками.
В этом месяце, вместо того, чтобы дать вам последний пример, который объединяет все пройденное, давайте расстанемся, бросив вызов. Проверьте, сможете ли вы потратить неделю, практикуя одну из описанных идей каждый день. Например, один день практикуете запуск вручную, на следующий выполняете базовую работу с live_loop
, а на другой день играете с мастер-микшером. Затем повторите это. Не беспокойтесь, если поначалу будет казаться, что все происходит медленно и неуклюже - просто продолжайте практиковаться, и вы станете лайвкодером для реальной аудитории, прежде чем успеете это осознать.
В прошлом месяце мы рассмотрели пять важных методов освоения лайвкодинга - другими словами, мы исследовали, как мы могли бы использовать Sonic Pi, подходя к коду так же, как мы подходили бы к музыкальному инструменту. Одной из важных концепций, которые мы обсуждали, была практика. В этом месяце мы углубимся в понимание того, почему практика лайвкодинга важна и как вы можете ее начать.
Самый важный совет - регулярно заниматься. Как правило, я обычно тренируюсь по 1-2 часа в день, но и 20 минут - это хорошо, когда вы начинаете. Пусть немного, но регулярно это то, к чему вам нужно стремиться - поэтому, даже если пока вы можете справиться только с 10 минутами, это отличное начало.
Практический совет № 1 - начните разрабатывать рутинную практику. Найдите подходящее время в подходящий день, и постарайтесь практиковать в это время столько дней недели, сколько сможете. Вскоре вы будете с нетерпением ждать вашей очередной сессии.
Если вы посмотрите на выступление профессиональных музыкантов, вы, вероятно, заметите несколько вещей. Во-первых, когда они играют, они не смотрят на свой инструмент. Их пальцы, руки и тело знают, на какие клавиши нажимать, какие струны касаться или в какие барабаны ударять, и им не нужно слишком много думать об этом. Это известно как «мышечная память». И, хотя это может звучать так, как если бы этим могли заниматься только профессионалы, - на деле это то же самое, как и когда вы впервые научились ходить или ездить на велосипеде - необходимо только настойчиво практиковаться. Лайвкодеры используют мышечную память, чтобы освободить свой ум от необходимости думать о том, куда двигать пальцами, в пользу сосредоточения на музыке. Это называется слепым набором текста - без необходимости смотреть на клавиатуру.
Практический совет #2 - тренируйте слепой набор. Есть множество приложений, вебсайтов и даже игр, которые могут помочь вам в этом деле. Найдите то, которое вам нравится и поупражняйтесь в нём, пока у вас не получится набирать текст не глядя.
Тело музыканта приспособлено к игре на его инструменте. Например, трубач должен уметь сильно дуть, гитарист должен уметь крепко держать гриф, а барабанщик должен уметь непрерывно ударять по барабанам в течение длительного периода времени. Итак, что же на уровне тела важно в лайвкодинге? Как и диджеи, лайвкодеры обычно выступают стоя, а некоторые даже танцуют, пока пишут! Если вы постоянно практикуете лайвкодинг сидя за столом, и однажды вам случится выступать перед аудиторией, то не имея навыка работать с кодом стоя, вы скорее всего испытаете серьезные трудности.
Практический совет № 3 - стойте во время тренировки. Самый простой способ сделать это - использовать стол с высокой рабочей поверхностью. Однако, если, как и у меня, его у вас в доме нет, то есть пара вариантов на замену. Я использую гладильную доску, которая работает в этом качестве довольно хорошо. Другой способ - расположить несколько коробок или больших книг на обычном столе и на них положить вашу клавиатуру. Кроме того, не забудьте размяться перед тем, как начать практиковать, и попробуйте немного потанцевать во время вашей сессии. Помните, никто не смотрит на вас, так что повеселитесь, и вы будете чувствовать себя намного более естественно на сцене.
Большинство инструментов требуют некоторой сборки и настройки, прежде чем на них можно будет играть. Если вы не рок-звезда с автобусом, полным помощников, вы сами должны настроить свой собственный инструмент перед своим выступлением. Это часто довольно не простое дело, и здесь часто возникают проблемы. Один из способов справиться с этим - включить процесс настройки в свои практические занятия.
Практический совет № 4 - рассматривайте установку и настройку оборудования как важную часть вашей практики. Например, возьмите с собой коробку или сумку, в которой можно хранить Raspberry Pi, клавиатуру и т. д. Перед каждой тренировочной сессией вынимайте все элементы вашего оборудования, соединяйте их вместе, делайте все, что необходимо вплоть до того, пока не запустите Sonic Pi и не сможете издавать звуки. Как только вы закончите практиковать, не торопитесь, займитесь тем, чтобы все тщательно упаковать. Сначала это может занять некоторое время, но вскоре вы сможете невероятно быстро собрать и разобрать все необходимое, не задумываясь об этом.
Как только вы настроите ваше оборудование и уже будете готовы начать создавать музыку, вы можете испытать затруднения с тем, чтобы сходу понять, с чего начать. Проблема, с которой сталкиваются многие люди, заключается в том, что они могут хорошо представлять звуки, которые они хотят произвести, но разочаровываются тем, что у них выходит на деле. А некоторые люди и вовсе не знают, какие звуки они хотят издавать! Прежде всего, не нужно волноваться - это очень распространенная история и она случается с каждым музыкантом - даже если они занимаются музыкой в течение длительного времени. Здесь гораздо важнее издавать звуки, даже те, которые вам не нравятся, чем вообще не издавать никаких звуков.
Практический совет № 5 - тратьте время на создание даже таких звуков и музыки, которые вам не нравятся. Постарайтесь найти время для изучения новых звуков и идей. Не волнуйтесь, это звучит ужасно, и не так, как бы вы хотели. Когда вы экспериментируете таким образом, вы увеличиваете вероятность наткнуться на звук или комбинацию звуков, которые вы полюбите! Даже если 99% ваших звуков плохие, этот 1% может стать главным риффом или вступлением к вашему новому треку. Забудьте о том, что у вас не выходит все сразу, и помните, что вам может пригодиться часть того, что вы сделали прямо сейчас. Это даже проще, когда вы пишете музыку с кодом - просто нажмите «Сохранить»!
Многие музыканты могут смотреть на музыкальное нотацию и слышать музыку в своей голове, не играя ее. Это очень полезный навык, и его стоит развить в своих практических занятих по лайвкодингу. Важным моментом является способность иметь некоторое представление о том, как будет звучать код. Вам не нужно быть в состоянии услышать это в своей голове в точности, но полезно знать, будет ли код быстрым, медленным, громким, ритмичным, мелодичным, случайным и т. д. Окончательная цель состоит в том, чтобы иметь возможность полностью обратить этот процесс - сначала суметь услышать музыку в голове, и потом найти, какой код написать для ее создания. Это может занять много времени, но как только вы овладеете этим, вы сможете импровизировать на сцене и свободно выражать свои идеи.
Практический совет № 6 - напишите какой-нибудь код в Sonic Pi, но не нажимайте кнопку Выполнить. Вместо этого попытайтесь представить, какой звук он произведет. Затем нажмите Выполнить, слушайте и думайте о том, верно ли вы предположили или нет. Продолжайте повторять, пока это не станет естественной частью вашего процесса кодирования. Когда занимаюсь, я обычно хорошо представляю, как будет звучать код. Тем не менее, я все еще иногда ошибаюсь, и провожу некоторое время, размышляя о том, почему я был неправ. Каждый раз, когда это происходит, я учусь новым трюкам, которые позволяют мне выразить себя по-новому.
Обычная проблема во время практики - отвлекаться на другие вещи. Практика сложна и требует настоящей дисциплины, независимо от того, какую музыку вы делаете - от джаза до классики и EDM. Если вы изо всех сил пытаетесь начать или добиться прогресса, часто слишком легко отвлечься на социальные сети, начать искать что-то в Интернете и т. д. Если вы поставили себе цель 20 минут практики, важно попробовать тратить все это время как можно более продуктивно.
Практический совет № 7 - прежде чем начать практиковаться, удалите как можно больше отвлекающих факторов. Например, отключитесь от Интернета, поместите свой телефон в другую комнату и попробуйте потренироваться в тихом месте, где вас вряд ли будут беспокоить. В этот момент попытайтесь сосредоточиться на кодировании музыки, ведь вы сможете вернуться к тому, что вас отвлекает, когда закончите.
Когда вы практикуете, вы часто обнаруживаете, что ваш ум полон новых захватывающих идей - новых направлений в исследовании музыки, новых звуков, которые нужно опробовать, новых функций для записи в код и т. д. Эти идеи часто настолько интересны, что вы можете остановить то, что вы делаете и начать работать над ними. Это еще одна форма отвлечения!
Практический совет № 8 - ведите дневник тренировок. Когда у вас появляется новая захватывающая идея, временно приостановите тренировочную сессию, быстро набросайте идею, затем забудьте о ней и продолжайте практиковаться. Вы можете потратить некоторое время на обдумывание и проработку своих идей после того, как закончите практиковать.
Постарайтесь завести практику, которая включает в себя как можно больше из этих идей. Постарайтесь, чтобы занятия проходили как можно более увлекательно, но имейте в виду, что некоторые тренировки будут трудными и будут немного походить на работу. Однако, все это будет стоить того, как только вы создадите свою первую пьесу или дадите свое первое выступление. Помните, практика - это ключ к успеху!
Когда люди открывают для себя Sonic Pi, первое, что они узнают, это то, как проиграть предварительно записанные звуки с помощью функции sample
. Например, вы можете сыграть индустриальную барабанную петлю, услышать звук хора или даже прослушать виниловой скретч через одну единственную строку кода. Однако многие люди не понимают, что могут изменить скорость воспроизведения сэмпла для получения некоторых мощных эффектов и совершенно нового уровня контроля над записанными звуками. Итак, запустите Sonic Pi и давайте начнем растягивать некоторые сэмплы!
Чтобы изменить скорость воспроизведения сэмпла, нам нужно использовать параметр rate:
:
sample :guit_em9, rate: 1
Если мы укажем rate:
значение 1
, то сэмпл воспроизведется с нормальной скоростью. Если мы хотим воспроизвести его с половиной начальной скорости, мы просто используем для rate:
значение 0.5
:
sample :guit_em9, rate: 0.5
Обратите внимание, что это производит два эффекта на аудио. Во-первых, сэмпл звучит ниже по высоте, а во-вторых, для воспроизведения требуется вдвое больше времени. Мы можем выбрать все более низкие значения, двигаясь в сторону 0
. Так rate:
в значении ` 0.25 - это четверть скорости,
0.1` - это десятая часть скорости и т. д. Попробуйте поиграть с некоторыми низкими значениями и посмотрите, как вы можете превратить звук в низкий грохот.
Помимо удлинения звука и его тональности посредством низких значений rate
, мы можем использовать высокие значения, чтобы сделать звук короче и выше. Давайте на этот раз поиграем с барабанной петлей. Сначала послушайте, как это звучит со скоростью по умолчанию 1
:
sample :loop_amen, rate: 1
Теперь давайте немного ускорим:
sample :loop_amen, rate: 1.5
Ха! Мы просто сменили музыкальные жанры из техно-стиля в джангл. Обратите внимание, что высота каждого удара барабана стала выше, а также как ускоряется и весь ритм. Теперь попробуйте еще более высокие значения и посмотрите, насколько высокими и короткими вы можете сделать барабанную петлю. Например, если вы используете значение 100
, барабанная петля превращается в щелчок!
Теперь, я уверен, что многие из вас думают об одном и том же прямо сейчас … «что если вы используете отрицательное значение для rate:
?». Отличный вопрос! Давайте подумаем об этом на мгновение. Если наш параметр rate:
обозначает скорость, с которой воспроизводится сэмпл, где 1
- нормальная скорость, 2
- двойная скорость, 0.5
- половинная скорость, -1
должно означать задом наперед! Давайте попробуем это на малом барабане. Сначала воспроизведите его с нормальной скоростью:
sample :elec_filt_snare, rate: 1
Теперь проиграем это в обратном направлении:
sample :elec_filt_snare, rate: -1
Конечно, вы можете играть в обратном направлении в два раза быстрее со значением -2
или назад в половину скорости со значением -0.5
. Теперь поиграйте с разными отрицательными значениями и получайте удовольствие. Это особенно забавно с сэмплом : misc_burp
!
Одним из эффектов изменения скорости на сэмплах является то, что более высокие значения приводят к тому, что сэмплы звучат выше по высоте, а более медленные скорости приводят к тому, что сэмплы звучат ниже по высоте. Другая ситуация, в которой вы, возможно, слышали этот эффект в повседневной жизни, - это когда вы едете на велосипеде или проезжаете мимо громкого пешеходного перехода - когда вы направляетесь к источнику звука, высота звука выше, чем при удалении от звука - это так называемый эффект Доплера. Почему это так?
Давайте рассмотрим простой звуковой сигнал, который представлен синусоидальной волной. Если мы используем осциллограф для построения звукового сигнала, мы увидим что-то вроде рисунка А. Если мы построим звуковой сигнал на октаву выше, мы увидим рисунок Б, а октава ниже будет выглядеть как на рисунке С. Обратите внимание, что волны более высокого уровня ноты более компактны, а волны нижних нот более длинные.
Сэмпл аналогового сигнала - это не что иное, как множество чисел (x, y, координаты), которые при перенесении на график воссоздают с той или иной точностью исходную звуковую волну. Смотрите рисунок D, где каждая точка представляет координату. Чтобы преобразовать координаты обратно в звук, компьютер соединяет каждое значение x с со соответствующим значением y и отправляет в динамики. Хитрость в том, что скорость, с которой компьютер работает с числами х, не обязательно должна совпадать со скоростью, с которой они были записаны. Другими словами, пространство (представляющее количество времени) между каждой точкой координат может быть растянуто или сжато. Таким образом, если компьютер будет проходить через значения x быстрее, чем исходная скорость, это приведет к сжатию координат ближе друг к другу, что приведет к более высокому тону сигнала. Также это сделает звуковой сигнал короче, так как мы будем проходить все координаты быстрее. Это показано на рисунке E.
Наконец, еще одна вещь, которую нужно знать, это то, что математик по имени Фурье доказал, что любой звук на самом деле - это множество синусоидальных волн, объединенных вместе. Поэтому, когда мы сжимаем и растягиваем любой записанный звук, мы фактически растягиваем и сжимаем множество синусоидальных волн одновременно.
Как мы уже видели, использование более высокой частоты сделает звук более высоким по тональности, а более медленной - более низким. Очень простой и полезный трюк состоит в том, чтобы знать, что удвоение скорости фактически приводит к тому, что высота тона становится на октаву выше, а обратное уменьшение частоты вдвое приводит к снижению высоты тона на октаву. Это означает, что для мелодичных сэмплов воспроизведение его вместе с двойной / половиной исходной скорости звучит довольно неплохо:
sample :bass_trance_c, rate: 1
sample :bass_trance_c, rate: 2
sample :bass_trance_c, rate: 0.5
Однако что, если мы просто хотим изменить скорость так, чтобы высота звука повышалась на один полутон (одна клавиша на фортепиано)? Sonic Pi делает это очень легко с помощью параметра rpitch:
:
sample :bass_trance_c
sample :bass_trance_c, rpitch: 3
sample :bass_trance_c, rpitch: 7
Если вы посмотрите в журнал, то заметите, что rpitch:
в значении 3
фактически соответствует скорости 1.1892
, а rpitch:
в значении 7
соответствует скорости 1.4983
. Наконец, мы можем даже объединить параметрыrate:
и rpitch:
:
sample :ambi_choir, rate: 0.25, rpitch: 3
sleep 3
sample :ambi_choir, rate: 0.25, rpitch: 5
sleep 2
sample :ambi_choir, rate: 0.25, rpitch: 6
sleep 1
sample :ambi_choir, rate: 0.25, rpitch: 1
Давайте посмотрим на простую пьесу, которая объединяет в себе эти идеи. Скопируйте ее в свободный буфер Sonic Pi, нажмите play, послушайте некоторое время, а затем используйте его в качестве отправной точки для вашего собственного произведения. Посмотрите, как весело управлять скоростью воспроизведения сэмплов. В качестве дополнительного упражнения попробуйте записать свои собственные сэмплы и поиграйте со скоростью, чтобы увидеть, какие сумасшедшие звуки вы можете издавать.
live_loop :beats do
sample :guit_em9, rate: [0.25, 0.5, -1].choose, amp: 2
sample :loop_garzul, rate: [0.5, 1].choose
sleep 8
end
live_loop :melody do
oct = [-1, 1, 2].choose * 12
with_fx :reverb, amp: 2 do
16.times do
n = (scale 0, :minor_pentatonic).choose
sample :bass_voxy_hit_c, rpitch: n + 4 + oct
sleep 0.125
end
end
end
Это первая из короткой серии статей о том, как использовать Sonic Pi для саунд дизайна. Мы проведем краткий обзор различных методов, доступных для вас, чтобы создать свой собственный уникальный звук. Первый метод, который мы рассмотрим, называется * аддитивный синтез *. Это может показаться сложным - но если мы немного внимательнее рассмотрим здесь каждое слово, то смысл сразу появится на поверхности. Во-первых, аддитивный означает сочетание нескольких вещей, а во-вторых, синтез означает создание звука. Следовательно, аддитивный синтез не означает ничего более сложного, чем * объединение существующих звуков для создания новых *. Эта методика синтеза восходит к очень давним временам - например, у трубных органов в средние века было много слегка отличающихся по звучанию трубок, которые вы могли включать или отключать с помощью специальных заглушек. Вытягивание заглушки из данной трубы «добавило ее в микс», сделав звук более насыщенным и сложным. Теперь давайте посмотрим, как мы можем вытащить все заглушки с Sonic Pi.
Давайте начнем с самого основного звука -простой синусоиды с чистыми тонами:
synth :sine, note: :d3
Теперь давайте посмотрим, как это звучит в сочетании с прямоугольной волной:
synth :sine, note: :d3
synth :square, note: :d3
Обратите внимание, как эти два звука объединяются, чтобы сформировать новый, более богатый звук. Конечно, нам не нужно останавливаться на достигнутом, мы можем добавить столько звуков, сколько хотим. Однако мы должны быть осторожны с тем, сколько звуков мы смешиваем. Точно так же, как когда мы смешиваем краски для создания новых цветов, добавление слишком большого количества цветов приведет к грязному коричневому цвету, аналогично - добавление слишком большого количества звуков вместе приведет к грязному звуку.
Давайте добавим что-нибудь, чтобы это зазвучало немного ярче. Мы могли бы использовать треугольную волну на октаву выше (для яркого звука), но воспроизводить ее с амплитудой 0.4
, чтобы она только добавила кое-то к звуку, а не перетянула все на себя:
synth :sine, note: :d3
synth :square, note: :d3
synth :tri, note: :d4, amp: 0.4
Теперь попробуйте создать свои собственные звуки, комбинируя 2 или более синтезатора с разными октавами и амплитудами. Также обратите внимание, что вы можете поиграть с опциями каждого синтезатора, чтобы модифицировать каждый исходный звук, прежде чем он будет смешан для еще большего количества комбинаций звуков.
Пока что, комбинируя наши разные синтезаторы, мы использовали либо одинаковую высоту, либо переключали октаву. Как это могло бы звучать, если бы мы не придерживались октав, а вместо этого выбрали чуть более высокую или более низкую ноту? Давай попробуем:
detune = 0.7
synth :square, note: :e3
synth :square, note: :e3 + detune
Если мы расстроем наши прямоугольные волны на 0,7 ноты, мы услышим что-то, что, возможно, звучит не в гармонии или не правильно - как «плохая» нота. Однако, когда мы приближаемся к 0, это будет звучать все менее и менее заметно, так как высота звука двух волн становится все ближе и ближе. Попробуйте сами! Измените значение параметра detune:
с 0.7
на 0.5
и прослушайте новый звук. Попробуйте 0.2
, 0.1
, 0.05
, 0
. Каждый раз, когда вы меняете значение, прислушайтесь и посмотрите, можете ли вы услышать, как меняется звук. Обратите внимание, что низкие значения расстройки, такие как 0.1
, производят действительно хороший «толстый» звук, при этом оба немного отличающихся тона взаимодействуют друг с другом интересным, часто удивительным, способом.
Некоторые из встроенных синтезаторов уже включают опцию расстройки, которая делает это в пределах одного синтезатора. Попробуйте поиграть с параметром detune:
синтезаторов : dsaw
,: dpulse
и : dtri
.
Еще один способ, которым мы можем точно создать свой звук, - это использовать разные огибающие и параметры для каждого запускаемого синтезатора. Например, это позволит вам воспроизвести некоторые аспекты перкуссионного звука, и другие, в течение времени звучания.
detune = 0.1
synth :square, note: :e1, release: 2
synth :square, note: :e1 + detune, amp: 2, release: 2
synth :gnoise, release: 2, amp: 1, cutoff: 60
synth :gnoise, release: 0.5, amp: 1, cutoff: 100
synth :noise, release: 0.2, amp: 1, cutoff: 90
В приведенном выше примере я смешал шумовой перкуссионный элемент с настойчивым грохочущим призвуком. Это было достигнуто в первую очередь за счет использования двух синтезаторов шума со средними значениями среза частоты фильтра (90
и 100
) и с использованием короткого времени высвобождения (release) наряду с шумом с более длительным временем высвобождения, но с низким значением частоты среза фильтра (что делает шум менее четким и более гудящим.)
Давайте объединим все эти методы, чтобы увидеть, сможем ли мы использовать аддитивный синтез для воссоздания простого звука колокольчика. Я разбил этот пример на четыре раздела. Во-первых, у нас есть секция «hit», которая является начальной частью звука колокольчика, поэтому мы используем быструю огибающую (например, release:
около 0.1
). Затем у нас есть длинный участок звука колокольчика, в котором я использую чистый звук синусоиды. Обратите внимание, что я часто увеличиваю ноту примерно на 12
и 24
, которые представляют собой количество нот в одной и двух октавах. Я также добавил пару низких синусоидальных волн, чтобы придать звуку немного баса и глубины. Наконец, я использовал define
, чтобы обернуть мой код в функцию, которую затем я могу использовать для воспроизведения мелодии. Попробуйте сыграть свою собственную мелодию, а также поиграться с содержанием функции : bell
, пока не создадите свой собственный сумасшедший звук для игры!
define :bell do |n|
# Triangle waves for the 'hit'
synth :tri, note: n - 12, release: 0.1
synth :tri, note: n + 0.1, release: 0.1
synth :tri, note: n - 0.1, release: 0.1
synth :tri, note: n, release: 0.2
# Sine waves for the 'ringing'
synth :sine, note: n + 24, release: 2
synth :sine, note: n + 24.1, release: 2
synth :sine, note: n + 24.2, release: 0.5
synth :sine, note: n + 11.8, release: 2
synth :sine, note: n, release: 2
# Low sine waves for the bass
synth :sine, note: n - 11.8, release: 2
synth :sine, note: n - 12, release: 2
end
# Play a melody with our new bell!
bell :e3
sleep 1
bell :c2
sleep 1
bell :d3
sleep 1
bell :g2
Это вторая статья из серии статей о том, как использовать Sonic Pi для саунд дизайна. В прошлом месяце мы рассмотрели аддитивный синтез, который, как мы обнаружили, представлял собой простой процесс одновременного воспроизведения нескольких звуков для создания нового комбинированного звука. Например, мы могли бы комбинировать разные звучащие синтезаторы или даже один и тот же синтезатор на разных высотах, чтобы создать новый сложный звук из простых ингредиентов. В этом месяце мы рассмотрим новую технику, обычно называемую * субтрактивным синтезом *, которая представляет собой акт извлечения существующего сложного звука и удаления его частей для создания чего-то нового. Это метод, который обычно ассоциируется со звуком аналоговых синтезаторов 1960-х и 1970-х годов, а также с недавним возрождением модульных аналоговых синтезаторов в популярных стандартах, таких как Eurorack.
Несмотря на то, что это звучит как очень сложная и продвинутая техника, Sonic Pi делает ее на удивление простой и легкой - так что давайте погрузимся в нее.
Чтобы звук хорошо работал в субтрактивном синтезе, он должен быть достаточно насыщенным и интересным. Это не значит, что нам нужно что-то чрезвычайно сложное - на самом деле, стандартная волна : square
или: saw
сделает что нужно:
synth :saw, note: :e2, release: 4
Обратите внимание, что этот звук уже довольно интересен и содержит много разных частот выше : e2
(E второй октавы на фортепиано), которые добавляются для создания тембра. Если для вас это пока не особенно понятно, попробуйте сравнить его с : beep
:
synth :beep, note: :e2, release: 4
Поскольку синтезатор : beep
- это просто синусоида, вы услышите более чистый тон и только в регистре : e2
и не буде выше него никаких хрустящих / гудящих звуков, которые вы слышали в : saw
. Именно с этими призвуками и вариациями чистой синусоидальной волны мы можем играть, используя субтрактивный синтез.
Как только у нас будет исходный сигнал, следующий шаг - пропустить его через какой-нибудь фильтр, который будет изменять звук, удаляя или уменьшая его части. Один из наиболее распространенных фильтров, используемых для вычитающего синтеза, называется фильтром нижних частот. Он позволит пропустить все низкие части звука, но уменьшит или удалит верхние. Sonic Pi имеет мощную, но простую в использовании систему эффектов, которая включает в себя фильтр низких частот, называемый : lpf
. Давайте поиграем с этим:
with_fx :lpf, cutoff: 100 do
synth :saw, note: :e2, release: 4
end
Если вы внимательно прослушаете, вы услышите, как некоторые из этих шумных и хрустящих звуков были удалены. Фактически, все частоты в звуке выше ноты 100
были уменьшены или удалены, и только те, что ниже, все еще присутствуют в звуке. Попробуйте изменить значение cutoff:
, укажите ему на более низкие ноты, скажем 70
, а затем 50
и сравните звуки.
Конечно, : lpf
не единственный фильтр, который вы можете использовать для манипулирования исходным сигналом. Другим важным эффектом является фильтр верхних частот, в Sonic Pi называемый : hpf
. Это противоположно : lpf
в том смысле, что пропускает верхние части звука и обрезает низкие.
with_fx :hpf, cutoff: 90 do
synth :saw, note: :e2, release: 4
end
Обратите внимание, что теперь это звучит гораздо более шумно и скрипуче, когда все низкочастотные звуки были удалены. Поиграйте со значением среза - обратите внимание, как низкие значения позволяют большему количеству басовых частей исходного сигнала проходить, а более высокие значения звучат все более жесткими и тихими.
Фильтр нижних частот является настолько важной частью каждого субтрактивного инструментария синтеза, что стоит более глубоко взглянуть на его работу. Эта диаграмма показывает одну и ту же звуковую волну (синтезатор : prophet
) с различной степенью фильтрации. Вверху в разделе A показана звуковая волна без фильтрации. Обратите внимание, что форма волны очень острая и содержит много острых краев. Именно эти жесткие, острые углы создают высокие хрустящие / шумные части звука. В разделе B показан фильтр нижних частот в действии - обратите внимание, что он менее острый и более округлый, чем форма волны выше. Это означает, что у звука будет меньше высоких частот, что придаст ему более мягкий округлый вид. В разделе C показан фильтр нижних частот с довольно низким значением отсечки - это означает, что еще больше высоких частот было удалено из сигнала, что привело к еще более мягкой, округлой форме волны. Наконец, обратите внимание, как размер формы волны, которая представляет амплитуду, уменьшается при переходе от А к С. Субтрактивный синтез работает путем удаления частей сигнала, что означает, что общая амплитуда уменьшается по мере того, как объем фильтрации увеличивается.
Пока что мы только что создали довольно статичные звуки. Другими словами, звук никак не меняется в течение всей его продолжительности. Часто вам может понадобиться какое-то движение в звуке, чтобы оживить тембр. Одним из способов достижения этого является модуляция фильтра - изменение параметров фильтра во времени. К счастью, Sonic Pi дает вам мощные инструменты для манипулирования параметрами эффектов во времени. Например, вы можете установить время скольжения для каждого модулируемого параметра, чтобы указать, сколько времени потребуется, чтобы текущее значение линейно скользило к заданному :
with_fx :lpf, cutoff: 50 do |fx|
control fx, cutoff_slide: 3, cutoff: 130
synth :prophet, note: :e2, sustain: 3.5
end
Давайте кратко рассмотрим, что здесь происходит. Сначала мы запускаем FX-блок : lpf
как обычно с начальным cutoff:
с очень низким значением 20
. Тем не менее, первая строка также заканчивается странным | fx |
в конце. Это необязательная часть синтаксиса with_fx
, которая позволяет вам напрямую называть и управлять запущенным эффектом синтезатора. Строка 2 управляет таким эффектом, устанавливая для параметра cutoff_slide:
значение 4, а целевое значение cutoff:
должно быть 130
. Эффект теперь начнет снижать значение параметра cutoff:
с 50
до 130
в течение 3 тактов. Наконец, мы запускаем синтезатор, чтобы слышать эффект модулированного фильтра нижних частот.
Это очень простой пример того, что возможно, когда вы используете фильтры для модификации и изменения исходного звука. Попробуйте поиграть с множеством встроенных эффектов Sonic Pi, чтобы увидеть, какие сумасшедшие звуки вы можете создать. Если ваш звук кажется слишком статичным, помните, что вы можете начать модулировать параметры, чтобы создать движение.
Давайте закончим, разработав функцию, которая будет воспроизводить новый звук, созданный с субтрактивным синтезом. Посмотрите, сможете ли вы выяснить, что здесь происходит, - и для продвинутых читателей Sonic Pi - посмотрите, сможете ли вы понять, почему я завернул все в вызов функции at
(пожалуйста, отправьте ответы на @samaaron в Twitter).
define :subt_synth do |note, sus|
at do
with_fx :lpf, cutoff: 40, amp: 2 do |fx|
control fx, cutoff_slide: 6, cutoff: 100
synth :prophet, note: note, sustain: sus
end
with_fx :hpf, cutoff_slide: 0.01 do |fx|
synth :dsaw, note: note + 12, sustain: sus
(sus * 8).times do
control fx, cutoff: rrand(70, 110)
sleep 0.125
end
end
end
end
subt_synth :e1, 8
sleep 8
subt_synth :e1 - 4, 8
(This article was published in issue 9 of the Hello World Magazine)
Code is one of the most creative media that humans have created. The initially obscure symbols of parentheses and lambdas are not just deeply rooted in science and mathematics, they are the closest we have managed to get to casting the same kind of magical spells as Gandalf and Harry Potter. I believe that this provides a powerful means of engagement in our learning spaces. Through the magic of code we are able to conjure up individually meaningful stories and learning experiences.
We are surrounded by magical experiences. From the sleight of hand of a stage magician making the ball disappear into thin air, to the wonder of seeing your favourite band perform on a big stage. It is these “wow” moments that inspire us to pick up a magic book and learn the French Drop or to start jamming power chords on an old guitar. How might we create similarly deep and lasting senses of wonder that will motivate people to practice and learn the fundamentals of programming?
The histories of music and computers have been intricately woven together since the inception of computing machines, or “engines” as Charles Babbage’s powerful analytical engine was called. Back in 1842 the Mathematician Ada Lovelace, who worked very closely with Babbage, saw the creative potential of these engines. Whilst these first engines had originally been designed to accurately solve hard maths problems, Ada dreamt about making music with them:
”..the engine might compose elaborate and scientific pieces of music of any degree of complexity or extent.” Ada Lovelace, 1842.
Of course, today in 2019 much of our music, regardless of genre, has either been composed, produced or mastered with a digital computer. Ada’s dream came true. It is even possible to trace the history back even further. If you see coding as the art of writing sequences of special symbols that instruct a computer to do specific things, then musical composition is a very similar practice. In Western music, the symbols are black dots positioned on a stave of lines that tell the musician which notes to play and when. Intriguingly, if we trace the roots of Western music notation back to the Italian Benedictine monk, Guido d’Arezzo, we find that the dots and lines system that modern orchestras use is just one of a number of notation systems he worked on. Some of the others were much closer to what we might now see as code.
Get
Лайв-кодинг
Sonic Pi has been used to perform in a wide range of venues such as school halls, nightclubs, outdoor stages at musical festivals, college chapels and prestigious music venues. For example the amazing Convo project which brought 1000 children together in the Royal Albert Hall to perform an ambitious new composition by composer Charlotte Harding. The piece was written for traditional instruments, choirs, percussion and Sonic Pi code. The pop-artist Jylda also performed with Sonic Pi in the Sage Gateshead for the Thinking Digital Conference, where she created a unique live-coded improvised remix of her song Reeled.
Sonic Pi used as one of the instruments as part of Convo at the Royal Albert Hall. Photo credit: Pete Jones.
Sonic Pi is a code-based music creation and performance tool that builds on all of these ideas. Unlike the majority of computing education software, it is both simple enough to use for education and also powerful enough for professionals. It has been used to perform in international music festivals, used to compose in a range of styles from classical, EDM and heavy metal, and was even reviewed in the Rolling Stone magazine. It has a diverse community of over 1.5 million live coders with a variety of backgrounds all learning and sharing their ideas and thoughts through the medium of code. It is free to download for Mac, PC and Raspberry Pi and includes a friendly tutorial that assumes you know nothing about either code or music.
Sonic Pi was initially conceived as a response to the UK’s newly released Computing curriculum in 2014. The goal was to find a motivating and fun way to teach the fundamentals of programming. It turns out that there is a lot in common and it’s huge fun to explain sequencing as melody, iteration as rhythm, conditionals as musical variety. I developed the initial designs and first iterations of the platform with Carrie Anne Philbin, who brought a teacher’s perspective to the project. Since then, Sonic Pi has undergone iterative improvements thanks to the feedback gained from observing learners and collaborating directly with educators in the classroom. A core design philosophy was to never add a feature that couldn’t be easily taught to a 10 year old child. This meant that most ideas had to be heavily refined and reworked until they were simple enough. Making things simple whilst keeping them powerful continues to be the hardest part of the project.
In order to provide the magical motivation, Sonic Pi’s design was never limited to a pure focus on education. Ideally there would be famous musicians and performers using Sonic Pi as a standard instrument alongside guitars, drums, vocals, synths, violins, etc. These performers would then act as motivational role models demonstrating the creative potential of code. For this to be possible sufficient focus and effort therefore had to be placed on making it a powerful instrument whilst still keeping it simple enough for 10 year olds to pick up. In addition to educators, I also worked directly with a variety of different artists in classrooms, art galleries, studios and venues in the early stages of Sonic Pi’s development. This provided essential feedback which enabled Sonic Pi to grow and ultimately flourish as a tool for creative expression.
There were a number of exciting and unexpected side effects of this dual focus on education and professional musicians. Many of the features are beneficial to both groups. For example, a lot of effort has been put into making error messages more friendly and useful (rather than being a huge complicated mess of jargon). This turns out to be very useful when you write a bug while performing in front of thousands of people. Additionally, functionality such as playing studio quality audio samples, adding audio effects, providing access to live audio from the microphone all turn out to make the learning experience more fun, rewarding and ultimately meaningful.
The Sonic Pi community continues to grow and share amazing code compositions, lesson plans, musical algorithms, and much more. Much of this happens on our friendly forum in_thread (in-thread.sonic-pi.net) which is home to a very diverse group of people that includes educators, musicians, programmers, artists and makers. It is a real joy to see people learn to use code to express themselves in new ways and for that in turn to inspire others to do the same.
From a Computer Science perspective, Sonic Pi provides you with the building blocks to teach you the basics as found in the UK’s curriculum such as sequencing, iteration, conditionals, functions, data structures, algorithms, etc. However, it also builds on a number of important and relevant concepts which have become adopted in mainstream industry such as concurrency, events, pattern matching, distributed computing and determinism - all whilst keeping things simple enough to explain to a 10 year old child.
Get
play 70
A melody can be constructed with one more command, sleep:
play 72
sleep 0.5
play 75
sleep 0.5
play 79
In this example, we play the note 70 (roughly the 70th note on a piano), wait for 1 second, play note 72, wait for half a second and then play note 75. What’s interesting here is that with just two commands we have access to pretty much all of Western notation (which notes to play and when) and learners can code any melody they’ve ever heard. This leads to huge variety in expressive outcomes whilst focussing on the same computing concept: sequencing in this case.
Taking ideas from the professional music world, we can also play back any recorded sound. Sonic Pi can play any audio file on your computer but also has a number of sounds built-in to make things easy to get started:
sample :loop_amen
This code will play back the drum break which was a pillarstone to early hip-hop, Drum and Bass and Jungle. For example, a number of early hip-hop artists played this drum break back at half speed to give it a more laid-back feeling:
sample :loop_amen, rate: 0.5
In the 90s a number of music scenes burst out of new technology which enabled artists to take drum breaks like this apart and reassemble in a different order. For example:
sample :loop_amen
случайный
Этот раздел будет охватывать некоторые очень полезные - на самом деле даже необходимые знания для получения максимальной отдачи от вашего опыта работы с Sonic Pi.
Мы поговорим о том, как получить пользу от множества доступных вам клавиатурных сочетаний, как делиться своими работами, а ещё, я дам вам несколько советов о выступлениях с Sonic Pi.
Sonic Pi такой же инструмент, как и среда разработки. Следовательно, клавиатурные сочетания могут сделать работу c Sonic Pi намного более эффективной и естественной - особенно когда вы играете вживую перед аудиторией.
Многое в Sonic Pi может контролироваться с помощью клавиатуры. Когда вы лучше познакомитесь с работой и выступлениями с Sonic Pi, вы, вероятно, начнёте использовать клавиатурные сочетания всё чаще и чаще. Лично я печатаю вслепую (рекомендую обдумать возможность обучения этому навыку) и огорчаюсь всякий раз, когда мне нужно тянуться за мышкой, так как это меня замедляет. Поэтому я использую все эти клавиатурные сочетания на постоянной основе!
Следовательно, если вы изучите эти клавиатурные сочетания, вы узнаете, как эффективно использовать клавиатуру, и вы начнёте кодировать вживую как профи в кратчайшие сроки.
Однако, не пытайтесь выучить все сочетания за один раз, просто пробуйте и запоминайте те сочетания, которые вы используете наиболее часто, а затем продолжайте добавлять новые в свою практику.
Представьте, что вы учитесь играть на кларнете. Вы ожидаете, что все кларнеты производятся со схожими элементами управления и аппликатурой. Если нет, вам будет трудно переключаться между различными кларнетами и вы будете вынуждены использовать всего один.
К сожалению три основные операционные системы (Linux, Mac ОС X и Windows) поставляются с собственными стандартами по умолчанию для таких действий, как вырезать, вставить и т. д. Sonic Pi будет пытаться соблюдать эти стандарты. Однако, вместо попыток соответствовать стандартам текущей платформы, Sonic Pi приоритетное внимание уделяет согласованности между платформами. Это значит, что если вы изучите сочетания клавиш во время игры с Sonic Pi на Raspberry Pi, то сможете перейти на Mac или PC и чувствовать себя там как дома.
Частью понятия согласованности является именование клавиатурных сочетаний. В Sonic Pi мы используем имена Control и Meta, ссылаясь на две главные комбинации клавиш. На всех платформах Control один и тот же (Ctrl). Однако, на Linux и Windows, Meta - это клавиша Alt, в то время как на Mac, Meta - это клавиша Command. Для единообразия мы будем использовать термин Meta - только не забудьте сопоставить его с соответствующей клавишей вашей операционной системы.
Чтобы сохранить вещи простыми и читабельными, мы будем использовать аббревиатуры - С- для Control плюс ещё одна клавиша, и М- - для Meta плюс ещё одна клавиша. Например, если клавиатурное сочетание требует от нас нажать одновременно Meta и r, мы напишем это как M-r
. Символ - означает “одновременно с”.
Ниже приведены клавиатурные сочетания, которые я считаю самыми полезными.
Вместо того, чтобы постоянно тянуться за мышью, чтобы выполнить свой код, вы можете просто нажать M-r
. Аналогично, чтобы остановить выполнение кода, вы можете нажать M-s
.
Я действительно потерялся бы без навигационных клавиш. Поэтому я настоятельно рекомендую вам потратить время, чтобы выучить их. Эти клавиатурные комбинации работают чрезвычайно хорошо в том случае, если вы освоили слепую печать, так как они используют обычные буквы и не нужно перемещать руку на мышь или клавиши со стрелками на вашей клавиатуре.
Вы можете двигаться к началу строки, используя C-a
, к концу строки, используя C-e
, на строку вверх - C-p
, на строку вниз - C-n
, на символ вперёд - C-f
, и на символ назад - C-b
.
Чтобы применить автовыравнивание к вашему коду, просто нажмите M-m
.
Для перехода к справочной системе вы можете нажать M-i
. Однако, гораздо полезнее знать сочетание C-i
, которое будет искать слово под курсором в документации и отображать её, если что-нибудь найдет. Мгновенная помощь!
Чтобы увидеть полный список клавиатурных сочетаний, загляните в раздел 10.2 Шпаргалка по клавиатурным сочетаниям.
Ниже приводится обзор основных клавиатурных сочетаний, доступных в Sonic Pi. Пожалуйста, посмотрите раздел 10.1 для подготовки и мотивации.
В этом списке мы используем следующие соглашения (где Meta называется Alt в Windows/Linux или Cmd в Mac):
C-a
значит удерживая клавишу Control, нажмите клавишу a. И после того, как обе клавиши будут нажаты одновременно, отпустите их.
M-r
значит удерживая клавишу Meta, нажмите клавишу r. И после того, как обе клавиши будут нажаты одновременно, отпустите их.
S-M-z
значит удерживая клавиши Shift и Meta, нажмите клавишу z. И после того, как все три клавиши будут нажаты одновременно, отпустите их.
C-M-f
значит удерживая клавиши Control и Meta, нажмите клавишу f. И после того, как все три клавиши будут нажаты одновременно, отпустите их.
M-r
- Выполнить код
M-s
- Остановить выполнение кода
M-i
- Показать/скрыть справочную систему
M-p
- Показать/скрыть настройки
M-{
- Переключить буфер влево
M-}
- Переключить буфер вправо
M-+
- Увеличить размер текста в текущем буфере
M--
- Уменьшить размер текста в текущем буфере
M-a
- Выбрать всё
M-c
- Копировать выделение в буфер обмена
M-]
- Копировать выделение в буфер обмена
M-x
- Вырезать выделение в буфер обмена
C-]
- Вырезать выделение в буфер обмена
C-k
- Вырезать от курсора до конца строки
M-v
- Вставить из буфера обмена в редактор
C-y
- Вставить из буфера обмена в редактор
C-SPACE
- Установить метку. Теперь навигация управляет областью выделения. Используйте C-g
для отмены.
M-m
- Выровнять весь текст
Tab
- Выровнять текущую линию/выделение
C-l
- Отобразить буфер с текущей строкой по центру экрана
M-/
- Комментировать/раскомментировать текущую строку
C-t
- Перемещение/замена символов
M-u
- Преобразовать следующее слово (или выделение) в верхний регистр.
M-l
- Преобразовать следующее слово (или выделение) в нижний регистр
C-a
- Перейти в начало строки
C-e
- Перейти в конец строки
C-p
- Перейти на предыдущую строку
C-n
- Перейти на следующую строку
C-f
- Перейти вперёд на один символ
C-b
- Перейти назад на один символ
M-f
- Перейти вперёд на одно слово
M-b
- Перейти назад на одно слово
C-M-n
- Переместить строку или выделение вниз
C-M-p
- Переместить строку или выделение вверх
S-M-u
- Подняться на 10 строк
S-M-d
- Опуститься на 10 строк
M-<
- Перейти в начало буфера
M->
- Перейти в конец буфера
C-h
- Удалить предыдущий символ
C-d
- Удалить следующий символ
C-i
- Показать документацию по слову под курсором
M-z
- Отмена
S-M-z
- Повтор
C-g
- Escape
S-M-f
- Переключение полноэкранного режима
S-M-b
- Показать/скрыть кнопки
S-M-l
- Показать/скрыть журнал
S-M-m
- Переключение между светлым и тёмным режимом
S-M-s
- Сохранить содержание буфера в файл
S-M-o
- Загрузить содержания из файла в буфер
Sonic Pi создан для обучения и обмена друг с другом.
Как только вы научитесь кодировать музыку, делитесь своими композициями. Это так же просто, как отправка электронной почты, содержащей ваш код. Пожалуйста, поделитесь своим кодом с окружающими, чтобы они могли учиться с помощью вашей работы или использовать её части в своём миксе.
Если вы не уверены, какой способ поделиться своей работой с остальными лучший, я рекомендую размещать свой код на GitHub и музыку на SoundCloud. Таким образом вы сможете охватить большую аудиторию.
GitHub - это сайт для обмена и работы с кодом. Он используется профессиональными разработчиками, а также художниками для обмена и совместной работы с кодом. Самый простой способ поделиться новым куском кода (или даже незавершённым куском) - создать Gist. Gist - это простой способ загружать свой код в удобной форме, чтобы другие могли увидеть, скопировать и поделиться им.
Еще один отличный способ поделиться вашей работой - сделать аудио запись и загрузить её на SoundCloud. После того как вы загрузили свою запись, другие пользователи могут комментировать и обсуждать её. Я также рекомендую поместить ссылку на ваш код в Gist в описание трека.
Для того, чтобы записать свою работу, нажмите кнопку Запись
в панели инструментов, и запись начнётся немедленно. Нажмите кнопку Выполнить
, чтобы запустить свой код, если он ещё не запущен. Когда вы закончите запись, нажмите мигающую кнопку Запись
снова, и вам будет предложено ввести имя файла. Запись будет сохранена в формате WAV-файл, который можно редактировать и конвертировать любым аудиоредактором с открытым исходным кодом (попробуйте, например, Audacity).
Я призываю вас делиться своей работой и на самом деле надеюсь, что мы все будем учить друг друга новым трюкам и развиваться вместе с Sonic Pi. Я действительно очень воодушевлён тем, что у вас будет, что показать мне.
Один из самых интересных аспектов Sonic Pi заключается в том, что он позволяет использовать код как музыкальный инструмент. Это значит, что написание кода вживую может теперь рассматриваться как новый вид музыкального исполнения.
Мы называем это Лайвкодинг.
Я рекомендую вам показывать сой экран аудитории во время лайвкодинга. Это как играть на гитаре, но скрывая свои пальцы и струны. Когда я практикуюсь дома, я использую Raspberry Pi и небольшой мини-проектор, направленный на стену моей гостиной. Вы можете использовать свой телевизор или один из своих школьных/рабочих проекторов для своего шоу. Попробуйте, это очень весело.
Don’t just play on your own - form a live coding band! It’s a lot of fun jamming with others. One person could do beats, another ambient background, etc. Use the live_audio
functionality to combine code with traditional instruments such as a guitar or a microphone.
See what interesting combinations of sounds you can create with code.
Кодирование вживую не такая уж и новинка - небольшое количество людей делало это в течение последних нескольких лет, обычно используя собственные системы, которые они сконструировали для себя сами. Отличное место для того, чтобы узнать больше о других людях, занимающихся лайвкодингом и их системах, это TOPLAP.
Ещё один отличный ресурс для изучения лайвкодинга, это Algorave. Здесь вы можете найти всё о конкретном направлении лайвкодинга - создании музыки в ночных клубах.
Sonic Pi теперь поддерживает простой API для взаимодействия с Minecraft Pi - специальным изданием Minecraft, которое устанавливается по умолчанию в Raspbian - операционную систему на основе Linux.
Интеграция в Minecraft Pi была разработана с целью быть безумно простой в использовании. Все, что вам нужно сделать, это запустить Minecraft Pi и создать мир. Затем можно свободно использовать mc_*
функции так, как если бы вы могли использовать play
и synth
. Не надо ничего импортировать или устанавливать какие-либо библиотеки - все готово и работает из коробки.
Minecraft Pi API отвечает за управление подключением в приложении Sonic Pi. Это означает, что вам не надо беспокоиться ни о чем. Если вы попытаетесь использовать Minecraft API, пока Minecraft не запущен, Sonic Pi вежливо сообщит вам об этом. Аналогично, если закрыть Minecraft Pi в то время, как всё ещё повторяется цикл live_loop
, использующий Minecraft API, цикл остановится и Sonic Pi вежливо скажет вам, что не может подключиться к Minecraft. Чтобы переподключиться, просто запустите Minecraft снова и Sonic Pi автоматически обнаружит и заново создаст подключение.
Minecraft Pi API был разработан для безупречной работы с циклами live_loop
. Это значит, что можно синхронизировать изменения в вашем Minecraft Pi мире с изменениями звука в Sonic Pi. Мгновенные, основанные на Minecraft, музыкальные клипы! Заметим, однако, что Minecraft Pi - альфа версия программы и, как известно, немного глючит. Если у вас возникнут проблемы, просто перезапустите Minecraft Pi и продолжайте как ни в чём не бывало. Sonic Pi позаботится о том, чтобы автоматически соединиться c Minecraft Pi.
Настоятельно рекомендуется, использовать Raspberry Pi 2, если вы хотите запускать Sonic Pi и Minecraft в одно и то же время - особенно если вы хотите использовать звуковые возможности Sonic Pi.
На данном этапе, Sonic Pi поддерживает базовые манипуляции блоками и игроком, подробно описанные в разделе 11.1. Поддержка обратных вызовов событий, вызванных взаимодействием игрока с миром, планируется в будущих релизах.
Sonic Pi в настоящее время поддерживает следующие основные взаимосвязи с Minecraft Pi:
Отображение сообщений в чате Установка позиции пользователя Получение позиции пользователя Установка типа блока по заданным координатам Получение типа блока по заданным координатам
Давайте рассмотрим каждую из них по очереди.
Давайте посмотрим, как легко управлять Minecraft Pi из Sonic Pi. Во-первых, убедись, что и Minecraft Pi, и Sonic Pi, открыты в одно и то же время, а также, что вы вошли в мир Minecraft и можете там передвигаться.
Просто наберите в пустом буфере Sonic Pi следующий код:
mc_message "Hello from Sonic Pi"
Когда вы нажмёте кнопку Выполнить, вы увидите своё сообщение в окне Minecraft. Поздравляю, вы написали свой первый код в Minecraft! Это было просто, не так ли.
Теперь давайте попробуем немного магии. Телепортируем себя куда-нибудь! Наберите следующее:
mc_teleport 50, 50, 50
Когда вы нажмёте Выполнить - бум! Вы мгновенно переноситесь на новое место. Скорее всего, это будет где-то в небе, и вы упадёте на землю, либо на сушу, или в воду. Что это за цифры: 50, 50, 50
? Это координаты места, в которые вы пытаетесь телепортироваться. Давайте сделаем короткий перерыв, чтобы выяснить, что такое координаты и как они работают, потому что они очень, очень важны для программирования Minecraft.
Представьте пиратскую карту с большой X
меткой на месте расположения каких-нибудь сокровищ. Точное местоположение X
может быть описано с помощью двух чисел - как далеко по карте слева направо и как далеко по карте снизу вверх. Например 10см
по горизонтали и 8 см
вверх. Эти числа 10
и 8
- это координаты. Вы можете легко представить местоположение других тайников с сокровищами, описанное другой парой чисел. Возможно, есть большой сундук золота на 2
по горизонтали и 9
по вертикали…
Но, в Minecraft двух чисел не достаточно. Нам также нужно знать как высоко мы находимся. Следовательно, нам нужно три числа:
Как далеко с права налево в мире - x
Как далеко от передней до задней части мира - z
Как высоко мы находимся в мире - y
Ещё один нюанс - мы описываем эти координаты в таком порядке: x
, y
, z
.
Давайте поиграем с координатами. Переместитесь в приятное место на карте Minecraft, а потом переключитесь на Sonic Pi. Введите следующее:
puts mc_location
Когда вы нажмёте кнопку Выполнить вы увидите, что координаты текущего положения отобразятся в окне журнала. Запишите их, затем двигайтесь вперёд в мире Minecraft и попробуйте получить координаты снова. Обратите внимание, как они изменились! А сейчас, я рекомендую вам потратить некоторое время на повторение именно этого - немного переместитесь в мире, посмотрите координаты и повтори это снова. Делайте это до тех пор, пока не начнёте чувствовать, как изменяются координаты, когда вы перемещаетесь. Как только вы поймёте, как координаты работают, программирование с Minecraft API будет совершенной мелочью.
Теперь, когда вы знаете, как найти текущую позицию и телепортироваться, используя координаты, у вас есть все инструменты, чтобы начать строить различные вещи в Minecraft с помощью кода. Допустим, вы хотите сделать блок с координатами 40
, 50
, 60
стеклянным. Это супер просто:
mc_set_block :glass, 40, 50, 60
Ха-ха, это действительно было просто. Увидеть дело рук своих проще простого - телепортируйтесь рядом и посмотрите:
mc_teleport 35, 50, 60
Теперь повернитесь и ты увидите свой стеклянный блок! Попробуйте изменить его на алмаз:
mc_set_block :diamond, 40, 50, 60
Если вы смотрели в правильном направлении, то могли увидеть эти изменения своими глазами! Это начало чего-то захватывающего…
Давай рассмотрим ещё одну, последнюю вещь, прежде чем перейдём к чему-то немного более сложному. Задавая набор координат, можно указать какого типа должен быть блок. Давайте попробуем это с алмазным блоком, который мы только что создали:
puts mc_get_block 40, 50, 60
Эй! Это :diamond
. Попробуйте изменить его обратно на стекло и спросите Minecraft об этом снова - он ответит :glass
? Я уверен, что да :-)
Перед тем, как пойти неистово кодировать на Minecraft Pi, вы могли бы найти этот список доступных типов блоков полезным:
:air
:stone
:grass
:dirt
:cobblestone
:wood_plank
:sapling
:bedrock
:water_flowing
:water
:water_stationary
:lava_flowing
:lava
:lava_stationary
:sand
:gravel
:gold_ore
:iron_ore
:coal_ore
:wood
:leaves
:glass
:lapis
:lapis_lazuli_block
:sandstone
:bed
:cobweb
:grass_tall
:flower_yellow
:flower_cyan
:mushroom_brown
:mushroom_red
:gold_block
:gold
:iron_block
:iron
:stone_slab_double
:stone_slab
:brick
:brick_block
:tnt
:bookshelf
:moss_stone
:obsidian
:torch
:fire
:stairs_wood
:chest
:diamond_ore
:diamond_block
:diamond
:crafting_table
:farmland
:furnace_inactive
:furnace_active
:door_wood
:ladder
:stairs_cobblestone
:door_iron
:redstone_ore
:snow
:ice
:snow_block
:cactus
:clay
:sugar_cane
:fence
:glowstone_block
:bedrock_invisible
:stone_brick
:glass_pane
:melon
:fence_gate
:glowing_obsidian
:nether_reactor_core