Samples
Samples — это наиболее распространенный способ создания звука в tidal и strudel. Sample — это (обычно короткий) фрагмент аудио, который используется в качестве основы для генерации звука и подвергается различным преобразованиям. Музыку, основанную на samples, можно представить как коллаж из звуков. Подробнее о Sampling
Strudel позволяет загружать samples в виде аудиофайлов различных форматов (wav, mp3, ogg) из любого общедоступного URL.
Default Samples
По умолчанию strudel поставляется со встроенной “sample map”, обеспечивающей надежную основу для экспериментов.
s("bd sd [~ bd] sd,hh*16, misc")Здесь мы используем функцию s для воспроизведения различных стандартных samples (bd, sd, hh и misc), чтобы получить барабанный бит.
Для барабанных звуков strudel использует обширную библиотеку tidal-drum-machines со следующими обозначениями:
| Drum | Abbreviation |
|---|---|
| Bass drum, Kick drum | bd |
| Snare drum | sd |
| Rimshot | rim |
| Clap | cp |
| Closed hi-hat | hh |
| Open hi-hat | oh |
| Crash | cr |
| Ride | rd |
| High tom | ht |
| Medium tom | mt |
| Low tom | lt |
original von Pbroks13
Дополнительные перкуссионные звуки:
| Source | Abbreviation |
|---|---|
| Shakers (and maracas, cabasas, etc) | sh |
| Cowbell | cb |
| Tambourine | tb |
| Other percussions | perc |
| Miscellaneous samples | misc |
| Effects | fx |
Кроме того, strudel также загружает samples инструментов из VCSL по умолчанию.
Чтобы увидеть, какие имена samples доступны, откройте вкладку sounds в REPL.
Вы также можете создавать пользовательские псевдонимы для существующих звуков, используя функцию soundAlias:
soundAlias('RolandTR808_bd', 'kick')
s("kick")Обратите внимание, что изначально загружаются только sample maps (отображение имен на URL), а сами аудио samples не загружаются до тех пор, пока они не будут воспроизведены.
Такое поведение загрузки вещей только тогда, когда они нужны, также называется lazy loading.
Хотя это экономит ресурсы, это также может привести к тому, что звуки не будут слышны при первом воспроизведении, потому что звук все еще загружается.
Это может быть исправлено в будущем
Sound Banks
Если мы откроем вкладку sounds, а затем drum-machines, мы увидим, что все drum samples имеют префиксы с названиями драм-машин: RolandTR808_bd, RolandTR808_sd, RolandTR808_hh и т.д.
Мы могли бы использовать их так:
s("RolandTR808_bd RolandTR808_sd,RolandTR808_hh*16")… но это, очевидно, слишком много для написания. Используя функцию bank, мы можем сократить это до:
s("bd sd,hh*16").bank("RolandTR808")Вы даже можете паттернизировать bank для переключения между различными драм-машинами:
s("bd sd,hh*16").bank("<RolandTR808 RolandTR909>")За кулисами bank просто добавляет имя драм-машины к имени sample с _ для получения полного имени.
Это, конечно, работает только потому, что имя после _ (bd, sd и т.д.) стандартизировано.
Также обратите внимание, что у некоторых banks может не быть samples для всех звуков!
Selecting Sounds
Если мы снова откроем вкладку sounds, затем вкладку drum machines, там также есть число за каждым именем, указывающее, сколько отдельных samples доступно.
Например, RolandTR909_hh(4) означает, что доступно 4 samples хэта TR909.
По умолчанию s будет воспроизводить первый sample, но мы можем выбрать другие, используя n, начиная с 0:
s("hh*8").bank("RolandTR909").n("0 1 2 3")Слишком большие числа просто обернутся к началу
s("hh*8").bank("RolandTR909").n("0 1 2 3 4 5 6 7")Здесь 0-3 будут воспроизводить те же звуки, что и 4-7, потому что RolandTR909_hh имеет только 4 звука.
Выбор звуков также работает внутри mini notation, используя “:” вот так:
s("bd*4,hh:0 hh:1 hh:2 hh:3 hh:4 hh:5 hh:6 hh:7")
.bank("RolandTR909")Loading Custom Samples
Вы можете загрузить нестандартную sample map, используя функцию samples.
Loading samples from file URLs
В этом примере мы назначаем имена bassdrum, hihat и snaredrum конкретным аудиофайлам на сервере:
samples({
bassdrum: 'bd/BT0AADA.wav',
hihat: 'hh27/000_hh27closedhh.wav',
snaredrum: ['sd/rytm-01-classic.wav', 'sd/rytm-00-hard.wav'],
}, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/');
s("bassdrum snaredrum:0 bassdrum snaredrum:1, hihat*16")Вы можете свободно выбирать любую комбинацию букв для каждого имени sample. Даже можно переопределить стандартные звуки.
Выбранные вами имена будут доступны в функции s.
Убедитесь, что URL и каждый путь к sample образуют правильный URL!
В приведенном выше примере bassdrum загрузит:
https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/bd/BT0AADA.wav
|----------------------base path --------------------------------|--sample path-|
Обратите внимание, что мы можем загрузить либо один файл, как для bassdrum и hihat, либо список файлов, как для snaredrum!
Как только вы запустите код, выбранные вами имена samples будут перечислены в sounds -> user.
Loading Samples from a strudel.json file
Приведенный выше способ загрузки samples может быть утомительным для записи / копирования-вставки каждый раз, когда вы пишете новый pattern.
Чтобы избежать этого, вы можете просто передать URL к файлу strudel.json где-то в интернете:
samples('https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/strudel.json')
s("bd sd bd sd,hh*16")Ожидается, что файл определит sample map с использованием JSON в том же формате, что описан выше.
Кроме того, базовый путь может быть определен с помощью ключа _base.
Последний раздел можно записать как:
{
"_base": "https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/",
"bassdrum": "bd/BT0AADA.wav",
"snaredrum": "sd/rytm-01-classic.wav",
"hihat": "hh27/000_hh27closedhh.wav"
}
Обратите внимание, что браузеры часто кэшируют strudel.json при первой загрузке и продолжают использовать кэшированную
версию, даже если оригинал был обновлен. Если это вас беспокоит (например, при разработке нового
sample pack), вы можете заставить браузер загрузить новую копию, например, изменив регистр одного
символа в URL или добавив атрибут URL, например:
samples('https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/strudel.json?version=2');
который игнорируется GitHub (но изменяет URL, заставляя браузер перезагружать при каждом увеличении номера версии).
Также возможно, конечно, просто удалить его из кэша (удаление кэша в настройках конфиденциальности браузера, или из консоли разработчика, если вы технически подкованы, или с помощью расширения для удаления кэша).
Generating strudel.json
Вы можете использовать @strudel/sampler для генерации файла strudel.json, выполнив:
npx --yes @strudel/sampler --json > strudel.json
Смотрите другие способы использования strudel/sampler ниже, в разделе “From Disk via @strudel/sampler”.
Github Shortcut
Поскольку загрузка samples из github является распространенной, есть сокращение:
samples('github:tidalcycles/dirt-samples')
s("bd sd bd sd,hh*16")Формат: samples('github:<user>/<repo>/<branch>'). Если вы опустите branch (как выше), будет использована ветка main.
Предполагается наличие файла strudel.json в корне репозитория:
https://raw.githubusercontent.com/<user>/<repo>/<branch>/strudel.json
From Disk via “Import Sounds Folder”
Если вы не хотите загружать свои samples в интернет, вы также можете загрузить их с локального диска.
Перейдите на вкладку sounds в REPL и откройте вкладку import-sounds под строкой поиска.
Нажмите кнопку “import sounds folder” и выберите папку, содержащую аудиофайлы.
Выбранная вами папка также может содержать подпапки с аудиофайлами.
Пример:
└─ samples
├─ swoop
│ ├─ swoopshort.wav
│ ├─ swooplong.wav
│ └─ swooptight.wav
└─ smash
├─ smashhigh.wav
├─ smashlow.wav
└─ smashmiddle.wav
В приведенном выше примере папка samples содержит 2 подпапки swoop и smash, которые содержат аудиофайлы.
Если вы выберете эту папку samples, вкладка user (рядом с вкладкой import-sounds) будет содержать 2 новых звука: swoop(3) smash(3)
Отдельные samples затем могут быть воспроизведены обычным способом, например s("swoop:0 swoop:1 smash:2").
Samples внутри каждого звука используют индексацию с нуля в алфавитном порядке.
From Disk via @strudel/sampler
Вместо загрузки samples в браузер с помощью кнопки “import sounds folder”, вы также можете обслуживать samples с локального файлового сервера. Самый простой способ сделать это — использовать @strudel/sampler:
cd samples
npx @strudel/sampler
Затем вы можете загрузить его через:
samples('http://localhost:5432/');
n("<0 1 2>").s("swoop smash")Удобство @strudel/sampler в том, что он автоматически генерирует файл strudel.json на основе структуры ваших папок.
Вы можете увидеть, что было сгенерировано, перейдя по адресу http://localhost:5432 в браузере.
Примечание: Для работы этого вам нужен установленный NodeJS.
Specifying Pitch
Чтобы убедиться, что ваши samples настроены правильно при воспроизведении с note, вы можете указать базовую высоту звука следующим образом:
samples({
'gtr': 'gtr/0001_cleanC.wav',
'moog': { 'g3': 'moog/005_Mighty%20Moog%20G3.wav' },
}, 'github:tidalcycles/dirt-samples');
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s("gtr,moog").clip(1)
.gain(.5)Мы также можем объявить разные samples для разных регионов клавиатуры:
setcpm(60)
samples({
'moog': {
'g2': 'moog/004_Mighty%20Moog%20G2.wav',
'g3': 'moog/005_Mighty%20Moog%20G3.wav',
'g4': 'moog/006_Mighty%20Moog%20G4.wav',
}}, 'github:tidalcycles/dirt-samples')
note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>")
.s('moog').clip(1)
.gain(.5)Sampler всегда выберет ближайший подходящий sample для текущей ноты!
Обратите внимание, что эта нотация для звуков с высотой тона также работает внутри файла strudel.json.
Shabda
Если вы не хотите выбирать samples вручную, есть также замечательный инструмент под названием shabda. С его помощью вы можете ввести любое имя (имена) sample для запроса из freesound.org. Пример:
samples('shabda:bass:4,hihat:4,rimshot:2')
$: n("0 1 2 3 0 1 2 3").s('bass')
$: n("0 1*2 2 3*2").s('hihat').clip(1)
$: n("~ 0 ~ 1 ~ 0 0 1").s('rimshot')Вы также можете генерировать искусственные голосовые samples с любым текстом на нескольких языках.
Обратите внимание, что код языка и параметры пола являются необязательными и по умолчанию имеют значения en-GB и f
samples('shabda/speech:the_drum,forever')
samples('shabda/speech/fr-FR/m:magnifique')
$: s("the_drum*2").chop(16).speed(rand.range(0.85,1.1))
$: s("forever magnifique").slow(4).late(0.125)Sampler Effects
Sampler effects — это функции, которые можно использовать для изменения поведения воспроизведения sample.
begin
Pattern чисел от 0 до 1. Пропускает начало каждого sample, например, 0.25 обрезает первую четверть каждого sample.
- amount (number|Pattern): от 0 до 1, где 1 это длина sample
samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/dirt-samples')
s("rave").begin("<0 .25 .5 .75>").fast(2)end
То же, что .begin, но обрезает конец каждого sample.
- length (number|Pattern): 1 = весь sample, .5 = половина sample, .25 = четверть sample и т.д.
s("bd*2,oh*4").end("<.1 .2 .5 1>").fast(2)loop
Зацикливает sample. Обратите внимание, что темп loop не синхронизирован с темпом цикла. Для изменения области loop используйте loopBegin / loopEnd.
- on (number|Pattern): Если 1, sample зациклен
s("casio").loop(1)loopBegin
loopbНачинает loop в определённой точке sample (между begin и end).
Обратите внимание, что точка loop должна находиться между begin и end, и перед loopEnd!
Примечание: Sample, начинающиеся с wt_, автоматически зацикливаются! (wt = wavetable)
- time (number|Pattern): от 0 до 1, где 1 это длина sample
s("space").loop(1)
.loopBegin("<0 .125 .25>")._scope()loopEnd
loopeЗаканчивает секцию loop в определённой точке sample (между begin и end).
Обратите внимание, что точка loop должна находиться между begin и end, и после loopBegin!
- time (number|Pattern): от 0 до 1, где 1 это длина sample
s("space").loop(1)
.loopEnd("<1 .75 .5 .25>")._scope()cut
В стиле классических драм-машин, cut остановит воспроизводящийся sample, как только будет воспроизведён другой sample в той же группе cut. Примером может быть открытый хэт, за которым следует закрытый, фактически заглушая открытый.
- group (number|Pattern): номер группы cut
s("[oh hh]*4").cut(1)clip
legatoУмножает длительность на заданное число. Также обрезает sample в конце, если они превышают длительность.
- factor (number|Pattern): = 0
note("c a f e").s("piano").clip("<.5 1 2>")loopAt
Makes the sample fit the given number of cycles by changing the speed.
samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
s("rhodes").loopAt(2)fit
Makes the sample fit its event duration. Good for rhythmical loops like drum breaks.
Similar to loopAt.
samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
s("rhodes/2").fit()chop
Cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'. It turns a pattern of samples into a pattern of parts of samples.
samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
s("rhodes")
.chop(4)
.rev() // reverse order of chops
.loopAt(2) // fit sample into 2 cyclesstriate
Cuts each sample into the given number of parts, triggering progressive portions of each sample at each loop.
s("numbers:0 numbers:1 numbers:2").striate(6).slow(3)slice
Chops samples into the given number of slices, triggering those slices with a given pattern of slice numbers. Instead of a number, it also accepts a list of numbers from 0 to 1 to slice at specific points.
samples('github:tidalcycles/dirt-samples')
s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(0.75)samples('github:tidalcycles/dirt-samples')
s("breaks125").fit().slice([0,.25,.5,.75], "0 1 1 <2 3>")splice
Works the same as slice, but changes the playback speed of each slice to match the duration of its step.
samples('github:tidalcycles/dirt-samples')
s("breaks165")
.splice(8, "0 1 [2 3 0]@2 3 0@2 7")scrub
Позволяет "скрабить" аудио файл, как ленточную петлю, передавая значения, представляющие позицию в аудио файле в опциональном синтаксисе массива, например: "0.5:2", второе значение контролирует скорость воспроизведения
samples('github:switchangel/pad')
s("swpad:0").scrub("{0.1!2 .25@3 0.7!2 <0.8:1.5>}%8")samples('github:yaxu/clean-breaks/main');
s("amen/4").fit().scrub("{0@3 0@2 4@3}%8".div(16))speed
Изменяет скорость воспроизведения sample, т.е. дешёвый способ изменить высоту тона.
- speed (number|Pattern): от -inf до inf, отрицательные числа воспроизводят sample в обратном направлении.
s("bd*6").speed("1 2 4 1 -2 -4")speed("1 1.5*2 [2 1.1]").s("piano").clip(1)После samples давайте посмотрим, что нам предоставляют Synths.