closedHiHat = drum 42;
rideCymbal = drum 59;
cabasa = drum 69;
maracas
= drum 70;
tom
= drum 45;
flute
= instr 73;
piano
= instr 0;
Ударная секция:
b1 = bam 100
b0 = bam 84
drums1 = loop 80 $ chord [
tom
$ line [qn b1, qn b0, hnr],
maracas $ line [hnr, hn b0]
]
drums2 = quieter 20 $ cabasa $ loop 120 $ en $ line [b1, b0, b0, b0, b0]
drums3 = closedHiHat $ loop 50 $ en (line [b1, loop 12 wnr])
drums = drums1 =:= drums2 =:= drums3
Уже сейчас мы можем загрузить эту партию в интерпретатор и послушать, вызвав out drums. Аккорды к
мелодии:
c7
= chord [c, e, b]
gs7 = chord [low af, c, g]
g7
= chord [low g, low bf, f]
harmony = piano $ loop 12 $ lower 1 $ bn $ line [bn c7, gs7, g7]
Мелодия:
ac = louder 5
mel1 = bn $ line [bnr, subMel, ac $ stretch (1+1/8) e, c,
subMel, enr]
where subMel = line [g, stretch 1.5 $ qn g, qn f, qn g]
mel2 = loop 2 $ qn $ line [subMel, ac $ bn ds, c, d, ac $ bn c, c, c, wnr,
subMel, ac $ bn g, f, ds, ac $ bn f, ds, ac $ bn c]
where subMel = line [ac ds, c, d, ac $ bn c, c, c]
mel3 = loop 2 $ line [pat1 (high c) as g, pat1 g f d]
where pat1 a b c = line [pat a, loop 3 qnr, wnr,
pat b, qnr, hnr, pat c, qnr, hnr]
pat
x
= en (x +:+ x)
mel = flute $ line [mel1, mel2, mel3]
Пример | 315
Добавим в конце звук тарелки:
cha = delay (dur mel1 + dur mel2) $ loop 10 $ rideCymbal $ delay 1 b1
Соберём всё вместе и послушаем:
res = chord [
drums,
harmony,
high mel,
louder 40 cha,
rest 0]
main = out res
В конце стоит фиктивный элемент rest 0 для того чтобы было удобно глушить инструменты комменти-
рованием.
21.6 Эффективное представление музыкальной нотации
Реализация, которую мы рассмотрели не эффективна, Мы могли бы определить тип Track и по-другому.
Мы очень часто пользуемся операцией delay через операцию line. Так в выражении:
q = line [s1, s2, line [loop 2 s3, s4], s5]
Мы будем несколько раз обходить элемент s3 для каждого применения line. К примеру сначала мы
смести все элементы на 3, потом сместим на 5, потом на 10, но вместо этого мы могли бы сразу сместить
все элементы на 18 за один проход. Для этого мы можем закодировать преобразования событий во времени
в типе Track:
data Track t a = Track {
trackDur
:: t,
trackEvents :: TList t a
data TList t a = Empty | Single a | Append (TList t a) (TList t a)
| TFun (Tfm t) (TList t a)
data Tfm t = Tfm ! t ! t
Тип TList позволяет проводить быстрое объединение списков. Дополнительный конструктор TFun обо-
значает линейное преобразование списка во времени. Линейное преобразование кодируется двумя числами,
это масштаб и смещение. Мы считаем, что события в конструкторе Single начинаются в момент времени 0
и длятся 1 единицу времени. Так например событие, которое произошло на 2 единице времени и длилось 4
единицы можно представить так:
TFun (4 2) (Single a)
Значение Tfm k d обозначает линейную функцию
f ( x) = kx + d
Для того чтобы получить настоящие отсчёты по времени мы применяем её к временным координатам
“не преобразованного” события, то есть события Event 0 1 a.
Единственное, что нам нужно для того чтобы встроить этот вариант в библиотеку это написать функцию:
Мы будем Вам очень признательны, если Вы оцените данную книгуили оставить свой отзыв на странице комментариев.
fromTList :: TList t a -> [Event t a]
И конечно переопределить все функции композиции. Но все сложные функции, которые отвечают за
перевод из Track в Midi останутся прежними.
21.7 Краткое содержание
В этой главе мы построили секвенсор для создания midi-файлов. Мы воспользовались библиотекой
HCodecs и создали над ней небольшую надстройку.
В нашей библиотеке примитивными конструкциями были события, параллельная композиция (одновре-
менное воспроизведение) и преобразование событий во времени (сдвиг и масштабирование). Все остальные
операции выражались через эти простейшие операции. Отметим, что есть и другие подходы. Например в биб-
лиотеках Haskore и Euterpea примитивными конструкциями является единичное событие (без отметок во
времени) и параллельная и последовательная композиции. Подход, который мы рассмотрели в более общем
виде реализован в библиотеках temporal—music—notation и temporal—music—notation—demo.
316 | Глава 21: Музыкальный пример
21.8 Упражнения
• Попробуйте написать какую-нибудь мелодию.
• Подумайте каких операций не хватает. Например было бы удобно иметь возможность вырезать из ме-
лодии куски. Так в примере у нас остались хвосты от ударной секции, определите операцию, которая
позволяет убрать лишнее.
Упражнения | 317
Приложения
318 | Приложения
Начало работы с Haskell
Компилятор
Для программирования в Haskell нам понадобится компилятор. Мы будем пользоваться наиболее разви-
тым компилятором~– GHC. Лучше всего устанавливать его вместе с Haskell Platform:
http://hackage.haskell.org/platform/
Haskell Platform содержит стабильную версию компилятора и много хороших, проверенных временем
библиотек. Если по каким-то причинам установить Haskell Platform не удалось. Не отчаивайтесь, можно
загрузить компилятор с сайта GHC:
http://www.haskell.org/ghc/
И далее установить все необходимые библиотеки с Hackage с помощью cabal (устанавливается отдельно
с http://www.haskell.org/cabal/).
Среда разработки
Для Haskell существует очень мало сред разработки. Обычно на Haskell программируют в каких-нибудь