haskell-notes

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 примитивными конструкциями является единичное событие (без отметок во

времени) и параллельная и последовательная композиции. Подход, который мы рассмотрели в более общем

виде реализован в библиотеках temporalmusicnotation и temporalmusicnotationdemo.

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 программируют в каких-нибудь

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162