Технологии программирования миди

 Навигация:

 Поиск:

 Новости:

17.02.2007
Полностью переработан дизайн сайта.

6.01.2007
Добавлен раздел Наработки Полезные и интересные программы и их исходники от автора.

19.11.2006
Функции WriteVarLen и ReadVarLen портированы с СИ на Delphi читать

14.11.2006
Появилась cтатья Midi-протокол глазами программиста

24.10.2006
Написана вторая часть MMSystem Функции midiOutGetVolume midiOutSetVolume midiOutMessage midiOutShortMsg и midiOutLongMsg

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

1.09.2006
Добавлен раздел MMSystem в котором находятся
подробные опсания функций winmm.dll, определенных в модуле mmSystem.pas,
с примерами их использования в Delphi.

13.08.2006
Опубликован исходник приложения, записывающего игру на клавиатуре
в стандартный midi-файл SMF - 0

4.07.2006
Добавлен раздел Структура формата миди-файла

 Счетчики:
Rambler's Top100 Яндекс цитирования Rambler's Top100
 Контент:

Формат миди-файлов

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

Стандартный MIDI файл (SMF v Standard MIDI FIle) - это специально разработанный формат файлов, предназначенный для хранения данных, записываемых и/или исполняемых секвенсером, секвенсер может быть как программой для компьютера, так и аппаратно выполненным модулем.

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

NOTE: Как правило, трэк представляет собой аналог музыкальной партии, например партии трубы. Аналогом паттерна может служить весь набор партий, взятых вместе, например совокупность партий трубы, ударных, фортепиано и т.д., которые используются в данном произведении или его части и исполняются одновременно.

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

Что такое запись?

Данные всегда хранятся в виде записей. В одном MIDI-файле могут сосуществовать несколько различных записей. Каждая запись может иметь свой собственный размер, т.е. количество байтов в различных записях может быть различно. Данные, хранящиеся в одной записи, связаны друг с другом определенным образом. Запись - это по своей сути набор взаимосвязанных байтов. Каждая запись начинается с указаения ее идентификатора, который состоит из четырех букв, т.е. из четырех ASCII байтов. Этот идентификатор указывает, какой тип записи представлен в содержащихся в записи байтах данных. Последующие за идентификатором четыре байта (каждый из которых состоит из 8 бит) образуют 32-битное значение, указывающее длину (или размер) данной записи. Все записи должны начинаться с этих двух полей: иденификатора записи и размера записи. Эти два поля, занимающие всего 8 байт, образуют заголовок записи.

NOTE: Длина записи не учитывает 8 байт заголовка. Байты длины просто указывают количество байтов в записи, которые следуют за заголовком.

Приведем пример заголовка (здесь байты представлены в шестнадцатеричном виде): 4D 54 68 64 00 00 00 06
Отметим, что первые четыре байта заголовка образуют MThd (т.е. первыми четырьмя байтами заголовка являются ascii значения букв 'M', 'T', 'h', и 'd'). Последующие 4 байта говорят нам, что в записи будет еще 6 байтов, следующих за заголовком. После этих шести байтов должен следовать следующий заголовок записи или же конец MIDI файла. Фактически все MIDI файлы начинаются с заголовка MThd и именно этот факт является указанием на то, что мы имеем дело со стандартным MIDI файфлом ).

Запись MThd

Запись MThd имеет идентификатор MThd и длину 6 байт.
Рассмотрим подробно эти 6 байтов, следующих за 8-байтным заголовком в MThd записи.

Первые два байта данных содержат информацию о формате или типе MIDI файла. Существует три различных типа (формата) MIDI файлов. Тип 0 означает, что файл содержит MIDI данные, записанные на одном трэке, который, вероятно, объединяет в себе все 16 MIDI каналов. Если ваш секвенсер сохраняет MIDI данные в одном единственном блоке памяти, из которого он их воспроизводит, то такой секвенсер будет читать и записывать MIDI данные именно в этот тип MIDI файлов. Файл типа 1 подразумевает, что в нем содержатся несколько (но возможно и всего один) одновременно воспроизводимых трэков, каждый, вероятно, представляет свой собственный MIDI канал. Все трэки начинают воспроизводиться в один и тот же нулевой момент времени. Все трэки, взятые вместе, образуют паттерн. Если ваш секвенсер разделяет в памяти различные MIDI трэки и хранит их в различных блоках и воспроизводит различные трэки одновременно, то такой секвенсер будет читать и писать файлы типа 1. Файлы типа 2 содержат один или несколько независимых трэков, каждый такой трэк образует свой собственный паттерн. Если ваш секвенсер разделяет MIDI данные на несколько блоков в памяти, но воспроизводит лишь один единственный блок в данное время, но не воспроизводит их одновременно, когда каждый блок памяти содержит отдельную пьесу или ее кусок, то этот секвенсер будет читать и записывать MIDI файлы второго типа.

Следующие два байта определяют количество треков, хранимых в файле, эти два байта обозначаются NumTracks. Естественно, что для файлов типа 0 значение NumTracks всегда равно 1. Для двух оставшихся типов возможны другие зкачения.

Оставшиеся два байта указывают величину временного разрешения, т.е. количество временных импульсов (временных тиков), приходящихся на одну четвертную длительность, что в виде аббревиатуры английских слов обозначается как PPQN. Например, если ваш секвенвер использует 96 ppqn, то соответствующее поле в заголовке записи будет иметь шестнадцатеричное значение 00 60 Напротив, если первый байт рассматриваемого поля заголовка отрицателен, то соответствущий формат использует SMPTE стандарт вместо PPQT стандарта. В этом случае первый байт поля временного разрешения принимает значения -24, -25, -29 или -30, что соответствует четырем стандартным типам в стандарте SMPTE. Второй байт (положительная величина) указывает величину разрешения во фрейме. Стандартные величины разрещения фрейма представляют собой 4 (временной код MIDI), 8, 10, 80 (SMPTE) или 100. Задавая значения фреймов -25 и величину внутрифреймового разрешения 40, можно установить значение временного разрешения длительностью в миллисекунду.

Ниже приводится пример целой записи типа MThd, включая ее заголовок:
4D 54 68 64 MThd идентификатор
00 00 00 06 Длина записи MThd всегда равна 6 байтам
00 01 Формат данного MIDI файла 1
00 02 В данном файле содержится 2 записи типа MTrk
E7 28 Каждый временной интeрвал представляет собой одну миллисекунду

Запись MTrk

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

MTrk запись содержит в себе MIDI данные и байты временных меток, а также необязательную информацию. Эти данные относятся к одному трэку. Очевидно, что количество MTrk записей в фалйе должно совпадать со значением NumTraks, указанном в записи MThd. Заголовок записи MTrk начинается с идентификатора записи, который представляет собой четыре ascii байта 'M', 'T', 'r', 'k', за которым следует значение длины записи, т.е. число, равное количеству байтов в данной записи. Для различных трэков значения длин MTrk записей могут быть различны. (Например, трэк, содержащий партию скрипки из Концерта Баха, по всей видимости будет содержать больше данных, чем трек, содержащий басовую партию, в которой на один такт приходится лишь две ноты.)

Величины переменной длины -- Временные метки событий

Трэк в MIDI файле аналогичен треку в MIDI секвенсере. Трэк секвенсера содержит последовательность событий. Например, первым событием может быть взятие ноты "до" первой октавы. Вторым событием может быть взятие ноты "ми" терцией выше. Эти два события могут произойти в одно и то же время. Третьим событием может быть снятие ноты "до". Это событие может произойти несколькими долями позже после первого события (т.е. звук "до" будет снят спустя несколько долей после того, как он был взят). Для каждого событие указывается его время, именно в этот момент времени событие происходит, все события организованы в пределах одной записи в памяти секвенсера в порядке их появления во времени.

В MIDI файле время события указывается перед байтами данных, которые описывают само событие. Иными словами, временная метка события предшествует описанию события. Например, если первое события происходит спустя 4 временных интервала (временной интервал устанавливается в MThd записи) после начала начала воспроизведения, то соответствующее ему значение "дельта" - значение промежутка времени - устанавливается равным 04. Если следующее событие происходит одновременно с этим первым событием, то значение его времении дельта равно 00. Таким образом, время дельта - это длительность, выраженная в элементарных временных интервалах, между данным событием и ему предшествующим событием.

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

Значения времен дельта хранятся в виде последовательностей байтов, которые носят название величин переменной длины. Лишь первые 7 бит каждого байта являются значимыми для определения дельта времени. Если время дельта выражено в виде набора 32 бит, то необходимо распаковать эту 4-байтовую величину, выделив последовательность четырех 7-битных значимых байтов (наподобие того, как это делается для передачи SYSEX сообщений в ракмках протокола MIDI). В зависимости от величины времени дельта, количество байтов может быть различным. Для того, чтобы отметить последний байт в последовательности этих байтов, необходимо оставить 7-ой бит этого последнего байта чистым (старший бит равен 0). Так, если время дельта находится в пределах от 0 до 127, то оно может быть выражено одним единственным байтом. Самое большое время дельта устанавливается в размере 0FFFFFFF, для записи такого времени потребуется величина паременной длины размером 4 байта. Так могут выглядеть величины переменной длины для разных значений времен дельта (время дельта выражено в виде 32-битного значения): Время дельта Соответствующая величина переменной длины

00000000 00

00000040 40

0000007F 7F

00000080 81 00

00002000 C0 00

00003FFF FF 7F

00004000 81 80 00

00100000 C0 80 00

001FFFFF FF FF 7F

00200000 81 80 80 00

08000000 C0 80 80 00

0FFFFFFF FF FF FF 7F

В дополнение к сказанному приведем пример программы, которая позволяет записывать и читать величины переменной длины, подобные временам дельта. Функция WriteVarLen(), передает 32-битное значение и преобразует его в последовательность байтов, записываемых в файл. Функция ReadVarLen() читает последовательность байтов из файла до тех пор, пока не достигнет последнего байта значения переменной длины, после чего возвращает 32-битное значние.

C
void WriteVarLen(register unsigned long value)

{

register unsigned long buffer;

buffer = value & 0x7F;

while ( (value >>= 7) )

{

buffer <<= 8;

buffer |= ((value & 0x7F) | 0x80);

}

while (TRUE)

{

putc(buffer,outfile);

if (buffer & 0x80)

buffer >>= 8;

else

break;

}

}


unsigned long ReadVarLen()

{

register unsigned long value;

register unsigned char c;

if ( (value = getc(infile)) & 0x80 )

{

value &= 0x7F;

do

{

value = (value >> 7) + ((c = getc(infile)) & 0x7F);

} while (c & 0x80);

}

return(value);

}

NOTE: Отметим, что использование значений переменной длины, т.е. разбиение большой величины на последовательность байтов, не ограничивается случаем с временами дельта. В дальнейшем мы увидим, что значения переменный длины используются в MIDI файлах и в других случаях.

События

Первые байты (байт 1 или байты с 1 по 4) записи MTrk задают значение времени дельта для первого события в формате величины переменной длины. Следующий за этой величиной байт данных представляет собой первый байт события MIDI. Это байт носит название байта статуса события или байта текущего MIDI статуса. Для MIDI событий он представляет собой статус байт данного события. Например, если этот байт равен 0x90, то данное событие - это событие Взять Ноту на MIDI канале 0. Или, если этот байт равен 0x23, то необходимо обратиться к статус байту предыдущего события. Очевидно, что первое MIDI событие в MTrk записи обязательно должно содержать в себе статус байт. После статус байта следуют один или два байта данных, в зависимости от типа события. После этих байтов данных находится следующее значение времени дельта ( в виде величины переменной длины), и начинается процесс прочтения следующего события.

Особый случай представляют собой сообщения SYSEX, имеющие статус байт, равный F0. События SYSEX могут иметь любую длину. После статус байта F0 следует последовательность значений перменной длины. Преобразуя их с помощью функции ReadVarLen() получаем 32-битовое значение, которое равно количеству следующих далее байтов, образующих SYSEX событие. Эта длина не включает в себя статус байт (F0).

Рассмотрим в качестве примера следующее SYSEX событие MIDI:
F0 7F 7F 04 01 7F 7F F7

В MIDI файле такое событие будет сохранено в виде следующей последовательности байтов (исключая время дельта, предшествующее событию):
F0 07 7F 7F 04 01 7F 7F F7

Статус байт FF зарезервирован для использования в качестве статуса события, не являющегося MIDI-событием. За батйом FF следует другой байт, указывающий какой тип не-MIDI события описывается в данном событии. Это своебразный второй статус байт. За этим байтом следует величина переменной длины, которая показывает, какое количество байтов содержится в данном событии. т.е. задает длину события. Длина не включает в себя начальный статус байт FF, байт типа события, байты длины события. Это особое сообщение, не принадлежащее протоколу MIDI, носит название мета-события. Ниже описаны некоторые мета-события. Если не указано обратное, в записи MTrk может быть размещено более одного мета-события, причем одно и то же мета-событие может быть размещено в одной записи более одного раза. Мета-события могут иметь произвольные временные метки (времена дельта). Как и все MIDI события, мета-события имеют дельта времена (временные метки), которые указывают промежуток времени, разделяющий данное MIDI событие или мета-событие от предшествующего, независимо от того, является это событие MIDI-событием или мета-событием. Таким образом, мы можем смешивать MIDI события и мета-события произвольным образом.

Номер последовательности (записи)

FF 00 02 ss ss Это необязательное мета-событие должно находиться в самом начале MTrk записи перед первой ненулевой временной меткой или перед первым событием. Это мета-событие устанавливает номер последовательности (номер записи) Два байта данных ss ss соответствуют данным в MIDI сообщении MIDI Cue. В MIDI файлах второго типа эти числа определяют номера каждого паттерна (или MTrk записи) таким образом, что последовательность пьес, содержащихся в файле может быть управляема при помощи сообщения MIDI Cue/ Если байты ss ss опущены (длина данного мета-сообщения равна 0 вместо 2), то номера MTrk записей усатнавливаются в порядке того, как они записаны в файле (первая MTrk соответствует первому трэку и т.д.) Файлы нулевого и первого типов, которые содержат единственный паттерн могут содержать мета-сообщение номера последовательности только в первой MTrk записи. Несколько Файлов первого типа, содержащих различные номера последовательностей могут рассматриваться как коллекции независимых пьес.

Можно использовать только одно мета-сообщение номера последовательности для каждогой MTrk записи в фалйе формата 2. Модно использовать только одно мета-сообщение номера последовательности в файле формата 0 им формата 1, и это мета-сообщение должно находиться в первой MTrk записи.

Текст

FF 01 len text
Это мета-событие содержит любой объем текста любого назначения. Значение len содержит длину текстового сообщения в байтах. Наиболее удобно помещать такие мета-сообщения в начале MTrk записи. Несмотря на то, что записываемый текст может быть использован в любых целях, необходимо иметь в виду, что предусмотрены также и иные текстовые мета-сообщения, которые специально предназначены для указания инструментов оркестра, слов песен, названий трэков и другие. Данное мета-событие главным образом предназначено для добавления коменнтариев к MIDI файлу, предполагается, что при загрузке файлов эти коменнтарии будут проигнорированы. Отметим, что величина len представляется в виде значения переменной длины.

Мета-событие Copyright

FF 02 len text
Текстовое мета-событие copyright наиболее удобно помещать в начале MTrk записи. Отметим, что величина len представляется в виде значения переменной длины.

Имя последовательноcти/Имя трэка

FF 03 len text
Тексовое мета-событие, содержащее название MIDI последовательности или трэка. Удобно располагать это мета-событие в начале MTrk записи. Отметим, что величина len представляется в виде значения переменной длины.

Инструмент

FF 04 len text
Текстовое мета-событие, содержащее название инструмента, исполняющего данный трэк. Название инструмента может отличаться от названия самого трэка. Например, название трэка может быть, скажем, "Ария Ленского", а название инструмента может указывать на голос и содержать значение "Тенор".

Наиболее удобно располагать одно или несколько мета-событий подобного типа в самом начале MTrk записи, поскольку эти события несут свспомогательную информацию, которая информирует пользователя о том, какой инструмент исполняет данный трэк, а также сообщают другие полезные данные. Обычно реальные параметры, задающие тип инструмента, исполняющего трэк, хранятся в файле в виде MIDI-событий типа MIDI Program Change, а описанные здесь мета-события позволяют снабдить пользователя удобно читаемыми описаниями, соответствующими сделанным в MTrk записях конфигурациям. Отметим, что величина len представляется в виде значения переменной длины.

Слова

FF 05 len text
Текстовое мета-событие, содержащее слова вокального произведения, приходящиеся на ту или иную музыкальную долю. Одно мета-событие "Слова" должно содержать один единственный слог текста. Отметим, что величина len представляется в виде значения переменной длины.

Маркер

FF 06 len text
Текстовое мета-событие Маркер устанавливается на определенной музыкальной доле. Это событие может использоватеься для организации петель и может обозначать начальную и конечную точку петли. Отметим, что величина len представляется в виде значения переменной длины.

Точка входа Cue Point

FF 07 len text
Текстовое мета-событие "точка входа" может использоваться для обозначения точки входа внешнего потока данных, например точки начала воспроизведения файла с цифровым звуком. Текстовое значение данного мета-события может содержать имя WAV файла, содержащего цифровой звук. Отметим, что величина len представляется в виде значения переменной длины.

Канал MIDI

FF 20 01 cc
Это необязательное мета-событие обычно располагается в начале MTrk сообщения перед первой ненулевой временной меткой и перед первым мета-событием, исключая мета-событие номера последовательности. Мета-событие "канал MIDI" устанавливает значение MIDI канала с которым будут связаны все последующие мета-события и события SYSEX. Байт данных cc - это номер MIDI канала, величине 0 соответствеут первый канал.

Специфакиция MIDI не предусматривает указание номера канала для SYSEX событий и мета-событий. Если создается файл типа 0, то все SYESX события и мета-мобытия находятся на одном трэке и затруднительно распределить эти события между соответствующими канальными (голосовыми) сообщениями (например, если вы хотите обозначить партию канала 1 как "Флейта соло", а партию канла 2 как "Труба соло", то вам придется использовать два мета-события "Имя трэка" для введения этих называний, но поскольку оба эти трэка расположены на одном канале, то перед первым мета-сообщением имени трэка необходимо поместить мета-сообщение "канал MIDI", в котором указать номер соответствующего канала, а перед вторым мета-сообщением имени трэка поместить мета-сообщение канала MIDI с указанием номера второго канала.

На одном MIDI трэке можно использовать более одного мета-сообщения "канал MIDI", если события этого трэка нужно распределить между несколькими каналами MIDI.

Порт MIDI

FF 21 01 pp
Это необязательное событие, которое как правило располагается в начале я MTrk записи перед первым ненулевым временем дельта и перед первым MIDI событием, которое определяет, с каким MIDI портом (или устройством) связаны события данного MTrk сообщения. Байт данныз pp - это номер порта, нулевому значению pp соответствует первое MIDI устройство в системе.

Спецификация MIDI предусматривает лишь 16 каналов на один входной или выходной порт (устройство, разъем, инструмент - терминология может быть различной) MIDI. Номер MIDI канала каждого события MIDI содержится в статус байте события, где он занимает четыре младших бита. Таким образом, номер канала всегда представляет собой число в пределах от 0 до 15. Иногда система позволяет осуществлять работу более чем с 16 каналами MIDI, возникает необходимость проедолеть ограничения, накладываемые малым количеством каналов MIDI, и расширить возможности обмена MIDI данными, сделать обмен информацией со внешними MIDI устройствами более эффективным, т.е. позволить музыканту работать более чем с 16 каналами. Некоторые секвенсеры также позволяют осуществлять работу более чем с 16 MIDI каналами на входе и выходе одновременно. К сожалению, протокол MIDI не предусматривает возможность использования более чем 16 MIDI каналов в рамках статус байта в событии MIDI. Ппоэтому необходим дополнительный метод, который позволяет различать события, которые соответствуют первому каналу на первом MIDI порте от событий, соответствующих, скажем, первому каналу на втором MIDI порте. Описываемой мета-событие позоляет секвенсеру определить на какой MIDI порт посылать события данного MTrk сообщения.

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

Конец трэка

FF 2F 00
Это событие является обязательным. Оно обязано быть последним событием каждой MTrk записи. Оно представляет собой явное обозначение конца MTrk записи. Допускается использование единственного мета-события "Конец трэка" для каждой MTrk записи.


 Bash.org.ru:

 Реклама:

 ©Copyright:
http://www.last.h16.ru - программирование миди. Идея, разработка и поддержка : Mo-skin © 2006-2007
X