52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 344

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 344

af, bf, cf, df, ef, ff, gf :: Score

c = note 0;

cs = note 1;

d = note 2;

ds = note 3;

...

Первая буква содержит буквенное обозначение ноты, а вторая либо s (от англ. sharp диез) или f (от англ.

flat бемоль). Все эти ноты находятся в первой октаве, но смещением высоты на 12 единиц мы легко можем

смещать эти ноты в любую другую октаву:

higher :: Int -> Score -> Score

higher n = fmap (\a -> a{ notePitch = 12*n + notePitch a })

lower :: Int -> Score -> Score

lower n = higher (-n)

high :: Score -> Score

high = higher 1

low :: Score -> Score

low = lower 1

С помощью этих функций мы легко можем смещать группы нот в любую октаву. Функция higher прини-

мает число октав, на которые необходимо сместить вверх высоту во всех нотах трека. Смещение высоты на

12 определяет смещение на одну октаву. Остальные функции определены в через функцию higher.

Длительность ноты

Пока что наши ноты длятся 1 единицу времени. Но нам бы хотелось иметь в распоряжении и другие дли-

тельности. Ноты других длительностей мы можем легко получать с помощью функции stretch, мы просто

изменим масштаб времени и длительность всех нот изменится. Определим несколько синонимов:

bn, hn, qn, en, sn :: Score -> Score

-- (brewis note)

(half note)

(quater note)

bn = stretch 2;

hn = stretch 0.5;

qn = stretch 0.25;

-- (eighth note)

(sizth note)

en = stretch 0.125;

sn = stretch 0.0625;

Эти преобразования отвечают длительностям нот в европейской музыкальной традиции.

Громкость ноты

Пока мы умеем создавать ноты средней громкости, но мы можем определить преобразователи на манер

тех, что изменяли высоту звука октавами:

louder :: Int -> Score -> Score

louder n = fmap $ \a -> a{ noteVolume = n + noteVolume a }

quieter :: Int -> Score -> Score

quieter n = louder (-n)

310 | Глава 21: Музыкальный пример

Смена инструмента

Изначально мы создаём ноты, которые играются на инструменте с кодом 0, в протоколе General Midi этот

номер соответствует роялю. Но с помощью класса Functor мы легко можем изменить инструмент:

instr :: Int -> Score -> Score

instr n = fmap $ \a -> a{ noteInstr = n, isDrum = False }

drum :: Int -> Score -> Score