Краткое руководство к программе MIDIM

Дата публикации:2007
Поделиться в Twitter Поделиться в F******k Поделиться в VKontakte Поделиться в Telegram Поделиться в Mastodon

Содержание

Раздел первый. Редактор нотного текста

Что такое Midim?

Midim - это секвенсер, который из нотного текста (в формате нотной системы Брайля (НСБ)) генерирует и воспроизводит Midi файл.

Нотный текст в формате НСБ, как вы, смею надеяться, знаете, есть ни что иное как обычный текст, то есть набор букв, цифр, скобок и так далее. Этим мы обязаны шести точкам, коими и ограничены наши возможности письма. Но в случае с компьютерными технологиями почему бы этот недостаток не обратить в достоинство? Конечно, в нотной записи есть символы, которые трудно изобразить текстом. Например, нота фа целая, то есть шеститочие, в буквенной записи вообще ни чего не обозначает и используется для зачёркивания или рисования. Также сложно отыскать буквенный аналог для диеза, цифири, обозначения октав и некоторых других элементов.

Надеюсь, мне удалось найти наиболее рациональное решение этой проблемы, по крайней мере, правила набора нотного текста в моей программе просты и доступны для понимания любого человека, знакомого с НСБ. Необходимо лишь немного тренировки и вы без особого труда будете набирать и редактировать музыкальные произведения любой сложности и структуры.

Шесть основных правил нотописи

Здесь я следовал принципу, по которому одному нотному символу по системе Брайля должен соответствовать только один буквенный символ, а между ними должна быть логическая связь, поэтому вам не придётся их заучивать, достаточно будет внимательно прочитать и осознать шесть основных правил нотописи, приведённые ниже:

  1. Для отображения нот необходимо использовать буквы латинского алфавита, цифры и некоторые дополнительные символы (регистр букв имеет значение).
  2. Если нотный символ по системе Брайля имеет аналог в буквенной записи, то записывать его необходимо именно этой буквой в малом регистре. Так, до половинная обозначается маленькой латинской n, половинная пауза - маленькой латинской u, целая пауза - маленькой латинской m и так далее.
  3. Если нотный символ по системе Брайля не имеет буквенного аналога, то следует поступить так:
    - поменяйте в этом символе вертикальные столбцы местами, то есть первую, вторую, третью точки с четвёртой, пятой и шестой соответственно;
    - если результат имеет буквенный аналог, то исходный нотный символ по системе Брайля необходимо записать этой буквой в большом регистре.
    Таким образом, до четвертная запишется большой латинской P, диез - большой латинской M, знак цифры - большой латинской V, знак большой октавы - большой латинской B, знак малой октавы - большой латинской L и так далее.
    В связи с этим рекомендую настроить ваш Jaws так, чтобы он реагировал на большой регистр, например, воспроизведением звукового сигнала. Если это сделать средствами Jaws по какой-то причине нельзя, то произведите соответствующие настройки в самой программе MIDIM.
    В качестве примера запишем ниже гамму до мажор четвертными длительностями:
    PSNQTOwP
    (до, ре, ми, фа, соль, ля, си, до)
  4. Если нотный символ по системе Брайля представляет собой сниженную цифру, то его необходимо записывать именно этой цифрой.
    Например, квинту надо записать цифрой 9, сексту - цифрой 0, септиму - цифрой 3 и так далее.
  5. Если нотный символ по системе Брайля не подпадает ни под одно из выше перечисленных правил, то такой символ является исключением.
    Ниже перечислю все эти символы и как их нужно писать:
    интервал "октава" _
    интервал "секунда" /
    бекар \
    знак слова )
    бемоль (
    объединитель ()
    си целая ]
    соль целая [
    знак первой октавы !
    знак третьей октавы @
    знак четвёртой октавы ,
    знак пятой октавы ,,
    точка после ноты .
    две точки после ноты ..
    три точки после ноты ...
    Теперь запишем всё ту же гамму до мажор в первой октаве, разными длительностями, с указанием размера (четыре четверти) и разобьём нотный текст на такты:
    Vd4!PSp * rs t.P
  6. Ещё символы, которые понимает MIDIM:
    уточнитель для целой, половинной, четвертной и восьмой длительностей !la
    уточнитель для остальных длительностей !lb
    лига держания для ноты Ac
    лига держания для аккорда Kc
    штрих легаттоc
    удвоенное легатто cc
    штрих стакатто 8
    удвоенное стакатто 88
    штрих стакаттисимо !8
    удвоенное стакаттисимо !8!8
    триоль 2
    второй способ записи триоли Kl3.
    квартоль Kl4.
    секстоль Kl6.
    септоль Kl7.
    и так далее, в том же роде...
  7. Один нотный символ по системе НСБ можно записать только по одному из перечисленных правил.

Редактор нотного текста

Музыкальное произведение, будем называть его сонгом, в этом секвенсере, впрочем как и в большинстве других секвенсерах, представлено в виде отдельных дорожек или треков, расположенных друг под другом. Каждый трек имеет своё имя и свой номер MIDI-канала, которые задаются в окне свойств трека. Треки могут быть разбиты на отдельные голоса. Это осуществляется посредством большого объединителя. Для облегчения работы и более наглядного представления нотного текста я ввёл возможность неявного использования этого элемента. В общем же случае нотный текст хранится в стандартном для НСБ виде со всеми описанными в правилах символами.

Нотный редактор в программе Midim является текстовым и однострочным, то есть максимальное количество символов, которое можно набрать в нём за один промежуток времени не превышает 255. Именно этим числом ограничивается общая длина одного такта, включая все его голоса и по два символа на каждый объединитель между ними.

Есть такие понятия, как текущий трек, текущий голос и текущий такт. Вот когда вы с помощью определённых сочетаний клавиш изменяете хотя бы один из этих параметров, тогда в редактор загружается именно та часть нотного текста, которую они описывают, а так как эта часть по понятным причинам не может содержать пробелов или больших объединителей, то эти символы в описываемом редакторе считаются запрещёнными. Именно поэтому, написав, скажем, первый такт, для того чтобы начать писать второй, вы должны нажать не на пробел, а на ту клавишу, которая изменит значение соответствующего параметра, то есть текущего такта.

Процесс Набора нотного текста в программе MIDIM похож на заполнение ячеек таблицы. В программном меню можно отыскать и многострочный нотный редактор, позволяющий набирать, редактировать или просто просматривать нотный текст как он есть, то есть с пробелами и объединителями, но работа в нём хотя и бывает необходимой, но, на мой взгляд, не слишком удобна.

Здесь же используя клавиши изменения значений текущих трека, такта и голоса, мы легко можем перемещаться по структуре сонга, какой бы сложной она не была. При каждом таком шаге джавс должен озвучить изменившийся параметр.

Например, путешествовать внутри трека можно с помощью сочетаний альта с клавишами перемещения курсора.

Все операции и соответствующие им горячие клавиши, которые вам доступны в программе, в том числе и навигационные, отражены в меню, поэтому не будем заострять на них особого внимания.

Таким образом, вы набираете нотный текст в полном соответствии со всеми основными правилами НСБ. Исключением является только то, что вы не используете пробелов для разделения тактов и объединителей для разделения голосов , причём все голоса как бы отделены друг от друга, словно треки, и имеют гораздо большую свободу, нежели это предусмотрено в НСБ. Выражается это тем, что ровно как каждый трек может иметь свой отличный ото всех остальных треков тактовый размер, так и каждый голос трека имеет такую же независимость от своих собратьев. Другими словами, на одном треке могут находиться несколько голосов с абсолютно разными размерами такта.

Все голоса и треки синхронизуются между собой, поэтому в программе существует определённая временная единица, в течение которой и только в течение которой будет звучать один такт, какого бы размера он ни был, и повлиять на эту единицу способен только темп произведения.

Вы, должно быть, знаете, что время в MIDI измеряется в тиках. Так вот здесь такт всегда содержит 1920 тиков. Эта величина фиксированная и повлиять на неё не возможно ничем.

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

Количество треков ограничено числом 255, причём один трек является общим для всех остальных и называется нулевым. Этот трек нельзя удалить или присвоить ему MIDI-канал. Имя этого трека есть ни что иное как имя всего сонга. Для чего он нужен вы поймёте дальше.

Особенности обозначений тактового размера и тональности

Базовые размер и тональность задаются в первом такте нулевого трека. Затем эти параметры могут меняться в любом месте как по вертикали, так и по горизонтали сонга на любом треке, в любом голосе и в начале любого такта.

Правила определения тактового размера и тональности такие же как и в нотной системе Брайля. Сначала проставляются ключевые знаки и после "цифири", то есть большой латинской V, количество долей в такте и длительность одной доли.

При смене тональности необходимо сначала с помощью бекаров отменить старые ключевые знаки, и лишь затем задать новые. Например, если при начальной тональности в три диеза мы зададим новую тональность, указав перед цифирью один диез, то результатом будет тональность в четыре диеза.

Ниже приведу примеры:

Vd4 - четыре четверти - без знаков ,
MVc4 - три четверти - с одним диезом,
((Vb2 - две вторых - с двумя бемолями,
\\\Vf8 - шесть восьмых - с тремя бекарами,
\MMMMVab16 - двенадцать шестнадцатых - с бекаром и четырьмя диезами

и так далее.

Нужно помнить, что если сразу после указанного размера следует нота, то её необходимо писать со знаком октавы, даже в случае когда по логике голосоведения этого делать не надо, ведь, например, до восьмую программа может принять за цифру четыре и отнести её к тактовому размеру. Также октава должна быть обязательно проставлена перед самой первой нотой в голосе, но это всё элементарные правила НСБ, поэтому мы перейдём к следующим особенностям.

К каждой ноте можно привязать метку или блок.

Метка - это именованная константа, значение которой можно использовать в обработчике. Записывается по общим правилам для переменных и констант (смотрите описание обработчика).

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

Внимание! У одной ноты может быть только одна метка! Также метку нельзя присоединять к интервалам.

Ниже приведу отрывок из нотного текста, содержащий метку Label, и ноту ми второй октавы целой длительности:

<Label>KY

Блок - это программа-обработчик, активизирующийся одновременно с началом звучания ноты, к которой он привязан. За продолжительность обработки отвечает сам блок. Его действие распространяется на весь канал.

Присоединить блок к ноте можно указав перед ней имя этого блока, а перед именем, в свою очередь, необходимо поставить знак слова (то есть правую круглую скобку). Заканчиваться описание имени блока должно точкой. Например:

)Cresh.

Если необходимо передать в блок параметры, то после его имени, но до точки можно поставить двоеточие и перечислить их через точку с запятой. Надеюсь, не запутаетесь...

Параметрами здесь могут быть числовые и символьные константы, переменные, а также арифметические и логические выражения (смотрите описание обработчика). Использовать или не использовать параметры решает вызываемый блок-обработчик, поэтому желательно знать их предназначение. Можно почитать описание к модулям, если оно есть, или просто изучить программный текст требуемого блока.

Например, в комплект программы входит модуль Factures4x4, написанный мной. Если мы присоединим его к нашему сонгу, а в нотном тексте, в одном из тактов, перед каким-нибудь аккордом напишем следующее:

)Guitor1:480;10;60.

программа не просто воспроизведёт этот и все следующие за ним аккорды, а сыграет его одним из гитарных приёмов.

Здесь мы передали блоку Guitor1 три параметра: 480, 10 и 60. Первый означает длительность одного удара, второй промежуток между двумя соседними звуками в ударе, а третий силу удара.

Если вы передадите лишние параметры, то они будут просто проигнорированы, а в случае отсутствия оных блок придаст им значения по умолчанию.

Блок Guitor2 из того же модуля заставляет звучать аккорды уже в другой, более сложной, ритмической окраске.

Аналогичным образом работают и остальные блоки-обработчики, только с тем отличием, что не всем им требуются параметры.

Внимание! К одной ноте может быть привязан только один блок-обработчик! К интервалу их привязывать нельзя.

На первый раз эти строки могут показаться вам не понятными, но если вы изучите описание обработчика во втором разделе и что-то там поймёте, то вернитесь сюда и перечитайте о метках и блоках-обработчиках снова.

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

Использование симиле и прочих приёмов сокращения в этой версии не поддерживается. При желании это легко можно осуществить в обработчике. Аппликатуру пока тоже использовать нельзя. Все мелизмы и штрихи необходимо описывать самостоятельно по нотам или программировать их.

На этом первый раздел, думаю, можно завершить. Если вы поняли о чём я разглагольствовал всё это время, то уже сейчас можете приступать к попыткам что-нибудь извлечь из моей программы. Учтите, что для свободного набора и редактирования нотного текста по описанным здесь правилам необходим навык, который обязательно придёт со временем, если, конечно, вы этого захотите...

Раздел второй. Обработчик

Для того чтобы легче понять устройство обработчика, рекомендую прочитать главу MIDI это просто из книги Алексея Паркова.

Обработчик - это встроенный язык программирования, позволяющий управлять всеми параметрами MIDI во времени, разве что кроме двух, ведь тональность и тактовый размер прочно привязаны к нотному тексту и оторвать их от туда просто не возможно. В остальном, обработчик может "дотянуться" куда угодно, будь то пространственная локализация или динамика, агогика или сама клавиатура инструмента. Перечислю конкретно все доступные ему параметры:

  • инструмент,
  • все 128 контроллеров,
  • скорость нажатия на клавишу,
  • скорость отпускания клавиши,
  • высота звучания,
  • темп,
  • сам нотный текст (всё кроме тактового размера и тональности),
  • гуманизация исполнения,
  • MIDI-канал,
  • управление штрихами.

За каждым треком закреплён свой обработчик, который влияет только на параметры MIDI-канала этого трека. Есть обработчик общий для всего сонга, он закреплён за нулевым треком. Здесь описываются команды, влияющие на такие характеристики как, например, темп, или любые другие единые для всего сонга. Иными словами, этот обработчик перед компиляцией будет присоединён к обработчикам остальных треков.

Вообще, все они представляют собой последовательность команд, описанных в текстовом виде, где каждая команда должна занимать одну строку Редактор для них находится, как и нотный редактор, в главном окне программы, но в отличие от того является многострочным Переход между этими редакторами осуществляется клавишей табуляции. Содержимое редактора обработчика изменяется при каждой смене текущего трека.

Принцип работы обработчика

Для начала опишем состав языка обработчика.

Он состоит из команд, выполняющих те или иные операции с данными во времени. Данными в обработчике могут быть: числовые и символьные константы, переменные, массивы, функции и выражения. Все они имеют один общий вещественный тип Extended. Имена символьных констант, переменных, массивов и функций состоят из букв латинского алфавита или цифр, причём первым символом в имени должна быть обязательно буква.

Массивы могут быть только одномерными, с постоянным индексным диапазоном от 0 до 127. Индекс массива указывается в квадратных скобках после его имени.

Функция внешне отличается от массива тем, что параметр, передаваемый ей указывается в круглых скобках, впрочем, есть функции и без параметров.

Выражение может состоять из любых констант, переменных, функций и их сочетаний. Ниже перечислю все доступные операции, в порядке увеличения их значимости, которые можно производить над данными в выражениях:

  • плюс +
  • минус -
  • разделить /
  • умножить *
  • остаток от деления Mod
  • меньше <
  • больше >
  • меньше или равно <=
  • больше или равно >=
  • равно ==
  • не равно <>
  • или or
  • и and

Таким образом выражение

3 + Tempo

выдаст результат сложения значения переменной Tempo с числовой константой 3.

Как вы обратили внимания, помимо обычных арифметических операций, в выражениях можно использовать и логические. Здесь не делается отличия между этими операциями, просто принято считать, что ложь - это 0, а истина - 127. Есть встроенные символьные константы, хранящие в себе именно эти значения: False и True.

Например, результатом выражения

100 == 100

будет 127 или True, а

127 < 100

выдаст в результате 0 или False.

Исходя из этого можно утверждать, что

True == 100 + 27
False == 20 - 20
True And False == False
True Or False == True
False Or False == False
True + False == True
True * False == False
и так далее...

Также в выражениях допускается применение круглых скобок с любым уровнем вложенности.

Например:

((True Or False) And(100 == 100)) == (True and (True > False))

Главное, чтобы длина одной строки с оператором или выражением не привышала всё тех же 255 символов!

В обработчике можно использовать условный оператор If. Общий синтаксис его таков:

If <выражение1> Then
<инструкции, выполняемые если выражение 1 истинно>
Else If <выражение2> Then
<инструкции, выполняемые если выражение2 истинно>
Else If ...
...
Else
<инструкции, выполняемые если все выражения не верны>
EndIf

При этом части, содержащие Else могут и отсутствовать.

Оператор If может быть вложенным сам в себя:

If <выражение1> Then
If <выражение2> Then
<инструкции, выполняемые если оба выражения истинны>
EndIf
EndIf

Конечно, это было бы правильней записать по-другому, в одном операторе If, но я просто привёл пример вложенности.

Теперь поговорим о командах, выполняющих операции над данными. Разнообразия тут особого нет, поскольку в вашем распоряжении на самом деле всего лишь одна команда присваивания Let.

Вид она имеет такой:

Let <имя > <выражение>>

Так, следующая строка присвоит переменной Tempo значение 120:

Let Tempo = 120

В обработчик Для каждого параметра MIDI, встроена своя переменная или массив, изменяя значение которых вы измените значение соответствующего параметра. Так, переменная Tempo, как не трудно догадаться, связана с темпом.

Время в обработчике

Я уже писал ранее, такт в программе MIDIM, не зависимо от его размера, содержит ровно 1920 тиков. В процессе обработки программа такт за тактом, тик за тиком берёт сначала информацию из нотного текста, передаёт её в обработчик и лишь затем подаёт на выход. В связи с этим, чтобы обработать скажем один такт нотного текста одного трека, обработчику придётся выполниться 1920 раз. Это конечно несколько замедляет процесс генерации MIDI-файла, но зато появляется возможность более гибко, точно и наглядно отслеживать музыкальные процессы.

Другими словами, если мы запишем опять ту же строку

Let Tempo = 120,

то значит она будет выполняться по 1920 раз в каждом такте, что отразится на скорости генерации MIDI-файла (хотя и весьма не существенно), но не на его размере, так как в итоговом файле фиксируются только изменения параметров, а не факт присвоения им значений.

Конечно, если Записать Let Tempo = Rnd(128), где RND - генератор случайных чисел (смотрите описание встроенных функций), то, это заметно увеличит размер полученного файла, так как на каждом тике будет зафиксировано очередное изменение темпа.

Теперь мы подошли к самой важной встроенной переменной, отвечающей за течение времени в обработчике. Это переменная PositionSong. В начале обработки её значение равно нулю, и с каждым тиком оно увеличивается самой программой на единицу. Благодаря именно этой переменной обработчик всегда знает, где он находится.

Рассмотрим переменную PositionSong на примере условного оператора If.

If PositionSong == 0 Then
Let Tempo = 120
Else If PositionSong == 1920 Then
Let Tempo = 240
EndIf

Так вот, в самом начале обработки, когда значение PositionSong равно нулю, обработчик установит темп равным 120 и целый такт будет звучать именно в этом темпе. В начале второго такта, когда переменная PositionSong дойдёт до значения 1920, темп увеличится в два раза и будет таковым уже до конца произведения.

На основе переменной PositionSong строятся два макро оператора: частотный оператор Evry и "временной заголовок".

"Временной заголовок" - это простая константа, переменная, функция или выражение, занимающая целую строку. Чтобы понять для чего он нужен, запишем рассмотренный выше пример с условным оператором If, но уже с помощью "временного заголовка":

0
Let Tempo = 120
1920
Let Tempo = 240

"Временной заголовок" введён только для упрощения и наглядности программного текста. Ведь можно, например, записать следующее:

0..1920
Лet Tempo = 100 + Rnd(28)

Здесь "временной заголовок" записан в виде отрезка, на протяжении которого переменной Tempo каждый тик будет присваиваться случайное значение от 120 до 127. С помощью оператора If это запишется так:

If ((PositionSong>=0) and (PositionSong<=1920)) Then
Лet Tempo = 100 + Rnd(28)
EndIf

Думаю, вы согласитесь, что первая запись всё же попроще.

Ещё одно отличие "временного заголовка" от оператора If заключается в том, что последний не может быть вложенным сам в себя. Каждый последующий "временной заголовок" отменяет предыдущий. Другими словами, действие "временного заголовка" распространяется с момента появления его в тексте, вплоть до конца или до появления другого "временного заголовка". В них, как я уже сказал, можно использовать не только числовые, а и любые другие символьные константы, переменные, функции и даже целые выражения. "Временной заголовок"

PositionSong

отменит все предыдущие заголовки.

Частотный оператор Evry

Синтаксис его таков:

Evry <частота> Do
<инструкции...>
EndEvry

Смысл этого оператора заключается в том, что <инструкции>, находящиеся внутри его тела будут выполняться не каждый тик, а согласно указанной частоте (в тиках).

Так, строки:

Evry 1920 Do
Let Tempo = Tempo + 1
EndEvry

приведут к тому, что в начале каждого такта произведения темп будет увеличиваться на единицу.

Опять же, для сравнения запишем это с помощью переменной PositionSong и оператора If:

If Positionsong Mod 1920 == 0 Then 
Let Tempo = Tempo + 1
EndIf

Здесь Mod - это остаток от деления.

Оператор Evry также не может быть вложенным сам в себя и его действие распространяется либо до появления другого такого оператора, либо до строки EndEvry.

Приведённый пример увеличивает темп в начале каждого такта, но как быть, если нам потребуется делать это, скажем, в его середине? Для этого в операторе Evry нужно указать частотное смещение OffSet. Приведу следующий пример:

Evry 1920 Do
Let Tempo = Tempo + 10
Evry 1920 OffSet 960 Do
Let Tempo = Tempo - 10
EndEvry

Здесь в начале каждого такта темп будет увеличен на 10 единиц, а в середине его вернётся в исходное значение. Понятно, что значение смещения не должно превышать значения частоты.

Операторы цикла

Оператор For имеет следующий синтаксис:

For <переменная> = <выражение1> To <выражение2> Do
<список операторов>
EndFor

Здесь <выражение2> должно быть обязательно больше или равно <выражению1>, иначе список операторов в теле цикла не выполнится ни разу.

Присвоим, например, всем контроллерам значение 0:

For c = 0 To 127 Do
Let controller[c] = 0
EndFor

Цикл While имеет следующий синтаксис:

While <выражение> Do
<список операторов>
EndWhile

Здесь <список операторов> в теле цикла будет выполняться только в том случае и до тех пор пока указанное <выражение> истинно. Будьте осторожны с ним , так как при неграмотной записи <выражения> он может просто зациклиться и вам придётся прибегнуть к аварийной остановке программы.

Учтите, что обработчику итак приходится не сладко, поэтому большое нагромождение циклов может значительно увеличить время генерации MIDI-файла. Используйте их только там, где это действительно необходимо.

Примеры толкового использования циклов

Для этих примеров мне понадобятся два встроенных в обработчик массива KeyLength[] и KeyPosition[], а также две встроенные функции KeyCount и Sounding().

Функция без параметра KeyCount возвращает количество нажатых клавиш в тот момент, когда к ней обращаются, а функция с параметром Sounding() возвращает номера этих клавиш (от 1 до 127). Здесь передаваемый ей параметр должен быть в диапазоне от 1 до KeyCount, в противном случае результатом выполнения этой функции будет 0.

Упомянутые массивы хранят в себе информацию о сто двадцать семи клавишах инструмента. Если в какой-то момент значение элемента массива KeyLength[x] стало отличным от нуля, это означает, что именно в этот момент была нажата клавиша x. Тогда элемент массива KeyPosition[x] с каждым последующим тиком, начиная с нуля, увеличивается на единицу и, когда KeyPosition[x] станет равной KeyLength[x], это будет означать, что клавиша x отпущена и значения элементов упомянутых массивов снова сбросятся в нуль.

Исходя из этого напишем фрагмент программы, который должен отслеживать нажатия клавиш, заданные в нотном тексте, и уменьшать их длительности в два раза.

For i = 1 To KeyCount Do
Let key = Sounding(i) 
If KeyLength[key] > 0 and KeyPosition[key] == 0 Then
Let KeyLength[key] = KeyLength[key] / 2
EndIf
EndFor

Учтите, что KeyCount считает и паузы, которые также воспринимаются как ноты, но sounding() для них возвращает 0.

Таким образом, циклы используются в основном для анализа и обработки нотного текста, поскольку только нотный текст способен повлиять на значение описанных здесь двух функций. Не думаю, что возникнет необходимость, скажем, использовать цикл с массивом Controller[]...

Добавлю, что если вы в какой-либо момент присвоите элементу массива KeyLength[x] значение y, то клавиша x зазвучит с того самого момента, как вы это сделаете и затихнет ровно через y тиков.

Вообще, значения всех встроенных переменных можно изменять, в том числе и PositionSong. Если мы запишем:

1920
Let PositionSong = 0

то воспроизведение первого такта зациклится до бесконечности.

Конечно, так писать нельзя, но если завести счётчик повторений и вовремя выйти, то, всё будет нормально.

Оператор Break

Не трудно догадаться, что оператор Breakиспользуется для досрочного выхода из циклов For и While, но это не единственное его предназначение, О чём будет сказано ниже в описании блоков-обработчиков.

Константы, переменные и функции, определяемые пользователем

В некоторых своих примерах я использовал переменные не только встроенные в обработчик. Вы тоже можете пользоваться любым количеством собственных констант, переменных и массивов. Для этого только нужно их объявить.

Оператор объявления переменной:

Variable <имя>

Оператор объявления массива:

Array <имя> (здесь квадратные скобки не ставятся!)

Оператор Объявления символьной константы:

Constant <имя> = <значение>

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

Главное, чтобы объявление всегда предшествовало использованию. Один оператор объявления может объявить только одну константу, переменную или массив. Запись:

Let i = 100
Variable i

является не верной и в ней следует строки поменять местами.

Объявлять ненужно только константы из нотного текста, то есть метки (см. первый раздел). Значение таких констант есть ни что иное, как время в тиках, то есть когда зазвучит нота, имеющая константу, тогда переменная PositionSong станет равна этой константе.

Блок-обработчик

Синтаксис:

Block <ИмяБлока>
<список операторов>
EndBlock

Имя блока задаётся по таким же правилам, как и имена констант или переменных. Список операторов в теле блока не будет исполняться обычным образом. Для того чтобы запустить этот блок, его имя нужно привязать к какой-нибудь ноте в нотном тексте. Как это сделать было описано выше (см. первый раздел).

Когда наступит время зазвучать ноте, к которой мы привязали блок, именно тогда он и начнёт свою работу. Приведу простейший пример блока TempoSinus:

Block TempoSinus
Evry 240 Do {выполнять каждые 240 тиков}
Let Tempo = 120 - Sin(PositionSong)*10
EndEvry
EndBlock

Если теперь в нотном тексте Перед какой-либо нотой написать

)TempoSinus.

с того места темп начнёт периодически ускоряться и замедляться. В этом примере я использовал встроенную функцию Sin, а в качестве её аргумента - переменную PositionSong. Оператор Evry необходим, чтобы не слишком частить с изменением темпа, а значит избежать перегрузки MIDI.

Блок работает до тех пор, пока он сам себя не выгрузит, а достигается это с помощью упомянутого выше оператора Break.

Напишем блок, который изменит темп и выгрузится.

Block ChangeTempo
Let Tempo= Parameter(1)
Break
EndBlock

Здесь новой для вас является встроенная функция Parameter().

Как было описано в первом разделе, привязывая какой-либо блок к ноте, мы можем передавать ему любое количество параметров. Именно извлечением этих параметров из нотного текста и занимается функция Parameter(x), где x - это его порядковый номер. Таким образом, следующая запись в нотном тексте:

)ChangeTempo:200.

приведёт к тому, что с того места где она обозначена блок сделает темп равным 200 и сразу после этого выгрузится.

Что делать, когда необходимо заставить блок работать какое-то определённое время?

Для этого можно использовать функцию StartBlock, возвращающую время начала блока в тиках и, известный нам "временной заголовок". Напишем блок который будет работать ровно один такт после своего вызова.

Block ChangeTempo
StartBlock..StartBlock+1920 {это временной заголовок}
Evry 240 Do
Let Tempo = Tempo + 1
EndEvry
EndBlock

Этому блоку не требуются параметры. Благодаря временному заголовку, он после вызова на протяжении 1920 тиков каждые 240 тиков будет увеличивать темп на единицу. Желательно позаботиться о том, чтобы после окончания работы этот блок выгрузился из памяти.

Block ChangeTempo
StartBlock..StartBlock+1920 
Evry 240 Do
Let Tempo = Tempo + 1
EndEvry
StartBlock + 1920
Break
EndBlock

Это лишь основные рекомендации по программированию блоков-обработчиков. Добавлю лишь, что они не могут быть вложенными сами в себя, аналогично оператору Evry, и заканчиваться должны либо началом другого блока-обработчика, либо словом EndBlock. Размещать же в тексте их можно где угодно, хоть вначале, хоть в конце, хоть в середине.

Ещё блоки-обработчики разрешается выносить в отдельные файлы, называемые модулями,которые имеют расширение BLK. Чтобы использовать такой блок в нотном тексте, нужно модуль, содержащий его, присоединить к основному обработчику. Для этого в тексте этого обработчика пишем

Module <имя>

где <имя> - имя файла модуля без пути и расширения.

Все файлы модулей хранятся в одном месте, в каталоге Modules. Пока создание их необходимо производить вручную, с помощью какого-либо текстового редактора.

В модуле запрещено размещать что-то кроме блоков-обработчиков, исключением являются только операторы объявления констант, переменных и массивов, которые могут находиться вне этих блоков.

Штрихи

В нотном тексте разрешено использование штрихов NonLegatto, Legatto, Stakatto и Stakattisimo. Штрих NonLegatto исполняется по умолчанию. Остальные необходимо указывать перед нотами. Также можно использовать удвоенные штрихи, что позволяет несколько сократить запись. Учтите, что штрихи - это единственное, что можно удваивать в MIDIM. Одинарный штрих здесь, как и в НСБ, отменяет удвоенный.

В обработчике доступны три переменные для управления упомянутыми штрихами:

  • NonLegatto - по умолчанию равна 0,99. Это ничто иное, как коэффициент, на который будет умножена длительность ноты, записанной в штрихе NonLegatto.
  • Stakatto - по умолчанию равна 0,25 - тоже коэффициент для соответствующего штриха,
  • Stakattisimo - отличается от предыдущих переменных тем, что её значение будет использоваться не как коэффициент, а как длительность ноты в тиках, при штрихе Stakattisimo. По умолчанию равна 10.

Придавая этим переменным различные значения, вы можете управлять используемыми штрихами.

Раздел третий. Встроенные константы, переменные, массивы и функции

Настало время перечислить весь инструментарий, с помощью которого и можно вытворять с нотным текстом всё, что вам заблагорассудится, но, разумеется, в рамках возможностей MIDI.

Встроенные константы

True = 127
False = 0
Pi = 3,1415926

Встроенные переменные

Instrument - инструмент MIDI-канала (по умолчанию - 0, т.е. Piano),
Tempo - темп сонга (по умолчанию - 120),
Pich - изменение высоты звучания (по умолчанию - 64),
PositionSong - текущая позиция обработки (в тиках),
LengSong - длина сонга (в тиках),
PositionRND - допустимая погрешность смещения нот (в тиках, по умолчанию - 0), употребляется для гуманизации,
Transpose - транспонирование нот по полутонам (по умолчанию - 0).
NonLegatto - коофицент длительности при соответствующем штрихе (по умолчанию 0,99),
Stakatto - коофицент длительности при соответствующем штрихе (по умолчанию 0,25),
Stakattisimo - длительность ноты в тиках, при соответствующем штрихе (по умолчанию 10),
Kanal - содержит номер MIDI-канала трека.

Встроенные массивы

Controller[] - контроллеры,
KeyOn[] - скорость нажатия клавиши (задаётся для каждой клавиши отдельно),
KeyOff[] - скорость отпускания клавиши (аналогично),
KeyLength[] - длительность звучащей клавиши (в тиках),
KeyPosition[] - счётчик звучания клавиши(аналогично),

Встроенные функции

sin(x) - синус аргумента x,
cos(x)- косинус аргумента x,
arctan(x) - арктангенс,
rnd(x) - генератор случайного числа от 0 до (x-1),
exp(x) - экспонента,
ln(x)- натуральный логарифм,
abs(x) - абсолютное значение x,
int(x) - целая часть вещественного x,
round(x) - округление по известным правилам вещественного x,
not(x) - преобразует true в false и наоборот,
sqr(x) - квадрат x,
sqrt(x) - корень x,
parameter(x) - извлекает параметр №x, переданный блоку-обработчику,
KeyCount - количество нажатых клавиш,
Sounding(x) - возвращает номер нажатой клавиши (x может быть от 1 до KeyCount),
StartBlock - в блоке-обработчике возвращает время его начала (в тиках),
SegmentCount - возвращает числитель тактового размера.

На этом крадкое руководство можно завершить. Надеюсь, вы сможете извлечь максимум пользы из этой программы.

Метки

Компьютерная музыка


Распространение материалов сайта означает, что распространитель принял условия лицензионного соглашения.
Идея и реализация: © Владимир Довыденков и Анатолий Камынин,  2004-2024